use std::mem; use logos::Logos; use logos::Span; use crate::lexer::Token; use self::error::FileId; use self::error::SyntaxError; pub mod check; mod error; #[derive(Debug, Clone, PartialEq)] pub struct PipelineElement { pub kind: PipelineElementKind, pub span: Span, } #[derive(Debug, Clone, PartialEq)] pub enum PipelineElementKind { Pipe, Command(Vec), } #[derive(Debug, Clone, PartialEq)] pub struct CommandPart { pub kind: CommandPartKind, pub span: Span, } #[derive(Debug, Clone, PartialEq)] pub enum CommandPartKind { Word(String), Integer(i64), Float(f64), String(String), } pub fn parse_syntax(input: &str, file_id: FileId) -> Result, SyntaxError> { let lexer = Token::lexer(input); let mut errs = Vec::new(); let mut r = Vec::new(); let mut partial_command: Vec = 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 { errs.push((file_id, span)) } } 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, }); } if errs.is_empty() { Ok(r) } else { Err(SyntaxError::InvalidToken(errs)) } }