From f6da90a354d5f1bbba51e57177f7a8270869c0f0 Mon Sep 17 00:00:00 2001 From: Schrottkatze Date: Mon, 3 Jun 2024 10:53:59 +0200 Subject: [PATCH] lang: improve and simplify error handling and storage fixes wrong error ordering with errors using `forward_parents`. --- crates/lang/src/lst_parser.rs | 44 ++++++++++----- crates/lang/src/lst_parser/error.rs | 2 +- crates/lang/src/lst_parser/events.rs | 53 +++++++++++++++++-- .../lang/src/lst_parser/grammar/expression.rs | 2 +- .../grammar/expression/collection/vec.rs | 2 +- .../lst_parser/grammar/expression/pipeline.rs | 2 +- crates/lang/src/lst_parser/output.rs | 28 +++++++--- flake.nix | 19 ++----- 8 files changed, 110 insertions(+), 42 deletions(-) diff --git a/crates/lang/src/lst_parser.rs b/crates/lang/src/lst_parser.rs index 9b93010..a6ec4d7 100644 --- a/crates/lang/src/lst_parser.rs +++ b/crates/lang/src/lst_parser.rs @@ -1,6 +1,12 @@ use drop_bomb::DropBomb; -use self::{error::SyntaxError, events::Event, input::Input, syntax_kind::SyntaxKind}; +use self::{ + error::SyntaxError, + events::{Event, NodeKind}, + input::Input, + syntax_kind::SyntaxKind, +}; +use std::cell::Cell; pub mod syntax_kind; #[cfg(test)] @@ -12,11 +18,13 @@ pub mod grammar; pub mod input; pub mod output; +const PARSER_STEP_LIMIT: u32 = 4096; + pub struct Parser<'src, 'toks> { input: Input<'src, 'toks>, pos: usize, events: Vec, - errors: Vec, + steps: Cell, } impl<'src, 'toks> Parser<'src, 'toks> { @@ -25,15 +33,16 @@ impl<'src, 'toks> Parser<'src, 'toks> { input, pos: 0, events: Vec::new(), - errors: Vec::new(), + steps: Cell::new(0), } } - pub fn finish(self) -> (Vec, Vec) { - (self.events, self.errors) + pub fn finish(self) -> Vec { + self.events } pub(crate) fn nth(&self, n: usize) -> SyntaxKind { + self.step(); self.input.kind(self.pos + n) } @@ -44,6 +53,7 @@ impl<'src, 'toks> Parser<'src, 'toks> { } pub(crate) fn current(&self) -> SyntaxKind { + self.step(); self.input.kind(self.pos) } @@ -80,6 +90,12 @@ impl<'src, 'toks> Parser<'src, 'toks> { fn push_ev(&mut self, event: Event) { self.events.push(event) } + + fn step(&self) { + let steps = self.steps.get(); + assert!(steps <= PARSER_STEP_LIMIT, "the parser seems stuck..."); + self.steps.set(steps + 1); + } } pub(crate) struct Marker { @@ -95,12 +111,13 @@ impl Marker { } } - pub(crate) fn complete(mut self, p: &mut Parser<'_, '_>, kind: SyntaxKind) -> CompletedMarker { + fn complete_node(mut self, p: &mut Parser, kind: NodeKind) -> CompletedMarker { self.bomb.defuse(); match &mut p.events[self.pos] { - Event::Start { kind: slot, .. } => *slot = kind, + Event::Start { kind: slot, .. } => *slot = kind.clone(), _ => unreachable!(), } + p.push_ev(Event::Finish); CompletedMarker { @@ -109,9 +126,12 @@ impl Marker { } } - pub(crate) fn complete_err(mut self, p: &mut Parser, kind: SyntaxError) -> CompletedMarker { - p.errors.push(kind); - self.complete(p, SyntaxKind::PARSE_ERR) + pub(crate) fn complete(self, p: &mut Parser<'_, '_>, kind: SyntaxKind) -> CompletedMarker { + self.complete_node(p, NodeKind::Syntax(kind)) + } + + pub(crate) fn error(self, p: &mut Parser, kind: SyntaxError) -> CompletedMarker { + self.complete_node(p, NodeKind::Error(kind)) } pub(crate) fn abandon(mut self, p: &mut Parser<'_, '_>) { @@ -119,7 +139,7 @@ impl Marker { if self.pos == p.events.len() - 1 { match p.events.pop() { Some(Event::Start { - kind: SyntaxKind::TOMBSTONE, + kind: NodeKind::Syntax(SyntaxKind::TOMBSTONE), forward_parent: None, }) => (), _ => unreachable!(), @@ -130,7 +150,7 @@ impl Marker { pub(crate) struct CompletedMarker { pos: usize, - kind: SyntaxKind, + kind: NodeKind, } impl CompletedMarker { diff --git a/crates/lang/src/lst_parser/error.rs b/crates/lang/src/lst_parser/error.rs index 1269acc..7fa4431 100644 --- a/crates/lang/src/lst_parser/error.rs +++ b/crates/lang/src/lst_parser/error.rs @@ -1,6 +1,6 @@ use crate::lst_parser::syntax_kind::SyntaxKind; -#[derive(Debug)] +#[derive(Debug, PartialEq, Eq, Clone)] pub enum SyntaxError { Expected(Vec), PipelineNeedsSink, diff --git a/crates/lang/src/lst_parser/events.rs b/crates/lang/src/lst_parser/events.rs index 00d7524..3ed630a 100644 --- a/crates/lang/src/lst_parser/events.rs +++ b/crates/lang/src/lst_parser/events.rs @@ -1,22 +1,69 @@ use crate::lst_parser::syntax_kind::SyntaxKind; +use super::error::SyntaxError; + #[derive(Debug)] pub enum Event { Start { - kind: SyntaxKind, + kind: NodeKind, forward_parent: Option, }, Finish, Eat { count: usize, }, - Error, +} + +#[derive(Debug, Clone, PartialEq)] +pub enum NodeKind { + Syntax(SyntaxKind), + Error(SyntaxError), +} + +impl NodeKind { + pub fn is_syntax(&self) -> bool { + matches!(self, Self::Syntax(_)) + } + + pub fn is_error(&self) -> bool { + matches!(self, Self::Error(_)) + } +} + +impl From for NodeKind { + fn from(value: SyntaxKind) -> Self { + NodeKind::Syntax(value) + } +} + +impl From for NodeKind { + fn from(value: SyntaxError) -> Self { + NodeKind::Error(value) + } +} + +impl PartialEq for NodeKind { + fn eq(&self, other: &SyntaxKind) -> bool { + match self { + NodeKind::Syntax(s) => s == other, + NodeKind::Error(_) => false, + } + } +} + +impl PartialEq for NodeKind { + fn eq(&self, other: &SyntaxError) -> bool { + match self { + NodeKind::Syntax(_) => false, + NodeKind::Error(e) => e == other, + } + } } impl Event { pub(crate) fn tombstone() -> Self { Self::Start { - kind: SyntaxKind::TOMBSTONE, + kind: SyntaxKind::TOMBSTONE.into(), forward_parent: None, } } diff --git a/crates/lang/src/lst_parser/grammar/expression.rs b/crates/lang/src/lst_parser/grammar/expression.rs index 33ef3fc..03c0d10 100644 --- a/crates/lang/src/lst_parser/grammar/expression.rs +++ b/crates/lang/src/lst_parser/grammar/expression.rs @@ -35,7 +35,7 @@ pub fn parenthesized_expr(p: &mut Parser) -> Option { let par_expr = p.start("parenthesized"); expression(p, false); if !p.eat(R_PAREN) { - return Some(par_expr.complete_err(p, SyntaxError::Expected(vec![R_PAREN]))); + return Some(par_expr.error(p, SyntaxError::Expected(vec![R_PAREN]))); } return Some(par_expr.complete(p, PARENTHESIZED_EXPR)); diff --git a/crates/lang/src/lst_parser/grammar/expression/collection/vec.rs b/crates/lang/src/lst_parser/grammar/expression/collection/vec.rs index 6e5884d..385723b 100644 --- a/crates/lang/src/lst_parser/grammar/expression/collection/vec.rs +++ b/crates/lang/src/lst_parser/grammar/expression/collection/vec.rs @@ -21,7 +21,7 @@ pub fn vec_matrix_list(p: &mut Parser) -> CompletedMarker { start.complete(p, LIST) } else { row_start.abandon(p); - start.complete_err(p, SyntaxError::Expected(vec![EXPR, R_BRACK])) + start.error(p, SyntaxError::Expected(vec![EXPR, R_BRACK])) } } diff --git a/crates/lang/src/lst_parser/grammar/expression/pipeline.rs b/crates/lang/src/lst_parser/grammar/expression/pipeline.rs index f2f090d..2c1c678 100644 --- a/crates/lang/src/lst_parser/grammar/expression/pipeline.rs +++ b/crates/lang/src/lst_parser/grammar/expression/pipeline.rs @@ -16,7 +16,7 @@ pub fn pipeline(p: &mut Parser, start_expr: CompletedMarker) -> Option, f: &mut dyn std::fmt::Write, @@ -31,7 +36,7 @@ fn debug_print_green_node( colored: bool, ) -> std::fmt::Result { for _ in 0..lvl { - f.write_str(" ")?; + f.write_str(INDENT_STR)?; } if !colored { @@ -68,7 +73,7 @@ fn debug_print_green_node( debug_print_green_node(c, f, lvl + 1, errs, colored)?; } for _ in 0..lvl { - f.write_str(" ")?; + f.write_str(INDENT_STR)?; } if kind != SyntaxKind::PARSE_ERR { write!(f, "{}", "}\n".yellow()) @@ -123,10 +128,11 @@ impl Output { } pub fn from_parser_output( mut raw_toks: Vec<(SyntaxKind, &str)>, - (mut events, errs): (Vec, Vec), + mut events: Vec, ) -> Self { let mut builder = GreenNodeBuilder::new(); let mut fw_parents = Vec::new(); + let mut errors = Vec::new(); raw_toks.reverse(); for i in 0..events.len() { @@ -170,8 +176,15 @@ impl Output { } for kind in fw_parents.drain(..).rev() { - if kind != SyntaxKind::TOMBSTONE { - builder.start_node(kind.into()); + match kind { + NodeKind::Syntax(kind) if kind != SyntaxKind::TOMBSTONE => { + builder.start_node(kind.into()) + } + NodeKind::Error(err) => { + errors.push(err); + builder.start_node(SyntaxKind::PARSE_ERR.into()) + } + _ => {} } } } @@ -180,13 +193,12 @@ impl Output { let (tok, text): (SyntaxKind, &str) = raw_toks.pop().unwrap(); builder.token(tok.into(), text); }), - Event::Error => todo!(), } } Self { green_node: builder.finish(), - errors: errs, + errors, } } } diff --git a/flake.nix b/flake.nix index caad7d6..8dd48aa 100644 --- a/flake.nix +++ b/flake.nix @@ -27,8 +27,7 @@ pkgs = nixpkgs.legacyPackages.${system}; toolchain = with fenix.packages.${system}; combine [ - default.toolchain - rust-analyzer + complete.toolchain ]; in { default = devenv.lib.mkShell { @@ -39,24 +38,14 @@ config, ... }: { - # languages.rust = { - # enable = true; - # channel = "nightly"; - # components = [ - # "rustc" - # "cargo" - # "clippy" - # "rustfmt" - # "rust-src" - # "rust-analyzer" - # ]; - # }; - pre-commit.hooks = { clippy.enable = false; rustfmt.enable = true; }; + env = { + RUST_BACKTRACE = 1; + }; packages = with pkgs; [ just nushell