axon_parseast_parser 0.8.0

A library to parse the output of SkySpark's parseAst function.
Documentation
use chrono::{NaiveDate, NaiveTime};
use crate::{Lit, Month, Val, YearMonth, str_to_number};
use raystack_core::{Number, Ref, Symbol, TagName};
use std::collections::HashMap;
use std::str::FromStr;

grammar;

pub Val: Val = {
    Bool => Val::Lit(Lit::Bool(<>)),
    Date => Val::Lit(Lit::Date(<>)),
    Null => Val::Lit(Lit::Null),
    Num => Val::Lit(Lit::Num(<>)),
    Ref => Val::Lit(Lit::Ref(<>)),
    Str => Val::Lit(Lit::Str(<>)),
    Symbol => Val::Lit(Lit::Symbol(<>)),
    Time => Val::Lit(Lit::Time(<>)),
    Uri => Val::Lit(Lit::Uri(<>)),
    YearMonth => Val::Lit(Lit::YearMonth(<>)),
    "[" "]" => Val::List(vec![]),
    "[" <first_val:Val> <vals:("," <Val>)*> "]" => {
        let mut vals = vals;
        vals.insert(0, first_val);
        Val::List(vals)
    },
    "{" "}" => Val::Dict(HashMap::new()),
    "{" <first_entry:DictEntry> <entries:("," <DictEntry>)*> "}" => {
        let mut entries = entries;
        entries.insert(0, first_entry);
        Val::Dict(entries.into_iter().collect())
    }
}

pub YearMonth: YearMonth = {
    r"[1-9][0-9]{3}-[0-9]{2}" => {
        let parts = <>.split("-").collect::<Vec<_>>();
        let year = u32::from_str(parts[0]).unwrap();
        let month = u32::from_str(parts[1]).unwrap();
        let month = Month::from_int(month).unwrap();
        YearMonth::new(year, month)
    }
}

pub Time: NaiveTime = {
    r"[0-9]{2}:[0-9]{2}:[0-9]{2}(\.[0-9]+)?" => {
        let with_fractional_secs = NaiveTime::parse_from_str(<>, "%H:%M:%S%.f");
        match &with_fractional_secs {
            Ok(_) => with_fractional_secs.unwrap(),
            Err(_) => NaiveTime::parse_from_str(<>, "%H:%M:%S").unwrap(),
        }
    }
}

pub Date: NaiveDate = {
    r"[1-9][0-9]{3}-[0-9]{2}-[0-9]{2}" => {
        NaiveDate::parse_from_str(<>, "%Y-%m-%d").unwrap()
    }
}

pub Ref: Ref = {
    r"@[a-zA-Z0-9_:\.~-]+" => Ref::new(<>.to_owned()).unwrap(),
}

Null: () = {
    "null" => (),
}

Bool: bool = {
    "true" => true,
    "false" => false,
}

DictEntry: (TagName, Box<Val>) = {
    <tag_name:TagName> ":" "removeMarker()" => (tag_name, Box::new(Val::Lit(Lit::DictRemoveMarker))),
    <tag_name:TagName> ":" <val:Val> => (tag_name, Box::new(val)),
    <tag_name:TagName> => (tag_name, Box::new(Val::Lit(Lit::DictMarker))),
}

pub Str: String = {
    r#""([^\\"]|\\[n\$t"\\])*""# => {
        let s = <>;
        let len = s.len();
        s[1..len - 1]
            .replace(r#"\""#, r#"""#)
            .replace(r"\n", "\n")
            .replace(r"\t", "\t")
            .replace(r"\\", r#"\"#)
            .to_owned()
    },
}

pub Num: Number = {
    <number:r"-?\d+(\.\d+)?(E-?\d+)?[^0-9,\{\}\[\]]*"> => {
        str_to_number(number)
    },
}

pub Uri: String = {
    <r"`[^`]*`"> => {
        let s = <>;
        let len = s.len();
        s[1..len - 1].to_owned()
    },
}

pub TagName: TagName = {
    r"[a-z]([a-zA-Z0-9_])*" => TagName::new(<>.to_owned()).unwrap(),
}

pub Symbol: Symbol = {
    r"\^[a-z][a-zA-Z0-9:_-]*" => Symbol::new(<>.to_owned()).unwrap(),
}