use super::*;
#[test]
fn sizes() {
use std::mem::size_of;
eprintln!("SizeOf µSTR = {}", size_of::<CompactString>());
eprintln!("SizeOf [Byt] = {}", size_of::<Vec<Byt>>());
eprintln!("SizeOf ->Byt = {}", size_of::<Box<Byt>>());
eprintln!("SizeOf LEX.L = {}", size_of::<Literal>());
eprintln!("SizeOf LEX.S = {}", size_of::<Symbol>());
eprintln!("SizeOf AST = {}", size_of::<Expression>());
eprintln!("- SizeOf AST.I = {}", size_of::<Invoke>());
eprintln!("- SizeOf AST.P = {}", size_of::<Pipe>());
eprintln!("SizeOf [AST;1] = {}", size_of::<ExpressionVec>());
assert!(dbg!(size_of::<Invoke>() <= 128), "The size of an Invoke-struct should be below 128 bytes.");
}
const SRC_CONSTANTS: &str = include_str!("./tests/constants.ifn");
const SRC_DICTS: &str = include_str!("./tests/dicts.ifn");
const SRC_EXAMPLES: &str = include_str!("./tests/examples.ifn");
const SRC_FIELD: &str = include_str!("./tests/field.ifn");
const SRC_IFS: &str = include_str!("./tests/ifs.ifn");
const SRC_INDEX: &str = include_str!("./tests/index.ifn");
const SRC_LISTS: &str = include_str!("./tests/lists.ifn");
const SRC_NUMARS: &str = include_str!("./tests/numars.ifn");
const SRC_NUMBERS: &str = include_str!("./tests/numbers.ifn");
const SRC_OBJ_REFS: &str = include_str!("./tests/obj-refs.ifn");
const SRC_OPERATORS: &str = include_str!("./tests/operators.ifn");
const SRC_PARAMS: &str = include_str!("./tests/params.ifn");
const SRC_PIPES: &str = include_str!("./tests/pipes.ifn");
const SRC_RANGE: &str = include_str!("./tests/range.ifn");
const SRC_REFS: &str = include_str!("./tests/refs.ifn");
const SRC_STRINGS: &str = include_str!("./tests/strings.ifn");
const SRC_TRY: &str = include_str!("./tests/try.ifn");
const SRC: &[&str] = &[
SRC_CONSTANTS,
SRC_NUMBERS,
SRC_STRINGS,
SRC_REFS,
SRC_OBJ_REFS,
SRC_NUMARS,
SRC_LISTS,
SRC_DICTS,
SRC_OPERATORS,
SRC_FIELD,
SRC_INDEX,
SRC_RANGE,
SRC_TRY,
SRC_PARAMS,
SRC_PIPES,
SRC_IFS,
SRC_EXAMPLES,
];
#[test]
fn parse_constants() -> Result<(), ParseError> {
chks(SRC_CONSTANTS.lines())?;
Ok(())
}
#[test]
fn parse_numbers() -> Result<(), ParseError> {
chks(SRC_NUMBERS.lines())?;
Ok(())
}
#[test]
fn parse_strings() -> Result<(), ParseError> {
chks(SRC_STRINGS.lines())?;
Ok(())
}
#[test]
fn parse_references() -> Result<(), ParseError> {
chks(SRC_REFS.lines())?;
Ok(())
}
#[test]
fn parse_obj_references() -> Result<(), ParseError> {
chks(SRC_OBJ_REFS.lines())?;
Ok(())
}
#[test]
fn parse_numeric_arrays() -> Result<(), ParseError> {
chks(SRC_NUMARS.lines())?;
Ok(())
}
#[test]
fn parse_lists() -> Result<(), ParseError> {
chks(SRC_LISTS.lines())?;
Ok(())
}
#[test]
fn parse_dicts() -> Result<(), ParseError> {
chks(SRC_DICTS.lines())?;
Ok(())
}
#[test]
fn parse_operators() -> Result<(), ParseError> {
chks(SRC_OPERATORS.lines())?;
Ok(())
}
#[test]
fn parse_field() -> Result<(), ParseError> {
chks(SRC_FIELD.lines())?;
Ok(())
}
#[test]
fn parse_index() -> Result<(), ParseError> {
chks(SRC_INDEX.lines())?;
Ok(())
}
#[test]
fn parse_range() -> Result<(), ParseError> {
chks(SRC_RANGE.lines())?;
Ok(())
}
#[test]
fn parse_try() -> Result<(), ParseError> {
chks(SRC_TRY.lines())?;
Ok(())
}
#[test]
fn parse_params() -> Result<(), ParseError> {
chks(SRC_PARAMS.lines())?;
Ok(())
}
#[test]
fn parse_pipes() -> Result<(), ParseError> {
chks(SRC_PIPES.lines())?;
Ok(())
}
#[test]
fn parse_ifs() -> Result<(), ParseError> {
chks(SRC_IFS.lines())?;
Ok(())
}
#[test]
fn parse_examples() -> Result<(), ParseError> {
chks(SRC_EXAMPLES.lines())?;
Ok(())
}
#[test]
fn parse() -> Result<(), ParseError> {
for src in SRC {
chks(src.lines())?;
}
Ok(())
}
#[test]
fn parse_into_html() -> Result<(), ParseError> {
use std::fmt::*;
use ast::html::FormatHtml;
let mut out = String::new();
let styles = r#"<!DOCTYPE html>
<html>
<body>
<style>
* { font-family: monospace; white-space: pre; box-sizing: border-box }
body { background: #111; color: white }
body > .expression { padding: 0.5rem; }
div > code {font-size: 0.75rem; color: grey; padding: 3px}
span { display: inline-block; border-radius: 3px }
.expression { color: white; padding: 1px 3px }
.expression > .literal { background: rgba(255, 255, 255, 0.125); color: limegreen }
.expression > .pipe { background: rgba(64, 64, 255, 0.25); color: white; padding: 2px }
.expression > .invoke { background: rgba(127, 127, 127, 0.25); color: white; padding: 2px }
.literal.str { background: rgba(255, 255, 255, 0.125); color: palegreen }
.invoke > .name { color: orangered }
.invoke > .key { color: #e5191c }
.invoke > .key-val > .key { color: #e5191c }
.member { color: gold }
.separator, .operator { color: goldenrod }
.filter { color: gold }
.obj-idx ,
.obj-uid ,
.obj-key { color: skyblue !important }
.source > .expression,
.target > .expression,
.val > .expression { padding:0 }
</style>
"#;
writeln!(&mut out, "{styles}").unwrap();
for src in SRC {
writeln!(&mut out, "<hr>").unwrap();
for line in src.lines()
.filter(|l| !l.is_empty())
.filter(|l| !l.starts_with("//"))
{
let expr = chk(line)?;
writeln!(&mut out, "<div><code>{}</code><br>{}</div>", line, expr.to_html()).unwrap();
}
}
std::fs::write("parser-tests.html", out.as_bytes()).unwrap();
Ok(())
}
#[test]
#[should_panic]
fn posarg_after_nomarg() {
chk("test 1 a=2 3 b=4").expect("positional arguments cannot be written after nominal arguments");
}
fn chk(input: &str) -> Result<Expression, ParseError> {
let mut stream = tokenize(input);
let mut stream = groupenize(&mut stream, None);
let output = parse_expression(
&mut stream,
true,
true
);
let output = match output {
Ok(o) => o,
Err(err) => {
println!("Failed to parse: {input}");
println!("Because: {err}");
println!("Tokens: {:?}", groupenize(&mut tokenize(input), None).collect::<Vec<_>>());
if let Some(token) = stream.peek() {
println!("Next token: {token}");
}
return Err(err);
},
};
eprintln!("INPUT: {},\t PARSED: {:?}", input, output);
Ok(output)
}
fn chks(input: impl Iterator<Item=&'static str>) -> Result<(), ParseError> {
for line in input
.filter(|l| !l.is_empty())
.filter(|l| !l.starts_with("//"))
{
chk(line)?;
}
Ok(())
}