use alloc::{borrow::ToOwned, format, string::String, vec, vec::Vec};
use chumsky::Parser;
use core::fmt::{Debug, Write};
use miette::NamedSource;
use crate::{
ast::Node,
context::Context,
errors::Error,
grammar,
traits::{Decode, DecodePartial, Encode, EncodePartial},
};
pub fn parse(ctx: &mut Context, input: &str) -> Result<Vec<Node>, Error> {
grammar::document()
.parse_with_state(input, ctx)
.into_result()
.map_err(|errors| Error {
source_code: NamedSource::new(ctx.get::<&str>().unwrap(), input.to_owned()),
errors: errors.into_iter().map(Into::into).collect(),
})
}
pub fn decode<T>(file_name: &str, input: &str) -> Result<T, Error>
where
T: Decode,
{
let mut ctx = Context::new();
let nodes = parse(&mut ctx, input)?;
ctx.set::<String>(file_name.to_owned());
Decode::decode(&nodes[0], &mut ctx).map_err(|error| Error {
source_code: NamedSource::new(file_name, input.to_owned()),
errors: vec![error.into()],
})
}
pub fn decode_children<T>(file_name: &str, input: &str) -> Result<T, Error>
where
T: DecodePartial,
{
decode_with_context(file_name, input, |_| {})
}
pub fn decode_with_context<T, F>(file_name: &str, input: &str, set_ctx: F) -> Result<T, Error>
where
F: FnOnce(&mut Context),
T: DecodePartial,
{
let mut ctx = Context::new();
let nodes = parse(&mut ctx, input)?;
set_ctx(&mut ctx);
let mut output = <T as Default>::default();
for node in nodes {
output
.decode_partial(&node, &mut ctx)
.map_err(|error| Error {
source_code: NamedSource::new(file_name, input.to_owned()),
errors: vec![error.into()],
})?;
}
Ok(output)
}
pub fn print(_ctx: &mut Context, node: Node) -> Result<String, Error> {
let mut output = String::new();
write!(output, "{}", node).unwrap();
Ok(output)
}
pub fn encode<T>(file_name: &str, t: &T) -> Result<String, Error>
where
T: Encode + Debug,
{
let mut ctx = Context::new();
ctx.set::<String>(file_name.to_owned());
let node = t.encode(&mut ctx).map_err(|error| Error {
source_code: NamedSource::new(file_name, format!("{:?}", &t)),
errors: vec![error.into()],
})?;
print(&mut ctx, node)
}
pub fn encode_children<T>(file_name: &str, t: &T) -> Result<String, Error>
where
T: EncodePartial + Debug,
{
encode_with_context(file_name, t, |_| {})
}
pub fn encode_with_context<T, F>(file_name: &str, t: &T, set_ctx: F) -> Result<String, Error>
where
F: FnOnce(&mut Context),
T: EncodePartial + Debug,
{
let mut ctx = Context::new();
set_ctx(&mut ctx);
let mut node = Node::new("-");
t.encode_partial(&mut node, &mut ctx)
.map_err(|error| Error {
source_code: NamedSource::new(file_name, format!("{:?}", &t)),
errors: vec![error.into()],
})?;
print(&mut ctx, node)
}
#[test]
fn normal() {
let mut ctx = Context::new();
let nodes = parse(&mut ctx, r#"node "hello""#).unwrap();
assert_eq!(nodes.len(), 1);
assert_eq!(&*nodes[0].node_name, "node");
}