dlexer 0.1.7

A high-performance, functional parser combinator library for Rust
Documentation
#![allow(dead_code)]

use crate::{
    lex::{number, symbol, token},
    map,
    parsec::{BasicParser, With, any, char, extra::build_ident, rec},
};

#[derive(Debug, Clone, PartialEq)]
pub enum JsonValue {
    Null,
    String(String),
    Number(f64),
    Boolean(bool),
    Array(Vec<JsonValue>),
    Object(Vec<(String, JsonValue)>),
}

pub fn json_value() -> With<BasicParser, JsonValue> {
    let esc = char('\\')
        >> map!(
            char('"') => '"',
            char('n') => '\n',
            char('t') => '\t',
            char('\\') => '\\',
            char('\"') => '\"'
        );
    let string = token(
        (esc | any().not('"'))
            .many()
            .between(char('"'), char('"'))
            .collect()
            .expected("string"),
    );

    let number = number().expected("number") & JsonValue::Number;

    let boolean = map!(
        symbol("true") => true,
        symbol("false") => false
    )
    .expected("boolean")
        & JsonValue::Boolean;

    let null = symbol("null").expected("null") & |_| JsonValue::Null;

    let array = rec(json_value).sep(char(',')).between(char('['), char(']')) & JsonValue::Array;

    let key = string.clone() | build_ident(["json", "null", "true", "false"]);
    let object = (key.with(char(':')) + rec(json_value))
        .sep(char(','))
        .between(char('{'), char('}'))
        & JsonValue::Object;

    let string = string & JsonValue::String;

    object | array | string | number | boolean | null
}

#[cfg(test)]
mod tests {
    use crate::lex::{BlockSkipper, CharSkipper, LineSkipper};

    use super::*;
    #[test]
    fn test_json_parser() {
        let parser = json_value();
        let input = r#"{
            "name": "John", // This is a comment
            "age": /* This is a block comment */ 30,
            "is_student": false,
            "courses": ["Math", "Science"],
            "address": {
                "street": "123 Main St",
                "city": "Anytown"
            },
            "grades": [85.5, 90.0, 78.5],
            "graduated": null
        }"#;
        let result = parser.parse(
            input,
            [
                CharSkipper(['\n', '\t', ' ']).into(),
                LineSkipper("//").into(),
                BlockSkipper("/*", "*/").into(),
            ],
        );
        match result {
            Ok(value) => println!("Parsed JSON value: {:#?}", value),
            Err(e) => println!("Error parsing JSON: {}", e),
        }
    }
}