From 91adcd40f514ee5bd5bc422fd32714105e0f731e Mon Sep 17 00:00:00 2001 From: Schrottkatze Date: Sat, 18 Nov 2023 18:34:03 +0100 Subject: [PATCH] wrote tests for parser and checks --- src/builtins/namespace.rs | 9 ----- src/main.rs | 85 +-------------------------------------- src/syntax/check.rs | 36 +++++++++++++---- src/syntax/error.rs | 26 ++++++------ src/syntax/mod.rs | 15 ++++--- 5 files changed, 52 insertions(+), 119 deletions(-) diff --git a/src/builtins/namespace.rs b/src/builtins/namespace.rs index 36ff066..d420de2 100644 --- a/src/builtins/namespace.rs +++ b/src/builtins/namespace.rs @@ -297,12 +297,3 @@ impl From> for InternalTypeDef { } } } - -// what is a type apart from the obvious? -// - it has Traits (integer might have the trait numeric for example)-> also need trait system, should share a namespace tho? - -// spec for add -// -// inputs: [ numeric numeric ] -// outputs: numeric -// diff --git a/src/main.rs b/src/main.rs index c019514..cd023da 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,88 +1,5 @@ -use builtins::initialise_globals; -use codespan_reporting::{ - files::SimpleFiles, - term::{ - self, - termcolor::{ColorChoice, StandardStream}, - }, -}; -use syntax::parse_syntax; - -use crate::syntax::check::check; - mod builtins; mod lexer; mod syntax; -mod type_repr; -fn main() { - let mut files = SimpleFiles::new(); - let mut out_errs = Vec::new(); - - let invalid_toks = "meow | gay $ error!\\"; - let invalid_toks_id = files.add("invalid_toks", invalid_toks); - if let Err(err) = parse_syntax(invalid_toks, invalid_toks_id) { - out_errs.push(err) - } - - let invalid_no_streamer = "| invert | save \"./image_processed.jpg\""; - let invalid_no_streamer_id = files.add("invalid_no_streamer", invalid_no_streamer); - if let Err(mut errs) = check( - parse_syntax(invalid_no_streamer, invalid_no_streamer_id).unwrap(), - invalid_no_streamer, - invalid_no_streamer_id, - ) { - out_errs.append(&mut errs) - } - - let invalid_missing_filters = "meow | | test | awa | | nya"; - let invalid_missing_filters_id = files.add("invalid_missing_filters", invalid_missing_filters); - if let Err(mut errs) = check( - parse_syntax(invalid_missing_filters, invalid_missing_filters_id).unwrap(), - invalid_missing_filters, - invalid_missing_filters_id, - ) { - out_errs.append(&mut errs) - } - - let invalid_no_sink = "meow | invert | "; - let invalid_no_sink_id = files.add("invalid_no_sink", invalid_no_sink); - if let Err(mut errs) = check( - parse_syntax(invalid_no_sink, invalid_no_sink_id).unwrap(), - invalid_no_sink, - invalid_no_sink_id, - ) { - out_errs.append(&mut errs) - } - - let global_ns = initialise_globals(); - let int = global_ns.get_type_by_name("integer").unwrap(); - let numeric = global_ns.get_trait_by_name("Numeric").unwrap(); - assert!(int.has_trait(&numeric)); - - let valid_add_input_pipe = "1 | add 2"; - let valid_add_input_pipe_id = files.add("valid_add_input_pipe", valid_add_input_pipe); - let syntax = dbg!(check( - parse_syntax(valid_add_input_pipe, valid_add_input_pipe_id).unwrap(), - valid_add_input_pipe, - valid_add_input_pipe_id, - ) - .unwrap()); - - let valid_add_input_args = "add 1 2"; - let valid_add_input_args_id = files.add("valid_add_input_args", valid_add_input_args); - let syntax = dbg!(check( - parse_syntax(valid_add_input_args, valid_add_input_args_id).unwrap(), - valid_add_input_args, - valid_add_input_args_id, - ) - .unwrap()); - - let writer = StandardStream::stderr(ColorChoice::Always); - let config = term::Config::default(); - - for err in out_errs { - let writer = &mut writer.lock(); - term::emit(writer, &config, &files, &err.to_diagnostic()).unwrap(); - } -} +fn main() {} diff --git a/src/syntax/check.rs b/src/syntax/check.rs index 953b75e..d689650 100644 --- a/src/syntax/check.rs +++ b/src/syntax/check.rs @@ -1,6 +1,6 @@ use super::{ error::{FileId, SyntaxError}, - PipelineElement, PipelineElementKind, + parse_syntax, PipelineElement, PipelineElementKind, }; pub fn check( @@ -11,17 +11,15 @@ pub fn check( let mut errs = Vec::new(); if let Err(e_span) = check_missing_streamer(&syntax) { - errs.push(SyntaxError::MissingStreamer(vec![(file_id, e_span)])); + errs.push(SyntaxError::MissingStreamer(vec![e_span])); } - if let Err(mut err_locs) = check_missing_filters(&syntax) { - errs.push(SyntaxError::MissingFilter( - err_locs.into_iter().map(|loc| (file_id, loc)).collect(), - )) + if let Err(err_locs) = check_missing_filters(&syntax) { + errs.push(SyntaxError::MissingFilter(err_locs)) } if let Err(e_span) = check_missing_sink(&syntax) { - errs.push(SyntaxError::MissingSink(vec![(file_id, e_span)])); + errs.push(SyntaxError::MissingSink(vec![e_span])); } if errs.is_empty() { @@ -43,6 +41,14 @@ fn check_missing_streamer(syntax: &Vec) -> Result<(), logos::Sp } } +#[test] +fn test_check_missing_streamer() { + let test_data = "| invert | save \"./image_processed.jpg\""; + let syntax = parse_syntax(test_data).unwrap(); + + assert_eq!(check_missing_streamer(&syntax), Err(0..1)) +} + fn check_missing_filters(syntax: &Vec) -> Result<(), Vec> { let mut missing_filter_locs = Vec::new(); @@ -69,6 +75,14 @@ fn check_missing_filters(syntax: &Vec) -> Result<(), Vec) -> Result<(), logos::Span> { if let Some(&PipelineElement { kind: PipelineElementKind::Pipe, @@ -80,3 +94,11 @@ fn check_missing_sink(syntax: &Vec) -> Result<(), logos::Span> Ok(()) } } + +#[test] +fn test_check_missing_sink() { + let test_data = "meow | invert | "; + let syntax = parse_syntax(test_data).unwrap(); + + assert_eq!(check_missing_sink(&syntax), Err(14..15)) +} diff --git a/src/syntax/error.rs b/src/syntax/error.rs index 19f39fc..cf5a02e 100644 --- a/src/syntax/error.rs +++ b/src/syntax/error.rs @@ -6,13 +6,13 @@ pub type FileId = usize; #[derive(Debug, Clone)] pub enum SyntaxError { /// This variant indicates a token that the Lexer didn't recognize - InvalidToken(Vec<(FileId, logos::Span)>), + InvalidToken(Vec), /// `MissingStreamer` means, that the pipeline starts with a Pipe (`|`), so it has no streamer as input in front of it. - MissingStreamer(Vec<(FileId, logos::Span)>), + MissingStreamer(Vec), /// `MissingSink` means, that the pipeline ends with a Pipe (`|`), meaning that the output can't go anywhere - MissingSink(Vec<(FileId, logos::Span)>), + MissingSink(Vec), /// This indicates a missing filter somewhere in the pipeline, meaning that there's 2 pipes after one another - MissingFilter(Vec<(FileId, logos::Span)>), + MissingFilter(Vec), /// A literal cannot be a sink, TODO LiteralAsSink, /// A literal can't be a filter either, TODO @@ -22,14 +22,14 @@ pub enum SyntaxError { } impl SyntaxError { - pub fn to_diagnostic(&self) -> Diagnostic { + pub fn to_diagnostic(&self, file_id: usize) -> Diagnostic { match self { Self::InvalidToken(errs) => Diagnostic::error() .with_message("failed to parse invalid tokens") .with_labels( errs.into_iter() - .map(|(file_id, span)| { - Label::primary(*file_id, span.clone()).with_message("invalid token") + .map(|span| { + Label::primary(file_id, span.clone()).with_message("invalid token") }) .collect(), ), @@ -37,8 +37,8 @@ impl SyntaxError { .with_message("pipelines must always start with a streamer") .with_labels( locs.into_iter() - .map(|(file_id, span)| { - Label::primary(*file_id, span.clone()).with_message("missing streamer") + .map(|span| { + Label::primary(file_id, span.clone()).with_message("missing streamer") }) .collect(), ), @@ -46,8 +46,8 @@ impl SyntaxError { .with_message("missing filters in pipelines") .with_labels( locs.into_iter() - .map(|(file_id, span)| { - Label::primary(*file_id, span.clone()).with_message("no filter here") + .map(|span| { + Label::primary(file_id, span.clone()).with_message("no filter here") }) .collect(), ), @@ -55,9 +55,7 @@ impl SyntaxError { .with_message("pipelines cannot end on a pipe") .with_labels( locs.into_iter() - .map(|(file_id, span)| { - Label::primary(*file_id, span.clone()).with_message("no sink") - }) + .map(|span| Label::primary(file_id, span.clone()).with_message("no sink")) .collect(), ), _ => unimplemented!(), diff --git a/src/syntax/mod.rs b/src/syntax/mod.rs index eec82fc..1d188bd 100644 --- a/src/syntax/mod.rs +++ b/src/syntax/mod.rs @@ -5,7 +5,6 @@ use logos::Span; use crate::lexer::Token; -use self::error::FileId; use self::error::SyntaxError; pub mod check; @@ -37,7 +36,7 @@ pub enum CommandPartKind { String(String), } -pub fn parse_syntax(input: &str, file_id: FileId) -> Result, SyntaxError> { +pub fn parse_syntax(input: &str) -> Result, Vec> { let lexer = Token::lexer(input); let mut errs = Vec::new(); @@ -83,7 +82,7 @@ pub fn parse_syntax(input: &str, file_id: FileId) -> Result _ => {} } } else { - errs.push((file_id, span)) + errs.push(span) } } @@ -91,7 +90,7 @@ pub fn parse_syntax(input: &str, file_id: FileId) -> Result let span = partial_command.first().unwrap().span.start..partial_command.last().unwrap().span.end; r.push(PipelineElement { - kind: PipelineElementKind::Command(mem::replace(&mut partial_command, Vec::new())), + kind: PipelineElementKind::Command(std::mem::take(&mut partial_command)), span, }); } @@ -99,6 +98,12 @@ pub fn parse_syntax(input: &str, file_id: FileId) -> Result if errs.is_empty() { Ok(r) } else { - Err(SyntaxError::InvalidToken(errs)) + Err(errs) } } + +#[test] +fn test_invalid_toks() { + let test_data = "meow | gay $ error!\\"; + assert_eq!(parse_syntax(test_data), Err(vec![11..12, 19..20])) +}