csvx 0.1.17

Comma-Separated Values eXtended
Documentation
use super::*;
use std::borrow::Borrow;

pub fn primitive_parse<T: Borrow<str>>(raw_string: &T) -> Result<Vec<PrimitiveToken>, ()> {
    let mut tokens = vec![];

    let chars: Vec<char> = raw_string.borrow().chars().collect();
    let mut i = 0;
    while i < chars.len() {
        match chars[i] {
            ' ' | '\t' => {}
            '\"' => {
                let mut chars_pending = vec![];
                let mut is_being_escaped = false;

                loop {
                    i += 1;
                    if i >= chars.len() {
                        return Err(());
                    }

                    if is_being_escaped {
                        match chars[i] {
                            'n' => chars_pending.push('\n'),
                            'r' => chars_pending.push('\r'),
                            't' => chars_pending.push('\t'),
                            '\\' => chars_pending.push('\\'),
                            '\0' => chars_pending.push('\0'),
                            '\'' => chars_pending.push('\''),
                            '\"' => chars_pending.push('\"'),
                            _ => chars_pending.push(chars[i]),
                        }
                        is_being_escaped = false;
                    } else {
                        match chars[i] {
                            '\"' => break,
                            '\\' => is_being_escaped = true,
                            _ => chars_pending.push(chars[i]),
                        }
                    }
                }

                tokens.push(PrimitiveToken::Parsed(Token::String(
                    chars_pending.iter().collect(),
                )));
            }
            '+' => tokens.push(PrimitiveToken::Parsed(Token::Add)),
            '-' => tokens.push(PrimitiveToken::Parsed(Token::Sub)),
            '*' => tokens.push(PrimitiveToken::Parsed(Token::Mul)),
            '/' => tokens.push(PrimitiveToken::Parsed(Token::Div)),
            '%' => tokens.push(PrimitiveToken::Parsed(Token::Mod)),
            '^' => tokens.push(PrimitiveToken::Parsed(Token::Xor)),
            '&' => {
                if i + 1 < chars.len() && chars[i + 1] == '&' {
                    i += 1;
                    tokens.push(PrimitiveToken::Parsed(Token::LogicalAnd));
                } else {
                    tokens.push(PrimitiveToken::Parsed(Token::BitwiseAnd));
                }
            }
            '|' => {
                if i + 1 < chars.len() && chars[i + 1] == '|' {
                    i += 1;
                    tokens.push(PrimitiveToken::Parsed(Token::LogicalOr));
                } else {
                    tokens.push(PrimitiveToken::Parsed(Token::BitwiseOr));
                }
            }
            '=' => {
                if i + 1 < chars.len() && chars[i + 1] == '=' {
                    i += 1;
                    tokens.push(PrimitiveToken::Parsed(Token::Equal));
                } else {
                    return Err(());
                }
            }
            '!' => {
                if i + 1 < chars.len() && chars[i + 1] == '=' {
                    i += 1;
                    tokens.push(PrimitiveToken::Parsed(Token::NotEqual));
                } else {
                    tokens.push(PrimitiveToken::Parsed(Token::Not));
                }
            }
            '<' => {
                if i + 1 < chars.len() && chars[i + 1] == '=' {
                    i += 1;
                    tokens.push(PrimitiveToken::Parsed(Token::LessThanEqual));
                } else if i + 1 < chars.len() && chars[i + 1] == '<' {
                    i += 1;
                    tokens.push(PrimitiveToken::Parsed(Token::LeftShift));
                } else {
                    tokens.push(PrimitiveToken::Parsed(Token::LessThan));
                }
            }
            '>' => {
                if i + 1 < chars.len() && chars[i + 1] == '=' {
                    i += 1;
                    tokens.push(PrimitiveToken::Parsed(Token::GreaterThanEqual));
                } else if i + 1 < chars.len() && chars[i + 1] == '>' {
                    i += 1;
                    tokens.push(PrimitiveToken::Parsed(Token::RightShift));
                } else {
                    tokens.push(PrimitiveToken::Parsed(Token::GreaterThan));
                }
            }
            '(' => tokens.push(PrimitiveToken::Parsed(Token::ParenthesisBegin)),
            ')' => tokens.push(PrimitiveToken::Parsed(Token::ParenthesisEnd)),
            ',' => tokens.push(PrimitiveToken::Parsed(Token::Comma)),
            _ => {
                let mut chars_pending = vec![chars[i]];

                while i + 1 < chars.len()
                    && !matches!(
                        chars[i + 1],
                        ' ' | '\t'
                            | '\"'
                            | '+'
                            | '-'
                            | '*'
                            | '/'
                            | '%'
                            | '^'
                            | '&'
                            | '|'
                            | '='
                            | '!'
                            | '<'
                            | '>'
                            | '('
                            | ')'
                            | ','
                    )
                {
                    chars_pending.push(chars[i + 1]);
                    i += 1;
                }

                tokens.push(PrimitiveToken::Raw(chars_pending.iter().collect()));
            }
        }
        i += 1;
    }

    Ok(tokens)
}