2023-11-15 11:18:45 +01:00
|
|
|
use core::panic;
|
2023-11-15 10:55:14 +01:00
|
|
|
use std::mem;
|
|
|
|
|
2023-11-15 11:18:45 +01:00
|
|
|
use codespan_reporting::diagnostic::Diagnostic;
|
|
|
|
use codespan_reporting::diagnostic::Label;
|
|
|
|
use codespan_reporting::files::Files;
|
|
|
|
use codespan_reporting::files::SimpleFile;
|
|
|
|
use codespan_reporting::files::SimpleFiles;
|
|
|
|
use codespan_reporting::term;
|
|
|
|
use codespan_reporting::term::termcolor::ColorChoice;
|
|
|
|
use codespan_reporting::term::termcolor::StandardStream;
|
2023-11-15 10:55:14 +01:00
|
|
|
use logos::Logos;
|
|
|
|
use logos::Span;
|
|
|
|
|
|
|
|
use crate::lexer::Token;
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
|
|
pub struct PipelineElement {
|
|
|
|
kind: PipelineElementKind,
|
|
|
|
span: Span,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
|
|
pub enum PipelineElementKind {
|
|
|
|
Pipe,
|
|
|
|
Command(Vec<CommandPart>),
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
|
|
pub struct CommandPart {
|
|
|
|
kind: CommandPartKind,
|
|
|
|
span: Span,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
|
|
pub enum CommandPartKind {
|
|
|
|
Word(String),
|
|
|
|
Integer(i64),
|
|
|
|
Float(f64),
|
|
|
|
String(String),
|
|
|
|
}
|
|
|
|
|
2023-11-15 11:18:45 +01:00
|
|
|
pub fn parse_syntax(input: &str) -> Vec<PipelineElement> {
|
2023-11-15 10:55:14 +01:00
|
|
|
let lexer = Token::lexer(input);
|
|
|
|
|
|
|
|
let mut r = Vec::new();
|
|
|
|
|
|
|
|
let mut partial_command: Vec<CommandPart> = Vec::new();
|
|
|
|
for (tok, span) in lexer.spanned().into_iter() {
|
|
|
|
if let Ok(tok) = tok {
|
|
|
|
match tok {
|
|
|
|
Token::Pipe => {
|
|
|
|
if !partial_command.is_empty() {
|
|
|
|
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(),
|
|
|
|
)),
|
|
|
|
span,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
r.push(PipelineElement {
|
|
|
|
kind: PipelineElementKind::Pipe,
|
|
|
|
span,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
Token::Word(word) => partial_command.push(CommandPart {
|
|
|
|
kind: CommandPartKind::Word(word.to_owned()),
|
|
|
|
span,
|
|
|
|
}),
|
|
|
|
Token::IntLiteral(int) => partial_command.push(CommandPart {
|
|
|
|
kind: CommandPartKind::Integer(int),
|
|
|
|
span,
|
|
|
|
}),
|
|
|
|
Token::FloatLiteral(float) => partial_command.push(CommandPart {
|
|
|
|
kind: CommandPartKind::Float(float),
|
|
|
|
span,
|
|
|
|
}),
|
|
|
|
Token::StringLiteral(string) => partial_command.push(CommandPart {
|
|
|
|
kind: CommandPartKind::String(string),
|
|
|
|
span,
|
|
|
|
}),
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
} else {
|
2023-11-15 11:18:45 +01:00
|
|
|
panic!("Error at {span:?}")
|
2023-11-15 10:55:14 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if !partial_command.is_empty() {
|
|
|
|
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())),
|
|
|
|
span,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
r
|
|
|
|
}
|
|
|
|
|
2023-11-15 11:18:45 +01:00
|
|
|
pub fn check_syntax(syntax: Vec<PipelineElement>, raw_source: &str) {
|
|
|
|
let mut files = SimpleFiles::new();
|
|
|
|
let file_id = files.add("input", raw_source);
|
|
|
|
|
|
|
|
if let Some(PipelineElement {
|
|
|
|
kind: PipelineElementKind::Pipe,
|
|
|
|
span,
|
|
|
|
}) = syntax.first()
|
|
|
|
{
|
|
|
|
let err = Diagnostic::error()
|
|
|
|
.with_message("Missing streamer for pipeline")
|
|
|
|
.with_labels(vec![
|
|
|
|
Label::primary(file_id, 0..span.end).with_message("expected streamer")
|
|
|
|
])
|
|
|
|
.with_notes(vec!["a pipeline can't start with a pipe".to_string()]);
|
|
|
|
|
|
|
|
let writer = StandardStream::stderr(ColorChoice::Always);
|
|
|
|
let config = codespan_reporting::term::Config::default();
|
|
|
|
|
|
|
|
term::emit(&mut writer.lock(), &config, &files, &err).unwrap();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-15 10:55:14 +01:00
|
|
|
#[test]
|
|
|
|
fn test_simple_parse_pipeline() {
|
|
|
|
let test_pipeline = "load ./image.png | invert | save ./image_processed.jpg";
|
2023-11-15 11:18:45 +01:00
|
|
|
parse_syntax(test_pipeline);
|
2023-11-15 10:55:14 +01:00
|
|
|
}
|