g1-common 0.1.0-alpha.3

Common types and traits between the client and server portion of the G1 graph store.
use logos::Logos;

pub struct Lexer<'src>(logos::Lexer<Token, &'src str>);

impl<'src> Lexer<'src> {
    pub fn new(src: &'src str) -> Lexer {
        Lexer(Token::lexer(src))
    }
}

impl<'src> Iterator for Lexer<'src> {
    type Item = (Token, &'src str);

    fn next(&mut self) -> Option<(Token, &'src str)> {
        if self.0.token == Token::End {
            None
        } else {
            while self.0.token == Token::Comment {
                self.0.advance();
            }

            let out = (self.0.token, self.0.slice());
            self.0.advance();
            Some(out)
        }
    }
}

#[derive(Clone, Copy, Debug, Eq, Logos, PartialEq)]
pub enum Token {
    #[end]
    End,

    #[error]
    Error,

    #[regex = "%[^\\r\\n]*"]
    Comment,

    #[token = ".create_atom"]
    DotCreateAtom,

    #[token = ".delete_atom"]
    DotDeleteAtom,

    #[token = ".create_name"]
    DotCreateName,

    #[token = ".delete_name"]
    DotDeleteName,

    #[token = ".upsert_name"]
    DotUpsertName,

    #[token = ".create_edge"]
    DotCreateEdge,

    #[token = ".delete_edge"]
    DotDeleteEdge,

    #[token = ".create_tag"]
    DotCreateTag,

    #[token = ".delete_tag"]
    DotDeleteTag,

    #[token = ".upsert_tag"]
    DotUpsertTag,

    #[token = ".create_blob"]
    DotCreateBlob,

    #[token = ".delete_blob"]
    DotDeleteBlob,

    #[token = ".help"]
    DotHelp,

    #[token = ".list"]
    DotList,

    #[token = ".upsert_blob"]
    DotUpsertBlob,

    #[token = ".quit"]
    DotQuit,

    #[token = ".undefine"]
    DotUndefine,

    #[token = ")"]
    ParenClose,

    #[token = "("]
    ParenOpen,

    #[token = "."]
    Period,

    #[token = ","]
    Comma,

    #[token = "/"]
    Slash,

    #[token = "?-"]
    Query,

    #[token = ":-"]
    Turnstile,

    #[token = "!"]
    Not,

    #[regex = "\"([^'\"\\\\]|\\\\[trn'\"\\\\])*\""]
    String,

    #[regex = "[0-9]+"]
    U32,

    #[regex = "'([^'\"\\\\]|\\\\[trn'\"\\\\])*'"]
    EscapedVar,

    #[regex = "[A-Za-z_-][0-9A-Za-z_-]*"]
    Var,
}

#[derive(Clone, Copy, Debug, Eq, Logos, PartialEq)]
pub enum StringToken {
    #[end]
    End,

    #[error]
    Error,

    #[token = "\\t"]
    EscTab,

    #[token = "\\r"]
    EscCR,

    #[token = "\\n"]
    EscNL,

    #[token = "\\'"]
    EscSQuote,

    #[token = "\\\""]
    EscDQuote,

    #[token = "\\\\"]
    EscBackslash,

    #[regex = "[^'\"\\\\]"]
    Char,
}

pub fn parse_stringish(s: &str) -> String {
    assert!(s.len() >= 2);
    let s = &s[1..s.len() - 1];

    let mut lexer = StringToken::lexer(s);
    let mut out = String::new();

    loop {
        match lexer.token {
            StringToken::End => break,
            StringToken::Error => unreachable!(),
            StringToken::EscTab => out.push('\t'),
            StringToken::EscCR => out.push('\r'),
            StringToken::EscNL => out.push('\n'),
            StringToken::EscSQuote => out.push('\''),
            StringToken::EscDQuote => out.push('"'),
            StringToken::EscBackslash => out.push('\\'),
            StringToken::Char => out.push_str(lexer.slice()),
        }
        lexer.advance();
    }
    out
}