miki 0.0.1

just a placeholder
Documentation
use crate::prelude::*;

use serde_json::Map;
use serde_json::Number;
use serde_json::Value;
use std::str::FromStr;

use crate::token::DelimiterKind;
use crate::token::IdentifierKind;
use crate::token::LiteralKind;
use crate::token::TokenKind;

pub fn bytes_to_str(_bytes: &[u8]) -> &str {
    unsafe { std::str::from_utf8_unchecked(_bytes) }
}

pub fn bytes_to_string(_bytes: &[u8]) -> String {
    unsafe { String::from_utf8_unchecked(_bytes.to_vec()) }
}

pub fn unescape_bytes(_bytes: &[u8]) -> Vec<u8> {
    let mut output = Vec::with_capacity(_bytes.len());
    let mut chars = _bytes.iter();

    while let Some(&c) = chars.next() {
        match c {
            b'\\' => {
                if let Some(&b) = chars.next() {
                    match b {
                        b'n' => output.push(b'\n'),
                        b'r' => output.push(b'\r'),
                        b't' => output.push(b'\t'),
                        b'"' => output.push(b),
                        b'\'' => output.push(b),
                        b'\\' => output.push(b),
                        b'`' => output.push(b),
                        _ => output.push(b),
                    }
                }
            }
            _ => output.push(c),
        }
    }

    output
}

#[derive(Default, Debug)]
pub struct Parser {
    index: usize,
}

impl Parser {
    fn index(&self) -> usize {
        self.index
    }

    fn next(&mut self) {
        self.index += 1;
    }

    pub fn new() -> Self {
        Parser { index: 0 }
    }

    pub fn parse(&mut self, tokens: &[TokenKind]) -> Result<Value> {
        match tokens.get(self.index()) {
            Some(token) => match token {
                TokenKind::Identifier(IdentifierKind::String(_)) => {
                    let mut values = Map::with_capacity(tokens.len());

                    while tokens.get(self.index()).is_some() {
                        let key = self.create_key(tokens)?;
                        self.next();
                        let value = self.create_value(tokens)?;
                        self.next();

                        values.insert(key, value);
                    }

                    Ok(Value::Object(values))
                }
                _ => {
                    let mut values = Vec::with_capacity(tokens.len());

                    while tokens.get(self.index()).is_some() {
                        let value = self.create_value(tokens)?;
                        self.next();

                        values.push(value);
                    }

                    Ok(Value::Array(values))
                }
            },
            None => Err(Error {
                description: "ran out of tokens".to_string(),
            }),
        }
    }

    pub fn create_list<'a>(&mut self, tokens: &'a [TokenKind<'a>]) -> Result<Value> {
        let mut values = Vec::new();

        while let Some(token) = tokens.get(self.index()) {
            match token {
                TokenKind::Delimiter(DelimiterKind::ArrayTerm(_)) => break,
                _ => {
                    let value = self.create_value(tokens)?;

                    self.next();

                    values.push(value);
                }
            }
        }

        Ok(Value::Array(values))
    }

    pub fn create_table<'a>(&mut self, tokens: &'a [TokenKind<'a>]) -> Result<Value> {
        let mut values = Map::new();

        while let Some(token) = tokens.get(self.index()) {
            match token {
                TokenKind::Delimiter(DelimiterKind::ObjectTerm(_)) => break,

                _ => {
                    let key = self.create_key(tokens)?;
                    self.next();

                    let value = self.create_value(tokens)?;
                    self.next();

                    values.insert(key, value);
                }
            }
        }

        Ok(Value::Object(values))
    }

    pub fn create_key<'a>(&mut self, tokens: &'a [TokenKind<'a>]) -> Result<String> {
        if let Some(token) = tokens.get(self.index()) {
            match token {
                TokenKind::Identifier(IdentifierKind::String(t)) => {
                    let result = bytes_to_string(t.bytes());
                    Ok(result)
                }

                token => Err(Error {
                    description: format!("invalid key '{:?}'", token),
                }),
            }
        } else {
            Err(Error {
                description: "expected a key".to_string(),
            })
        }
    }

    pub fn create_value<'a>(&mut self, tokens: &'a [TokenKind<'a>]) -> Result<Value> {
        if let Some(token) = tokens.get(self.index()) {
            match token {
                TokenKind::Literal(LiteralKind::True(_)) => Ok(Value::Bool(true)),

                TokenKind::Literal(LiteralKind::False(_)) => Ok(Value::Bool(false)),

                TokenKind::Literal(LiteralKind::String(t)) => {
                    let bytes_str = t.bytes();

                    if bytes_str.contains(&b'\\') {
                        let unescaped = unescape_bytes(bytes_str);
                        let result = bytes_to_string(&unescaped);
                        Ok(Value::String(result))
                    } else {
                        let result = bytes_to_string(bytes_str);
                        Ok(Value::String(result))
                    }
                }

                TokenKind::Literal(LiteralKind::Number(t)) => {
                    let num_str = bytes_to_str(t.bytes());

                    match Number::from_str(num_str) {
                        Ok(num) => Ok(Value::Number(num)),
                        Err(e) => Err(Error {
                            description: e.to_string(),
                        }),
                    }
                }

                TokenKind::Literal(LiteralKind::Null(_)) => Ok(Value::Null),

                TokenKind::Delimiter(DelimiterKind::ObjectPrec(_)) => {
                    self.next(); // skip opening "{"

                    match self.create_table(tokens) {
                        Ok(tbl) => Ok(tbl),
                        Err(e) => Err(Error {
                            description: format!(
                                "failed creating a table because of {}",
                                e.description
                            ),
                        }),
                    }
                }

                TokenKind::Delimiter(DelimiterKind::ArrayPrec(_)) => {
                    self.next(); // skip opening "["

                    match self.create_list(tokens) {
                        Ok(ls) => Ok(ls),
                        Err(e) => Err(Error {
                            description: format!(
                                "failed creating a list because of {}",
                                e.description
                            ),
                        }),
                    }
                }

                TokenKind::Delimiter(DelimiterKind::ArrayTerm(ctx)) => Err(Error {
                    description: format!(
                        "'{}' is not a valid value ({}:{})",
                        bytes_to_str(ctx.bytes()),
                        ctx.location().start().line(),
                        ctx.location().start().column()
                    ),
                }),

                TokenKind::Delimiter(DelimiterKind::ObjectTerm(ctx)) => Err(Error {
                    description: format!(
                        "'{}' is not a valid value ({}:{})",
                        bytes_to_str(ctx.bytes()),
                        ctx.location().start().line(),
                        ctx.location().start().column()
                    ),
                }),

                TokenKind::Identifier(IdentifierKind::String(ctx)) => Err(Error {
                    description: format!(
                        "'{}' is not a valid value ({}:{})",
                        bytes_to_str(ctx.bytes()),
                        ctx.location().start().line(),
                        ctx.location().start().column()
                    ),
                }),
            }
        } else {
            Err(Error {
                description: "ran out of tokens".to_string(),
            })
        }
    }
}