#![feature(extract_if)]
#![feature(test)]
pub mod parser;
pub mod token;
#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error("Error: {0}")]
Error(String),
#[error("Invalid String: {0}")]
InvalidString(String),
#[error("Tokenize: {0}")]
Tokenize(String),
#[error("Unexpected token")]
UnexpectedToken,
#[error("Unexpected length")]
UnexpectedLength,
#[error("Unexpected value")]
UnexpectedValue,
#[error("Unsupported")]
Unsupported,
#[error("Parse: {0}")]
Parser(String),
#[error("serde_json")]
Serde(#[from] serde_json::Error),
#[error("IO")]
Io(#[from] std::io::Error),
#[error("Utf8")]
Utf8(#[from] std::str::Utf8Error),
}
type Result<T> = std::result::Result<T, Error>;
macro_rules! errloc {
() => {{
let line = line!();
let file = file!();
format!("{file}:{line}")
}};
}
pub(crate) use errloc;
macro_rules! parsererror {
($msg:expr) => {{
let errloc = crate::errloc!();
let err = format!("{errloc}: error: {}", $msg);
log::error!("{err}");
Err(crate::Error::Parser(err))
}};
}
pub(crate) use parsererror;
macro_rules! generror {
($msg:expr, $log:ident) => {{
let errloc = crate::errloc!();
let err = format!("{errloc}: error: {}", $msg);
log::$log!("{err}");
Err(crate::Error::Error(err))
}};
($msg:expr) => {
generror!($msg, error)
};
}
pub(crate) use generror;
macro_rules! verify {
($expr:expr, $error:ident) => {
if (!($expr)) {
let errloc = crate::errloc!();
log::error!("{errloc}: expression failed: {}", stringify!($expr));
return Err(crate::Error::$error);
}
};
}
pub(crate) use verify;
macro_rules! consume {
($tokens:expr, $check:expr) => {{
if $tokens.is_empty() {
let errloc = crate::errloc!();
let msg = format!("{errloc}: expected {:?}, but tokens is empty", $check);
log::error!("{msg}");
return Err(crate::Error::Parser(msg));
}
let t = $tokens.remove(0);
if t != $check {
let errloc = crate::errloc!();
let msg = format!("{errloc}: expected {:?}, but got token {:?}", $check, t);
log::error!("{msg}");
return Err(crate::Error::Parser(msg));
}
t
}};
($tokens:expr) => {{
if $tokens.is_empty() {
let errloc = crate::errloc!();
let msg = format!("{errloc}: expected new value but tokens is empty");
log::error!("{msg}");
return Err(crate::Error::Parser(msg));
}
$tokens.remove(0)
}};
}
pub(crate) use consume;
macro_rules! check_empty {
($tokens:expr) => {
if !$tokens.is_empty() {
let errloc = crate::errloc!();
let msg = format!("{errloc}: expected tokens to be empty, left: {:?}", $tokens);
log::error!("{msg}");
return Err(crate::Error::Parser(msg));
}
};
}
pub(crate) use check_empty;
macro_rules! gen_get_ident {
($name:ident) => {
pub fn identifier(&self) -> &Identifier {
&self.$name
}
};
}
pub(crate) use gen_get_ident;
macro_rules! gen_get {
($funcname:ident, $field:ident, $val:ty) => {
pub fn $funcname(&self) -> &$val {
&self.$field
}
};
($field:ident, $val:ty) => {
gen_get! { $field, $field, $val }
};
}
pub(crate) use gen_get;
macro_rules! gen_get_mut {
($funcname:ident, $field:ident, $val:ty) => {
pub fn $funcname(&mut self) -> &mut $val {
&mut self.$field
}
};
($field:ident, $val:ty) => {
gen_get_mut! { $field, $field, $val }
};
}
pub(crate) use gen_get_mut;
macro_rules! gen_get_iter {
($funcname:ident, $field:ident, $val:ty) => {
pub fn $funcname(&self) -> std::slice::Iter<'_, $val> {
self.$field.iter()
}
};
($field:ident, $val:ty) => {
gen_get_iter! { $field, $field, $val }
};
}
pub(crate) use gen_get_iter;
macro_rules! gen_find_ident {
($field:ident) => {
pub fn find_ident<'a>(entries: &'a [Self], ident: &Identifier) -> Option<&'a Self> {
for val in entries.iter() {
if val.$field == *ident {
return Some(val);
}
}
None
}
};
($field:ident, $val:ty) => {
gen_get_iter! { $field, $field, $val }
};
}
pub(crate) use gen_find_ident;
macro_rules! gen_get_ident_matches {
($name:ident) => {
pub fn ident_matches(&self, name: &str) -> bool {
self.$name.name == name
}
};
}
pub(crate) use gen_get_ident_matches;
macro_rules! gen_find_by_ident {
($name:ident, $field:ident, $val:ty) => {
pub fn $name(&self, ident: &Identifier) -> Option<&$val> {
self.$field.iter().find(|&s| s.identifier() == ident)
}
};
}
pub(crate) use gen_find_by_ident;
macro_rules! gen_find_by_name {
($name:ident, $field:ident, $val:ty) => {
pub fn $name<I: Into<Identifier>>(&self, name: I) -> Option<&$val> {
let ident: Identifier = name.into();
self.$field.iter().find(|&s| s.identifier() == &ident)
}
};
}
pub(crate) use gen_find_by_name;
#[cfg(test)]
#[ctor::ctor]
fn global_test_setup() {
env_logger::init();
}