From 3de2753e0b17e515badfb700531b768388f8a782 Mon Sep 17 00:00:00 2001 From: David Edey Date: Fri, 28 Nov 2025 21:10:57 +0000 Subject: [PATCH 1/3] feat: Distinct inputs have distinct parser handles --- Cargo.toml | 1 + src/interpretation/input_handler.rs | 27 +++++++++++++++++++-------- src/interpretation/interpreter.rs | 8 ++++---- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 68de12a5..a0483419 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,6 +33,7 @@ debug = [] # Non-stable, for internal use only proc-macro2 = { version = "1.0.93" } syn = { version = "2.0.107", default-features = false, features = ["parsing", "derive", "printing", "clone-impls", "full"] } quote = { version = "1.0.38", default-features = false } +slotmap = { version = "1.0.7" } [dev-dependencies] trybuild = { version = "1.0.110", features = ["diff"] } diff --git a/src/interpretation/input_handler.rs b/src/interpretation/input_handler.rs index 3e5dfebe..c206cde8 100644 --- a/src/interpretation/input_handler.rs +++ b/src/interpretation/input_handler.rs @@ -1,13 +1,20 @@ use super::*; +use slotmap::{SlotMap, new_key_type}; + +new_key_type! { + pub(crate) struct ParserHandle; +} pub(crate) struct InputHandler { - input_stack: Vec>, + parsers: SlotMap>, + parser_stack: Vec, } impl InputHandler { pub(crate) fn new() -> Self { Self { - input_stack: vec![], + parsers: SlotMap::with_key(), + parser_stack: Vec::new(), } } @@ -17,25 +24,29 @@ impl InputHandler { /// /// TODO: Replace this with returning a ParseGuard which captures the lifetime and handles calling /// `finish_parse` automatically when dropped, to avoid misuse. - pub(super) unsafe fn start_parse(&mut self, input: ParseStream) { + pub(super) unsafe fn start_parse(&mut self, input: ParseStream) -> ParserHandle { let parse_stack = ParseStack::new(input); - self.input_stack.push(std::mem::transmute::< + let handle = self.parsers.insert(std::mem::transmute::< ParseStack<'_, Output>, ParseStack<'static, Output>, >(parse_stack)); + self.parser_stack.push(handle); + handle } /// SAFETY: Must be called after a prior `start_parse` call, and while the input is still alive. - pub(super) unsafe fn finish_parse(&mut self) { - self.input_stack.pop(); + pub(super) unsafe fn finish_parse(&mut self, handle: ParserHandle) { + let popped_handle = self.parser_stack.pop(); + assert_eq!(popped_handle, Some(handle), "Popped handle does not match the provided handle"); + self.parsers.remove(handle); } pub(super) fn current_stack( &mut self, span_source: &impl HasSpanRange, ) -> ExecutionResult<&mut ParseStack<'static, Output>> { - match self.input_stack.last_mut() { - Some(parse_stack) => Ok(parse_stack), + match self.parser_stack.last() { + Some(parser_handle) => Ok(self.parsers.get_mut(*parser_handle).unwrap()), None => { span_source.control_flow_err("There is no input stream available to read from.") } diff --git a/src/interpretation/interpreter.rs b/src/interpretation/interpreter.rs index 3579c618..b4dc060d 100644 --- a/src/interpretation/interpreter.rs +++ b/src/interpretation/interpreter.rs @@ -225,15 +225,15 @@ impl Interpreter { f: impl FnOnce(&mut Interpreter) -> ExecutionResult<()>, ) -> ExecutionResult<()> { stream.parse_with(|input| { - unsafe { + let handle = unsafe { // SAFETY: This is paired with `finish_parse` below, // without any early returns in the middle - self.input_handler.start_parse(input); - } + self.input_handler.start_parse(input) + }; let result = f(self); unsafe { // SAFETY: This is paired with `start_parse` above - self.input_handler.finish_parse(); + self.input_handler.finish_parse(handle); } result }) From 0ebe247125da4a731579c68f2964b55c5ee86d29 Mon Sep 17 00:00:00 2001 From: David Edey Date: Sat, 29 Nov 2025 00:25:48 +0000 Subject: [PATCH 2/3] feat: Add parse expression --- plans/TODO.md | 60 ++++-- src/expressions/array.rs | 2 +- src/expressions/control_flow.rs | 70 +++++++ .../evaluation/control_flow_analysis.rs | 3 + src/expressions/evaluation/node_conversion.rs | 5 + src/expressions/evaluation/value_frames.rs | 2 +- src/expressions/expression.rs | 5 +- src/expressions/expression_parsing.rs | 5 +- src/expressions/mod.rs | 2 + src/expressions/parser.rs | 181 ++++++++++++++++++ src/expressions/stream.rs | 15 +- src/expressions/type_resolution/arguments.rs | 2 +- .../type_resolution/interface_macros.rs | 14 +- src/expressions/type_resolution/outputs.rs | 12 -- src/expressions/type_resolution/type_data.rs | 2 + src/expressions/value.rs | 19 +- src/extensions/errors_and_spans.rs | 14 +- src/interpretation/input_handler.rs | 7 + src/interpretation/interpreter.rs | 17 +- src/interpretation/mod.rs | 2 +- src/interpretation/output_stream.rs | 5 + src/misc/keywords.rs | 4 +- src/misc/parse_traits.rs | 2 + src/transformation/patterns.rs | 2 +- .../core/set_span_example.rs | 24 +++ .../core/set_span_example.stderr | 9 + .../expressions/invalid_unary_operator.stderr | 2 +- tests/literal.rs | 5 + tests/parsing.rs | 31 +++ 29 files changed, 461 insertions(+), 62 deletions(-) create mode 100644 src/expressions/parser.rs create mode 100644 tests/compilation_failures/core/set_span_example.rs create mode 100644 tests/compilation_failures/core/set_span_example.stderr create mode 100644 tests/parsing.rs diff --git a/plans/TODO.md b/plans/TODO.md index 39e58b40..131af754 100644 --- a/plans/TODO.md +++ b/plans/TODO.md @@ -166,29 +166,49 @@ These are things we definitely want to do: First, read the @./2025-11-vision.md - [x] We store input in the interpreter -- [ ] Create new `Parser` value kind -- [ ] Create (temporary) `parse X as Y { }` expression +- [x] Create new `Parser` value kind +- [x] Add ParserHandle to `InputHandler` and use some generational map to store ParseStacks (or import slotmap) + - [x] Look at https://donsz.nl/blog/arenas/ + - [ ] If using slotmap / generational-arena, replace the arena implementation too +- [x] Create (temporary) `parse X => |Y| { }` expression +- [x] Bind `input` to `Parser` at the start of each parse expression - [ ] Create `consume X @[ .. ]` expression -- [ ] Bind `input` to `Parser` at the start of each parse expression - [ ] Move transform logic from transformers onto `Parser`, and delete the transformers -- [ ] Rename the transform stream to `ParseModeStream` -- [ ] Reversion works in attempt blocks, via forking and committing or rolling back - the fork, fix `TODO[parser-input-in-interpreter]` -- [ ] Remove all remaining parsers. +- [ ] Remove all remaining transformers. - [ ] Remove parsing in a stream pattern - instead we just support a literal +- [ ] Rename the transform stream to `ParseModeStream` +- [ ] Reversion works in attempt blocks, via forking and committing or rolling back the fork, fix `TODO[parser-input-in-interpreter]` - [ ] Address any remaining `TODO[parser-no-output]` and `TODO[parsers]` +- [ ] Add tests for all the methods on Parser, and for nested parse statements `Parser` methods: -* `ident()`, `is_ident()` -* `literal()`, `is_literal()` -* `integer()`, `is_integer()` -* `float()`, `is_float()` -* `char()`, `is_char()` -* `string()`, `is_string()` -* `error()` etc -* `end()`, `is_end()` -* `token_tree()` -* `span()` or `cursor()` -- maybe? outputs a token with a span for outputting errors. If at end of an inner stream, it outputs the ident `END` with the span of the closing bracket. +- [x] `ident()`, `is_ident()` +- [x] `literal()`, `is_literal()` +- [x] `integer()`, `is_integer()` +- [x] `float()`, `is_float()` +- [x] `char()`, `is_char()` +- [x] `string()`, `is_string()` +- [x] `end()`, `is_end()` +- [ ] `rest()` +- [ ] `error()` etc +- [ ] `token_tree()` +- [ ] `span()` or `cursor()` -- maybe? outputs a token with a span for outputting errors. If at end of an inner stream, it outputs the ident `END` with the span of the closing bracket. + +And all of these from normal macros: +- [ ] block: a block (i.e. a block of statements and/or an expression, surrounded by braces) +- [ ] expr: an expression +- [ ] ident: an identifier (this includes keywords) +- [ ] item: an item, like a function, struct, module, impl, etc. +- [ ] lifetime: a lifetime (e.g. 'foo, 'static, …) +- [ ] literal: a literal (e.g. "Hello World!", 3.14, '🦀', …) +- [ ] meta: a meta item; the things that go inside the #[...] and #![...] attributes +- [ ] pat: a pattern +- [ ] path: a path (e.g. foo, ::std::mem::replace, transmute::<_, int>, …) +- [ ] stmt: a statement +- [ ] tt: a single token tree +- [ ] ty: a type +- [ ] vis: a possible empty visibility qualifier (e.g. pub, pub(in crate), …) +``` Consider if we want separate types for e.g. * `Span` @@ -215,8 +235,7 @@ input.repeated( ``` Later: -- [ ] Support for starting to parse a `input.open('(')` in the left part of an attempt arm - and completing in the right arm `input.close(')')` - there needs to be some error checking in the parse stream stack. We probably can't allow closing in the LHS of an attempt arm. We should record a reason on the new parse buffer and raise if it doesn't match +- [ ] Support for starting to parse a `input.open('(')` in the left part of an attempt arm and completing in the right arm `input.close(')')` - there needs to be some error checking in the parse stream stack. We probably can't allow closing in the LHS of an attempt arm. We should record a reason on the new parse buffer and raise if it doesn't match ## Methods and closures @@ -351,6 +370,9 @@ preinterpret::run! { ## Optimizations - [ ] Look at benchmarks and if anything should be sped up +- [ ] Speeding up stream literal processing + - [ ] When interpreting a stream literal, we can avoid having to go through error handling pathways to get an `output` from the intepreter by storing a `OutputInterpreter<'a>` which wraps an `&mut OutputStream` and a pointer to an Intepreter, and can be converted back into/from an `Interpreter` easily + - [ ] Possibly similarly for an `InputInterpreter<'a>` when processing a `ConsumeStream` - [ ] Speeding up scopes at runtime: - [ ] In the interpreter, store a flattened stack of variable values - [ ] `no_mutation_above` can be a stack offset diff --git a/src/expressions/array.rs b/src/expressions/array.rs index 97193c31..31842eb0 100644 --- a/src/expressions/array.rs +++ b/src/expressions/array.rs @@ -213,7 +213,7 @@ define_interface! { Ok(()) } - [context] fn to_stream_grouped(this: ArrayExpression) -> StreamOutput { + [context] fn to_stream_grouped(this: ArrayExpression) -> StreamOutput [ignore_type_assertion!] { let error_span_range = context.span_range(); StreamOutput::new(move |stream| this.output_items_to(&mut ToStreamContext::new(stream, error_span_range), Grouping::Grouped)) } diff --git a/src/expressions/control_flow.rs b/src/expressions/control_flow.rs index d8e8ca7b..5d2f0e2e 100644 --- a/src/expressions/control_flow.rs +++ b/src/expressions/control_flow.rs @@ -548,3 +548,73 @@ impl AttemptExpression { self.braces.control_flow_err("No attempt arm ran successfully. You may wish to add a fallback arm `{} => { None }` to ignore the error or to propogate a better message: `{} => { %[].error(\"Error message\") }`.") } } + +pub(crate) struct ParseExpression { + parse_ident: ParseKeyword, + input: Expression, + _fat_arrow: Unused]>, + _left_bar: Unused, + parser_variable: VariableDefinition, + _right_bar: Unused, + scope: ScopeId, + body: UnscopedBlock, +} + +impl HasSpanRange for ParseExpression { + fn span_range(&self) -> SpanRange { + SpanRange::new_between(self.parse_ident.span(), self.body.span()) + } +} + +impl ParseSource for ParseExpression { + fn parse(input: SourceParser) -> ParseResult { + let parse_ident = input.parse()?; + let input_expression = input.parse()?; + let _fat_arrow = input.parse()?; + let _left_bar = input.parse()?; + let parser_variable = input.parse()?; + let _right_bar = input.parse()?; + let body = input.parse()?; + Ok(Self { + parse_ident, + input: input_expression, + _fat_arrow, + _left_bar, + parser_variable, + _right_bar, + scope: ScopeId::new_placeholder(), + body, + }) + } + + fn control_flow_pass(&mut self, context: FlowCapturer) -> ParseResult<()> { + context.register_scope(&mut self.scope); + self.input.control_flow_pass(context)?; + context.enter_scope(self.scope); + self.parser_variable.control_flow_pass(context)?; + self.body.control_flow_pass(context)?; + context.exit_scope(self.scope); + Ok(()) + } +} + +impl ParseExpression { + pub(crate) fn evaluate( + &self, + interpreter: &mut Interpreter, + ownership: RequestedValueOwnership, + ) -> ExecutionResult { + let input = self.input.evaluate_owned(interpreter)? + .resolve_as("The input to a parse expression")?; + + interpreter.enter_scope(self.scope); + + let output = interpreter.start_parse(input, |interpreter, handle| { + self.parser_variable.define(interpreter, handle); + self.body.evaluate(interpreter, ownership) + })?; + + interpreter.exit_scope(self.scope); + Ok(output) + } +} \ No newline at end of file diff --git a/src/expressions/evaluation/control_flow_analysis.rs b/src/expressions/evaluation/control_flow_analysis.rs index 72c738f1..03b5f585 100644 --- a/src/expressions/evaluation/control_flow_analysis.rs +++ b/src/expressions/evaluation/control_flow_analysis.rs @@ -185,6 +185,9 @@ impl Leaf { Leaf::AttemptExpression(attempt_expression) => { attempt_expression.control_flow_pass(context) } + Leaf::ParseExpression(parse_expression) => { + parse_expression.control_flow_pass(context) + } Leaf::Discarded(_) => Ok(()), Leaf::Value(_) => Ok(()), } diff --git a/src/expressions/evaluation/node_conversion.rs b/src/expressions/evaluation/node_conversion.rs index ae76b9b2..64c5594d 100644 --- a/src/expressions/evaluation/node_conversion.rs +++ b/src/expressions/evaluation/node_conversion.rs @@ -64,6 +64,11 @@ impl ExpressionNode { let item = attempt_expression.evaluate(context.interpreter(), ownership)?; context.return_item(item)? } + Leaf::ParseExpression(parse_expression) => { + let ownership = context.requested_ownership(); + let item = parse_expression.evaluate(context.interpreter(), ownership)?; + context.return_item(item)? + } } } ExpressionNode::Grouped { delim_span, inner } => { diff --git a/src/expressions/evaluation/value_frames.rs b/src/expressions/evaluation/value_frames.rs index 226aa0fc..2bd1d06f 100644 --- a/src/expressions/evaluation/value_frames.rs +++ b/src/expressions/evaluation/value_frames.rs @@ -753,7 +753,7 @@ impl EvaluationFrame for BinaryOperationBuilder { if let Some(method) = method { // TODO[operation-refactor]: Use proper span range from operation let span_range = - SpanRange::new_between(left.span_range().start(), right.span_range().end()); + SpanRange::new_between(left.span_range(), right.span_range()); let mut call_context = MethodCallContext { output_span_range: span_range, diff --git a/src/expressions/expression.rs b/src/expressions/expression.rs index 33d34790..12fabaf5 100644 --- a/src/expressions/expression.rs +++ b/src/expressions/expression.rs @@ -161,6 +161,7 @@ pub(super) enum Leaf { WhileExpression(Box), ForExpression(Box), AttemptExpression(Box), + ParseExpression(Box), } impl HasSpanRange for Leaf { @@ -176,6 +177,7 @@ impl HasSpanRange for Leaf { Leaf::WhileExpression(expression) => expression.span_range(), Leaf::ForExpression(expression) => expression.span_range(), Leaf::AttemptExpression(expression) => expression.span_range(), + Leaf::ParseExpression(expression) => expression.span_range(), } } } @@ -188,7 +190,8 @@ impl Leaf { | Leaf::LoopExpression(_) | Leaf::WhileExpression(_) | Leaf::ForExpression(_) - | Leaf::AttemptExpression(_) => true, + | Leaf::AttemptExpression(_) + | Leaf::ParseExpression(_) => true, Leaf::Variable(_) | Leaf::Discarded(_) | Leaf::Value(_) | Leaf::StreamLiteral(_) => { false } diff --git a/src/expressions/expression_parsing.rs b/src/expressions/expression_parsing.rs index 8cd72578..6ccbfe0a 100644 --- a/src/expressions/expression_parsing.rs +++ b/src/expressions/expression_parsing.rs @@ -111,8 +111,10 @@ impl<'a> ExpressionParser<'a> { if punct.as_char() == '.' { UnaryAtom::Range(input.parse()?) - } else { + } else if punct.as_char() == '-' || punct.as_char() == '!' { UnaryAtom::PrefixUnaryOperation(input.parse()?) + } else { + return input.parse_err("Expected an expression"); } } SourcePeekMatch::Ident(ident) => { @@ -129,6 +131,7 @@ impl<'a> ExpressionParser<'a> { "while" => UnaryAtom::Leaf(Leaf::WhileExpression(Box::new(input.parse()?))), "for" => UnaryAtom::Leaf(Leaf::ForExpression(Box::new(input.parse()?))), "attempt" => UnaryAtom::Leaf(Leaf::AttemptExpression(Box::new(input.parse()?))), + "parse" => return Ok(UnaryAtom::Leaf(Leaf::ParseExpression(Box::new(input.parse()?)))), "None" => UnaryAtom::Leaf(Leaf::Value(SharedValue::new_from_owned( ExpressionValue::None.into_owned(input.parse_any_ident()?.span_range()), ))), diff --git a/src/expressions/mod.rs b/src/expressions/mod.rs index 424fc189..ba066e19 100644 --- a/src/expressions/mod.rs +++ b/src/expressions/mod.rs @@ -12,6 +12,7 @@ mod integer; mod iterator; mod object; mod operations; +mod parser; mod range; mod statements; mod stream; @@ -43,3 +44,4 @@ use float::*; use integer::*; use range::*; use string::*; +use parser::*; diff --git a/src/expressions/parser.rs b/src/expressions/parser.rs new file mode 100644 index 00000000..e593036e --- /dev/null +++ b/src/expressions/parser.rs @@ -0,0 +1,181 @@ +use super::*; + +#[derive(Clone)] +pub(crate) struct ParserExpression { + handle: ParserHandle, +} + +impl HasValueType for ParserExpression { + fn value_type(&self) -> &'static str { + "parser" + } +} + +impl ParserExpression { + pub(crate) fn new(handle: ParserHandle) -> Self { + Self { handle } + } +} + +impl ToExpressionValue for ParserExpression { + fn into_value(self) -> ExpressionValue { + ExpressionValue::Parser(self) + } +} + +impl ToExpressionValue for ParserHandle { + fn into_value(self) -> ExpressionValue { + ParserExpression::new(self).into_value() + } +} + +fn parser<'a>(this: Shared, context: &'a mut MethodCallContext) -> ExecutionResult> { + context.interpreter.parser(this.as_spanned().map(|e, _| e.handle)) +} + +define_interface! { + struct ParserTypeData, + parent: ValueTypeData, + pub(crate) mod parser_interface { + pub(crate) mod methods { + // GENERAL + // ======= + + [context] fn is_end(this: Shared) -> ExecutionResult { + Ok(parser(this, context)?.is_empty()) + } + + // Asserts that the parser has reached the end of input + [context] fn end(this: Shared) -> ExecutionResult<()> { + let parser = parser(this, context)?; + match parser.is_empty() { + true => Ok(()), + false => parser.parse_err("unexpected token")?, + } + } + + [context] fn token_tree(this: Shared) -> ExecutionResult { + Ok(parser(this, context)?.parse()?) + } + + [context] fn ident(this: Shared) -> ExecutionResult { + Ok(parser(this, context)?.parse()?) + } + + [context] fn punct(this: Shared) -> ExecutionResult { + Ok(parser(this, context)?.parse()?) + } + + // LITERALS + // ======== + + [context] fn is_literal(this: Shared) -> ExecutionResult { + Ok(parser(this, context)?.cursor().literal().is_some()) + } + + [context] fn literal(this: Shared) -> ExecutionResult { + let literal = parser(this, context)?.parse()?; + Ok(OutputStream::new_with(|s| s.push_literal(literal))) + } + + [context] fn inferred_literal(this: Shared) -> ExecutionResult { + let literal = parser(this, context)?.parse()?; + Ok(ExpressionValue::for_literal(literal).into_value()) + } + + [context] fn is_char(this: Shared) -> ExecutionResult { + Ok(parser(this, context)?.peek(syn::LitChar)) + } + + [context] fn char_literal(this: Shared) -> ExecutionResult { + let char: syn::LitChar = parser(this, context)?.parse()?; + Ok(OutputStream::new_with(|s| s.push_tokens(char))) + } + + [context] fn char(this: Shared) -> ExecutionResult { + let char: syn::LitChar = parser(this, context)?.parse()?; + Ok(char.value()) + } + + [context] fn is_string(this: Shared) -> ExecutionResult { + Ok(parser(this, context)?.peek(syn::LitStr)) + } + + [context] fn string_literal(this: Shared) -> ExecutionResult { + let string: syn::LitStr = parser(this, context)?.parse()?; + Ok(OutputStream::new_with(|s| s.push_tokens(string))) + } + + [context] fn string(this: Shared) -> ExecutionResult { + let string: syn::LitStr = parser(this, context)?.parse()?; + Ok(string.value()) + } + + [context] fn is_integer(this: Shared) -> ExecutionResult { + Ok(parser(this, context)?.peek(syn::LitInt)) + } + + [context] fn integer_literal(this: Shared) -> ExecutionResult { + let integer: syn::LitInt = parser(this, context)?.parse()?; + Ok(OutputStream::new_with(|s| s.push_tokens(integer))) + } + + [context] fn integer(this: Shared) -> ExecutionResult { + let integer: syn::LitInt = parser(this, context)?.parse()?; + Ok(IntegerExpression::for_litint(&integer)?.into_inner()) + } + + [context] fn is_float(this: Shared) -> ExecutionResult { + Ok(parser(this, context)?.peek(syn::LitFloat)) + } + + [context] fn float_literal(this: Shared) -> ExecutionResult { + let float: syn::LitFloat = parser(this, context)?.parse()?; + Ok(OutputStream::new_with(|s| s.push_tokens(float))) + } + + [context] fn float(this: Shared) -> ExecutionResult { + let float: syn::LitFloat = parser(this, context)?.parse()?; + Ok(FloatExpression::for_litfloat(&float)?.into_inner()) + } + } + pub(crate) mod unary_operations { + } + interface_items { + } + } +} + +impl_resolvable_argument_for! { + ParserTypeData, + (value, context) -> ParserExpression { + match value { + ExpressionValue::Parser(value) => Ok(value), + other => context.err("parser", other), + } + } +} + +impl ToExpressionValue for TokenTree { + fn into_value(self) -> ExpressionValue { + OutputStream::new_with(|s| s.push_raw_token_tree(self)).into_value() + } +} + +impl ToExpressionValue for Ident { + fn into_value(self) -> ExpressionValue { + OutputStream::new_with(|s| s.push_ident(self)).into_value() + } +} + +impl ToExpressionValue for Punct { + fn into_value(self) -> ExpressionValue { + OutputStream::new_with(|s| s.push_punct(self)).into_value() + } +} + +impl ToExpressionValue for Literal { + fn into_value(self) -> ExpressionValue { + OutputStream::new_with(|s| s.push_literal(self)).into_value() + } +} diff --git a/src/expressions/stream.rs b/src/expressions/stream.rs index 6e07e7e9..f294c190 100644 --- a/src/expressions/stream.rs +++ b/src/expressions/stream.rs @@ -169,14 +169,23 @@ define_interface! { string_interface::methods::to_ident_upper_snake(context, string.as_str().into_spanned_ref(this.span_range())) } - [context] fn to_literal(this: SpannedAnyRef) -> ExecutionResult { + // Some literals become ExpressionValue::UnsupportedLiteral but can still be round-tripped back to a stream + [context] fn to_literal(this: SpannedAnyRef) -> ExecutionResult { let string = this.concat_recursive(&ConcatBehaviour::literal(this.span_range())); - string_interface::methods::to_literal(context, string.as_str().into_spanned_ref(this.span_range())) + let literal = string_interface::methods::to_literal(context, string.as_str().into_spanned_ref(this.span_range()))?; + Ok(ExpressionValue::for_literal(literal).into_value()) } // CORE METHODS // ============ + // NOTE: with_span() exists on all values, this is just a specialized mutable version for streams + fn set_span(mut this: Mutable, span_source: Shared) -> ExecutionResult<()> { + let span_range = span_source.resolve_content_span_range().unwrap_or(Span::call_site().span_range()); + this.value.replace_first_level_spans(span_range.join_into_span_else_start()); + Ok(()) + } + fn error(this: Shared, message: Shared) -> ExecutionResult { let error_span_range = this.resolve_content_span_range().unwrap_or(Span::call_site().span_range()); error_span_range.assertion_err(message.as_str()) @@ -233,7 +242,7 @@ define_interface! { [context] fn reinterpret_as_stream(this: Owned) -> ExecutionResult { let source = this.into_inner().value.into_token_stream(); let (reparsed, scope_definitions) = source.source_parse_and_analyze( - |input| SourceStream::parse_with_span(input, context.output_span_range.start()), + |input| SourceStream::parse_with_span(input, context.output_span_range.span_from_join_else_start()), SourceStream::control_flow_pass, )?; let mut inner_interpreter = Interpreter::new(scope_definitions); diff --git a/src/expressions/type_resolution/arguments.rs b/src/expressions/type_resolution/arguments.rs index ebf392a5..a30b6839 100644 --- a/src/expressions/type_resolution/arguments.rs +++ b/src/expressions/type_resolution/arguments.rs @@ -16,7 +16,7 @@ impl<'a> ResolutionContext<'a> { } /// Create an error for the resolution context. - fn err( + pub(crate) fn err( &self, expected_value_kind: &str, value: impl Borrow, diff --git a/src/expressions/type_resolution/interface_macros.rs b/src/expressions/type_resolution/interface_macros.rs index 7c4ec5a7..398b7a50 100644 --- a/src/expressions/type_resolution/interface_macros.rs +++ b/src/expressions/type_resolution/interface_macros.rs @@ -285,12 +285,12 @@ macro_rules! define_interface { $mod_vis:vis mod $mod_name:ident { $mod_methods_vis:vis mod methods { $( - $([$method_context:ident])? fn $method_name:ident($($method_args:tt)*) $(-> $method_output_ty:ty)? $method_body:block + $([$method_context:ident])? fn $method_name:ident($($method_args:tt)*) $(-> $method_output_ty:ty)? $([ignore_type_assertion $method_ignore_type_assertion:tt])? $method_body:block )* } $mod_unary_operations_vis:vis mod unary_operations { $( - $([$unary_context:ident])? fn $unary_name:ident($($unary_args:tt)*) $(-> $unary_output_ty:ty)? $unary_body:block + $([$unary_context:ident])? fn $unary_name:ident($($unary_args:tt)*) $(-> $unary_output_ty:ty)? $([ignore_type_assertion $unary_ignore_type_assertion:tt])? $unary_body:block )* } interface_items { @@ -319,9 +319,19 @@ macro_rules! define_interface { fn asserts() { $( $type_data::assert_first_argument::(); + if_exists! { + {$($method_ignore_type_assertion)?} + {} + {$($type_data::assert_output_type::<$method_output_ty>();)?} + } )* $( $type_data::assert_first_argument::(); + if_exists! { + {$($unary_ignore_type_assertion)?} + {} + {$($type_data::assert_output_type::<$unary_output_ty>();)?} + } )* } diff --git a/src/expressions/type_resolution/outputs.rs b/src/expressions/type_resolution/outputs.rs index 84908785..a7d488a1 100644 --- a/src/expressions/type_resolution/outputs.rs +++ b/src/expressions/type_resolution/outputs.rs @@ -54,18 +54,6 @@ impl ResolvableOutput for ExecutionResult { } } -impl ResolvableOutput for Ident { - fn to_resolved_value(self, output_span_range: SpanRange) -> ExecutionResult { - OutputStream::new_with(|s| s.push_ident(self)).to_resolved_value(output_span_range) - } -} - -impl ResolvableOutput for Literal { - fn to_resolved_value(self, output_span_range: SpanRange) -> ExecutionResult { - ExpressionValue::for_literal(self).to_resolved_value(output_span_range) - } -} - pub(crate) trait StreamAppender { fn append(self, output: &mut OutputStream) -> ExecutionResult<()>; } diff --git a/src/expressions/type_resolution/type_data.rs b/src/expressions/type_resolution/type_data.rs index b97b3f3f..08e16ace 100644 --- a/src/expressions/type_resolution/type_data.rs +++ b/src/expressions/type_resolution/type_data.rs @@ -48,6 +48,8 @@ pub(crate) trait HierarchicalTypeData { fn assert_first_argument>() {} + fn assert_output_type() {} + fn resolve_own_method(_method_name: &str) -> Option { None } diff --git a/src/expressions/value.rs b/src/expressions/value.rs index 18832471..61f5a785 100644 --- a/src/expressions/value.rs +++ b/src/expressions/value.rs @@ -16,6 +16,7 @@ pub(crate) enum ExpressionValue { Stream(StreamExpression), Range(RangeExpression), Iterator(IteratorExpression), + Parser(ParserExpression), } #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -32,6 +33,7 @@ pub(crate) enum ValueKind { Stream, Range, Iterator, + Parser, } impl ValueKind { @@ -46,6 +48,7 @@ impl ValueKind { static STREAM: StreamTypeData = StreamTypeData; static RANGE: RangeTypeData = RangeTypeData; static ITERATOR: IteratorTypeData = IteratorTypeData; + static PARSER: ParserTypeData = ParserTypeData; match self { ValueKind::None => &NONE, ValueKind::Integer(kind) => kind.method_resolver(), @@ -59,6 +62,7 @@ impl ValueKind { ValueKind::Stream => &STREAM, ValueKind::Range => &RANGE, ValueKind::Iterator => &ITERATOR, + ValueKind::Parser => &PARSER, } } @@ -83,6 +87,9 @@ impl ValueKind { ValueKind::Stream => false, ValueKind::Range => true, ValueKind::Iterator => false, + // A parser is a handle, to can be cloned transparently. + // It may fail to be able to be used to parse if the underlying stream is out of scope of course. + ValueKind::Parser => true, } } } @@ -230,7 +237,8 @@ define_interface! { stream_interface::methods::to_ident_upper_snake(context, spanned) } - [context] fn to_literal(this: OwnedValue) -> ExecutionResult { + // Some literals become ExpressionValue::UnsupportedLiteral but can still be round-tripped back to a stream + [context] fn to_literal(this: OwnedValue) -> ExecutionResult { let stream = this.into_stream()?; let spanned = stream.into_spanned_ref(context.output_span_range); stream_interface::methods::to_literal(context, spanned) @@ -532,6 +540,7 @@ impl ExpressionValue { ExpressionValue::Stream(_) => ValueKind::Stream, ExpressionValue::Range(_) => ValueKind::Range, ExpressionValue::Iterator(_) => ValueKind::Iterator, + ExpressionValue::Parser(_) => ValueKind::Parser, ExpressionValue::UnsupportedLiteral(_) => ValueKind::UnsupportedLiteral, } } @@ -579,6 +588,7 @@ impl ExpressionValue { } ExpressionValue::Iterator(value) => operation.unsupported(value), ExpressionValue::Range(value) => operation.unsupported(value), + ExpressionValue::Parser(value) => operation.unsupported(value), } } @@ -741,6 +751,9 @@ impl ExpressionValue { let iterator = IteratorExpression::new_for_range(range.clone())?; iterator.output_items_to(output, Grouping::Flattened)? } + Self::Parser(_) => { + return output.type_err("Parsers cannot be output to a stream"); + } }; Ok(()) } @@ -777,6 +790,9 @@ impl ExpressionValue { ExpressionValue::Range(range) => { range.concat_recursive_into(output, behaviour)?; } + ExpressionValue::Parser(_) => { + return behaviour.error_span_range.type_err("Parsers cannot be output to a string"); + } ExpressionValue::Integer(_) | ExpressionValue::Float(_) | ExpressionValue::Char(_) @@ -916,6 +932,7 @@ impl HasValueType for ExpressionValue { Self::Stream(value) => value.value_type(), Self::Iterator(value) => value.value_type(), Self::Range(value) => value.value_type(), + Self::Parser(value) => value.value_type(), } } } diff --git a/src/extensions/errors_and_spans.rs b/src/extensions/errors_and_spans.rs index 033e1b6d..d65d93dc 100644 --- a/src/extensions/errors_and_spans.rs +++ b/src/extensions/errors_and_spans.rs @@ -105,11 +105,11 @@ pub(crate) trait HasSpanRange { #[allow(unused)] fn start_span(&self) -> Span { - self.span_range().start() + self.span_range().start } fn end_span(&self) -> Span { - self.span_range().end() + self.span_range().end } fn span_from_join_else_start(&self) -> Span { @@ -179,16 +179,6 @@ impl SpanRange { pub(crate) fn set_end(&mut self, end: Span) { self.end = end; } - - #[allow(unused)] - pub(crate) fn start(&self) -> Span { - self.start - } - - #[allow(unused)] - pub(crate) fn end(&self) -> Span { - self.end - } } // This is implemented so we can create an error from it using `Error::new_spanned(..)` diff --git a/src/interpretation/input_handler.rs b/src/interpretation/input_handler.rs index c206cde8..f0bf32c9 100644 --- a/src/interpretation/input_handler.rs +++ b/src/interpretation/input_handler.rs @@ -41,6 +41,13 @@ impl InputHandler { self.parsers.remove(handle); } + pub(super) fn get( + &mut self, + handle: ParserHandle, + ) -> Option<&mut ParseStack<'static, Output>> { + self.parsers.get_mut(handle) + } + pub(super) fn current_stack( &mut self, span_source: &impl HasSpanRange, diff --git a/src/interpretation/interpreter.rs b/src/interpretation/interpreter.rs index b4dc060d..dbb789c9 100644 --- a/src/interpretation/interpreter.rs +++ b/src/interpretation/interpreter.rs @@ -219,18 +219,18 @@ impl Interpreter { } // Input - pub(crate) fn start_parse( + pub(crate) fn start_parse( &mut self, stream: OutputStream, - f: impl FnOnce(&mut Interpreter) -> ExecutionResult<()>, - ) -> ExecutionResult<()> { + f: impl FnOnce(&mut Interpreter, ParserHandle) -> ExecutionResult, + ) -> ExecutionResult { stream.parse_with(|input| { let handle = unsafe { // SAFETY: This is paired with `finish_parse` below, // without any early returns in the middle self.input_handler.start_parse(input) }; - let result = f(self); + let result = f(self, handle); unsafe { // SAFETY: This is paired with `start_parse` above self.input_handler.finish_parse(handle); @@ -239,6 +239,15 @@ impl Interpreter { }) } + pub(crate) fn parser( + &mut self, + handle: Spanned, + ) -> ExecutionResult> { + let stack = self.input_handler.get(handle.value) + .ok_or_else(|| handle.value_error("This parser is no longer available"))?; + Ok(stack.current()) + } + pub(crate) fn parse_group( &mut self, span_source: &impl HasSpanRange, diff --git a/src/interpretation/mod.rs b/src/interpretation/mod.rs index 8df4fb46..610a1a17 100644 --- a/src/interpretation/mod.rs +++ b/src/interpretation/mod.rs @@ -14,7 +14,7 @@ mod variable; use crate::internal_prelude::*; pub(crate) use bindings::*; use control_flow_pass::*; -use input_handler::*; +pub(crate) use input_handler::*; pub(crate) use interpret_traits::*; pub(crate) use interpreter::*; use output_handler::*; diff --git a/src/interpretation/output_stream.rs b/src/interpretation/output_stream.rs index 52b55bbe..25657eb5 100644 --- a/src/interpretation/output_stream.rs +++ b/src/interpretation/output_stream.rs @@ -55,6 +55,10 @@ impl OutputStream { self.push_raw_token_tree(punct.into()); } + pub(crate) fn push_tokens(&mut self, tokens: impl ToTokens) { + self.extend_raw_tokens(tokens.into_token_stream()); + } + pub(crate) fn push_grouped( &mut self, appender: impl FnOnce(&mut Self) -> ExecutionResult<()>, @@ -120,6 +124,7 @@ impl OutputStream { let parse_result = self.clone().parse_as::(); match parse_result { Ok(syn_lit) => ExpressionValue::for_syn_lit(syn_lit).into_inner(), + // Keep as stream otherwise Err(_) => self.into_value(), } } diff --git a/src/misc/keywords.rs b/src/misc/keywords.rs index cfaab80e..e83ec6b5 100644 --- a/src/misc/keywords.rs +++ b/src/misc/keywords.rs @@ -31,15 +31,17 @@ pub(crate) mod keyword { pub(crate) const REVERT: &str = "revert"; pub(crate) const EMIT: &str = "emit"; pub(crate) const ATTEMPT: &str = "attempt"; + pub(crate) const PARSE: &str = "parse"; } pub(crate) fn is_keyword(ident: &str) -> bool { - matches!(ident, keyword::REVERT | keyword::EMIT | keyword::ATTEMPT) + matches!(ident, keyword::REVERT | keyword::EMIT | keyword::ATTEMPT | keyword::PARSE) } ExactIdent![emit as EmitKeyword]; ExactIdent![revert as RevertKeyword]; ExactIdent![attempt as AttemptKeyword]; +ExactIdent![parse as ParseKeyword]; // CONTEXTUAL KEYWORDS // These can still be used as identifiers in other contexts. diff --git a/src/misc/parse_traits.rs b/src/misc/parse_traits.rs index e81697f5..88ebbe14 100644 --- a/src/misc/parse_traits.rs +++ b/src/misc/parse_traits.rs @@ -332,6 +332,8 @@ impl Parse for T { } } + +pub(crate) type OutputParseStream<'a> = &'a ParseBuffer<'a, Output>; pub(crate) type ParseStream<'a, K> = &'a ParseBuffer<'a, K>; // We create our own ParseBuffer mostly so we can overwrite diff --git a/src/transformation/patterns.rs b/src/transformation/patterns.rs index 6fc77191..00f0ad99 100644 --- a/src/transformation/patterns.rs +++ b/src/transformation/patterns.rs @@ -359,7 +359,7 @@ impl HandleDestructure for StreamPattern { .resolve_as("The value destructured with a stream pattern")?; // TODO[parser-no-output]: Remove this once transformers no longer output let _ = interpreter.capture_output(|interpreter| { - interpreter.start_parse(stream.value, |interpreter| { + interpreter.start_parse(stream.value, |interpreter, _| { self.content.handle_transform(interpreter) }) })?; diff --git a/tests/compilation_failures/core/set_span_example.rs b/tests/compilation_failures/core/set_span_example.rs new file mode 100644 index 00000000..0255e524 --- /dev/null +++ b/tests/compilation_failures/core/set_span_example.rs @@ -0,0 +1,24 @@ +use preinterpret::*; + +// Taken from core.rs +macro_rules! capitalize_variants { + ($enum_name:ident, [$($variants:ident),*]) => {run!{ + let enum_name = %raw[$enum_name]; + let variants = []; + for variant in [$(%raw[$variants]),*] { + let capitalized = variant.to_string().capitalize().to_ident(); + capitalized.set_span(variant); + variants.push(capitalized); + } + + %[ + enum #enum_name { + #(variants.intersperse(%[,])) + } + ] + }}; +} + +capitalize_variants!(MyEnum, [helloWorld, Test, HelloWorld]); + +fn main() {} diff --git a/tests/compilation_failures/core/set_span_example.stderr b/tests/compilation_failures/core/set_span_example.stderr new file mode 100644 index 00000000..fc079d23 --- /dev/null +++ b/tests/compilation_failures/core/set_span_example.stderr @@ -0,0 +1,9 @@ +error[E0428]: the name `HelloWorld` is defined multiple times + --> tests/compilation_failures/core/set_span_example.rs:22:49 + | +22 | capitalize_variants!(MyEnum, [helloWorld, Test, HelloWorld]); + | ---------- ^^^^^^^^^^ `HelloWorld` redefined here + | | + | previous definition of the type `HelloWorld` here + | + = note: `HelloWorld` must be defined only once in the type namespace of this enum diff --git a/tests/compilation_failures/expressions/invalid_unary_operator.stderr b/tests/compilation_failures/expressions/invalid_unary_operator.stderr index c2abe00b..b72dcef7 100644 --- a/tests/compilation_failures/expressions/invalid_unary_operator.stderr +++ b/tests/compilation_failures/expressions/invalid_unary_operator.stderr @@ -1,4 +1,4 @@ -error: Expected ! or - +error: Expected an expression --> tests/compilation_failures/expressions/invalid_unary_operator.rs:5:11 | 5 | #(^10) diff --git a/tests/literal.rs b/tests/literal.rs index 41bc26aa..313e15dd 100644 --- a/tests/literal.rs +++ b/tests/literal.rs @@ -21,6 +21,7 @@ fn test_c_string_literal() { run!(%[c '"' hello World! "\""].to_literal()), c"helloWorld!" ); + run!(%[].assert_eq(%[c '"' hello World! "\""].to_literal().to_debug_string(), "c\"helloWorld!\"")); } #[test] @@ -28,6 +29,8 @@ fn test_integer_literal() { assert_eq!(run!(%["123" 456].to_literal()), 123456); assert_eq!(run!(%[456u "32"].to_literal()), 456); assert_eq!(run!(%[000 u64].to_literal()), 0); + + run!(%[].assert_eq(%[456u "32"].to_literal().to_debug_string(), "456u32")); } #[test] @@ -35,6 +38,8 @@ fn test_float_literal() { assert_eq!(run!(%[0 . 123].to_literal()), 0.123); assert_eq!(run!(%[677f32].to_literal()), 677f32); assert_eq!(run!(%["12" 9f64].to_literal()), 129f64); + + run!(%[].assert_eq(%["12" 9f64].to_literal().to_debug_string(), "129f64")); } #[test] diff --git a/tests/parsing.rs b/tests/parsing.rs new file mode 100644 index 00000000..6b21af44 --- /dev/null +++ b/tests/parsing.rs @@ -0,0 +1,31 @@ +#[path = "helpers/prelude.rs"] +mod prelude; +use prelude::*; + +#[test] +#[cfg_attr(miri, ignore = "incompatible with miri")] +fn test_transfoming_compilation_failures() { + if !should_run_ui_tests() { + // Some of the outputs are different on nightly, so don't test these + return; + } + let t = trybuild::TestCases::new(); + t.compile_fail("tests/compilation_failures/parsing/*.rs"); +} + +#[test] +fn test_variable_parsing() { + run! { + let stream = %[]; + let output = parse stream => |input| { + %[#{ + let _ = input.punct(); + emit input.ident(); + let _ = input.ident(); + emit input.ident(); + let _ = input.punct(); + }] + }; + %[].assert_eq(output.to_debug_string(), "%[Hello World]") + } +} From b1576ed04bbe9b6316b73694fb855b0aced8f358 Mon Sep 17 00:00:00 2001 From: David Edey Date: Sat, 29 Nov 2025 00:35:22 +0000 Subject: [PATCH 3/3] fix: Style fix --- src/expressions/control_flow.rs | 6 ++++-- src/expressions/evaluation/control_flow_analysis.rs | 4 +--- src/expressions/evaluation/value_frames.rs | 3 +-- src/expressions/mod.rs | 2 +- src/expressions/parser.rs | 9 +++++++-- src/expressions/value.rs | 4 +++- src/interpretation/input_handler.rs | 13 +++++++------ src/interpretation/interpreter.rs | 4 +++- src/misc/keywords.rs | 5 ++++- src/misc/parse_traits.rs | 1 - 10 files changed, 31 insertions(+), 20 deletions(-) diff --git a/src/expressions/control_flow.rs b/src/expressions/control_flow.rs index 5d2f0e2e..195a824a 100644 --- a/src/expressions/control_flow.rs +++ b/src/expressions/control_flow.rs @@ -604,7 +604,9 @@ impl ParseExpression { interpreter: &mut Interpreter, ownership: RequestedValueOwnership, ) -> ExecutionResult { - let input = self.input.evaluate_owned(interpreter)? + let input = self + .input + .evaluate_owned(interpreter)? .resolve_as("The input to a parse expression")?; interpreter.enter_scope(self.scope); @@ -617,4 +619,4 @@ impl ParseExpression { interpreter.exit_scope(self.scope); Ok(output) } -} \ No newline at end of file +} diff --git a/src/expressions/evaluation/control_flow_analysis.rs b/src/expressions/evaluation/control_flow_analysis.rs index 03b5f585..42b63722 100644 --- a/src/expressions/evaluation/control_flow_analysis.rs +++ b/src/expressions/evaluation/control_flow_analysis.rs @@ -185,9 +185,7 @@ impl Leaf { Leaf::AttemptExpression(attempt_expression) => { attempt_expression.control_flow_pass(context) } - Leaf::ParseExpression(parse_expression) => { - parse_expression.control_flow_pass(context) - } + Leaf::ParseExpression(parse_expression) => parse_expression.control_flow_pass(context), Leaf::Discarded(_) => Ok(()), Leaf::Value(_) => Ok(()), } diff --git a/src/expressions/evaluation/value_frames.rs b/src/expressions/evaluation/value_frames.rs index 2bd1d06f..0b73a767 100644 --- a/src/expressions/evaluation/value_frames.rs +++ b/src/expressions/evaluation/value_frames.rs @@ -752,8 +752,7 @@ impl EvaluationFrame for BinaryOperationBuilder { // Try method resolution first (we already determined this during left evaluation) if let Some(method) = method { // TODO[operation-refactor]: Use proper span range from operation - let span_range = - SpanRange::new_between(left.span_range(), right.span_range()); + let span_range = SpanRange::new_between(left.span_range(), right.span_range()); let mut call_context = MethodCallContext { output_span_range: span_range, diff --git a/src/expressions/mod.rs b/src/expressions/mod.rs index ba066e19..28fda0d3 100644 --- a/src/expressions/mod.rs +++ b/src/expressions/mod.rs @@ -42,6 +42,6 @@ use character::*; use expression_parsing::*; use float::*; use integer::*; +use parser::*; use range::*; use string::*; -use parser::*; diff --git a/src/expressions/parser.rs b/src/expressions/parser.rs index e593036e..9ba2a811 100644 --- a/src/expressions/parser.rs +++ b/src/expressions/parser.rs @@ -29,8 +29,13 @@ impl ToExpressionValue for ParserHandle { } } -fn parser<'a>(this: Shared, context: &'a mut MethodCallContext) -> ExecutionResult> { - context.interpreter.parser(this.as_spanned().map(|e, _| e.handle)) +fn parser<'a>( + this: Shared, + context: &'a mut MethodCallContext, +) -> ExecutionResult> { + context + .interpreter + .parser(this.as_spanned().map(|e, _| e.handle)) } define_interface! { diff --git a/src/expressions/value.rs b/src/expressions/value.rs index 61f5a785..fe25d2f3 100644 --- a/src/expressions/value.rs +++ b/src/expressions/value.rs @@ -791,7 +791,9 @@ impl ExpressionValue { range.concat_recursive_into(output, behaviour)?; } ExpressionValue::Parser(_) => { - return behaviour.error_span_range.type_err("Parsers cannot be output to a string"); + return behaviour + .error_span_range + .type_err("Parsers cannot be output to a string"); } ExpressionValue::Integer(_) | ExpressionValue::Float(_) diff --git a/src/interpretation/input_handler.rs b/src/interpretation/input_handler.rs index f0bf32c9..25125ec0 100644 --- a/src/interpretation/input_handler.rs +++ b/src/interpretation/input_handler.rs @@ -1,5 +1,5 @@ use super::*; -use slotmap::{SlotMap, new_key_type}; +use slotmap::{new_key_type, SlotMap}; new_key_type! { pub(crate) struct ParserHandle; @@ -37,14 +37,15 @@ impl InputHandler { /// SAFETY: Must be called after a prior `start_parse` call, and while the input is still alive. pub(super) unsafe fn finish_parse(&mut self, handle: ParserHandle) { let popped_handle = self.parser_stack.pop(); - assert_eq!(popped_handle, Some(handle), "Popped handle does not match the provided handle"); + assert_eq!( + popped_handle, + Some(handle), + "Popped handle does not match the provided handle" + ); self.parsers.remove(handle); } - pub(super) fn get( - &mut self, - handle: ParserHandle, - ) -> Option<&mut ParseStack<'static, Output>> { + pub(super) fn get(&mut self, handle: ParserHandle) -> Option<&mut ParseStack<'static, Output>> { self.parsers.get_mut(handle) } diff --git a/src/interpretation/interpreter.rs b/src/interpretation/interpreter.rs index dbb789c9..a14a0cf1 100644 --- a/src/interpretation/interpreter.rs +++ b/src/interpretation/interpreter.rs @@ -243,7 +243,9 @@ impl Interpreter { &mut self, handle: Spanned, ) -> ExecutionResult> { - let stack = self.input_handler.get(handle.value) + let stack = self + .input_handler + .get(handle.value) .ok_or_else(|| handle.value_error("This parser is no longer available"))?; Ok(stack.current()) } diff --git a/src/misc/keywords.rs b/src/misc/keywords.rs index e83ec6b5..48c97442 100644 --- a/src/misc/keywords.rs +++ b/src/misc/keywords.rs @@ -35,7 +35,10 @@ pub(crate) mod keyword { } pub(crate) fn is_keyword(ident: &str) -> bool { - matches!(ident, keyword::REVERT | keyword::EMIT | keyword::ATTEMPT | keyword::PARSE) + matches!( + ident, + keyword::REVERT | keyword::EMIT | keyword::ATTEMPT | keyword::PARSE + ) } ExactIdent![emit as EmitKeyword]; diff --git a/src/misc/parse_traits.rs b/src/misc/parse_traits.rs index 88ebbe14..0e2477ce 100644 --- a/src/misc/parse_traits.rs +++ b/src/misc/parse_traits.rs @@ -332,7 +332,6 @@ impl Parse for T { } } - pub(crate) type OutputParseStream<'a> = &'a ParseBuffer<'a, Output>; pub(crate) type ParseStream<'a, K> = &'a ParseBuffer<'a, K>;