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(),
}