wp-lang 0.2.1

WPL language crate with AST, parser, evaluator, builtins, and generators.
Documentation
use super::super::prelude::*;
use std::collections::HashMap;
use wp_model_core::model::FNameStr;

use crate::eval::runtime::field::FieldEvalUnit;
use crate::eval::value::parse_def::*;
use crate::eval::value::parser::physical::foundation::gen_chars;
use crate::generator::{FieldGenConf, GenScopeEnum};
use crate::generator::{GenChannel, ParserValue};
use crate::parser::error::WplCodeResult;
use crate::parser::utils::{quot_r_str, quot_str, take_to_end, window_path};
use rand::RngExt;
use winnow::ascii::{digit1, multispace0};
use winnow::combinator::{alt, preceded};
use wp_model_core::model::{DataField, Value};
use wp_model_core::model::{DataType, DigitValue};
use wp_primitives::Parser;
use wp_primitives::WResult as ModalResult;

#[derive(Default)]
pub struct CharsP {}

impl ParserValue<DigitValue> for CharsP {
    fn parse_value<'a>(data: &mut &str) -> ModalResult<DigitValue> {
        preceded(multispace0, digit1.try_map(str::parse::<DigitValue>)).parse_next(data)
    }
}

impl PatternParser for CharsP {
    fn pattern_parse<'a>(
        &self,
        _e_id: u64,
        _fpu: &FieldEvalUnit,
        _ups_sep: &WplSep,
        data: &mut &str,
        name: FNameStr,
        out: &mut Vec<DataField>,
    ) -> ModalResult<()> {
        multispace0.parse_next(data)?;
        let buffer = alt((quot_r_str, quot_str, window_path, take_to_end)).parse_next(data)?;
        out.push(DataField::new_opt(
            DataType::Chars,
            Some(name),
            //Value::Chars(buffer.trim().to_string()),
            Value::Chars(buffer.trim().into()),
        ));
        Ok(())
    }

    fn patten_gen(
        &self,
        gnc: &mut GenChannel,
        f_conf: &WplField,
        g_conf: Option<&FieldGenConf>,
    ) -> WplCodeResult<DataField> {
        let name = f_conf.safe_name();
        let len = f_conf.length.unwrap_or(20);
        let mut dat = gen_chars(gnc, len, false);
        if let Some(conf) = g_conf {
            match &conf.scope {
                Some(GenScopeEnum::Digit(digit)) => {
                    dat = gnc.rng.random_range(digit.beg..digit.end).to_string();
                }
                Some(GenScopeEnum::Chars(values)) => {
                    let val = gnc.rng.random_range(0..values.len());
                    dat = values[val].to_string();
                }
                _ => {}
            }

            if let Some(fmt) = &conf.gen_fmt {
                let mut vars = HashMap::new();
                vars.insert("val".to_string(), dat.clone());
                match strfmt::strfmt(fmt, &vars) {
                    Ok(dat) => {
                        return Ok(DataField::from_chars(name.to_string(), dat));
                    }
                    Err(e) => {
                        error!("gen fmt error: {}", e);
                    }
                }
            }
        }
        Ok(DataField::from_chars(name.to_string(), dat))
    }
}

#[cfg(test)]
mod tests {
    use crate::ast::WplField;
    use crate::eval::value::test_utils::ParserTUnit;
    use crate::parser::error::WplCodeResult;
    use orion_error::testcase::TestAssert;

    use super::*;

    #[test]
    fn test_char1() {
        let mut data = "aGVsbG8=";
        let res = ParserTUnit::new(CharsP::default(), WplField::try_parse("chars").assert())
            .verify_parse_suc(&mut data)
            .assert();
        assert_eq!(res[0], DataField::from_chars("chars", "aGVsbG8="));

        let mut data = "aGVsbG8= ";
        let res = ParserTUnit::new(CharsP::default(), WplField::try_parse("chars").assert())
            .verify_parse_suc(&mut data)
            .assert();
        assert_eq!(res[0], DataField::from_chars("chars", "aGVsbG8="));

        let mut data = "[abc,efg,hij]";
        let conf = WplField::try_parse("chars<[,]>").assert();

        let res = ParserTUnit::new(CharsP::default(), conf)
            .verify_parse_suc(&mut data)
            .assert();
        assert_eq!(res[0], DataField::from_chars("chars", "abc,efg,hij"));
    }

    #[test]
    fn test_char4() {
        let mut data = r#""abc efg hij""#;
        let conf = WplField::try_parse(r#"chars:name<",">"#).assert();

        let res = ParserTUnit::new(CharsP::default(), conf)
            .verify_parse_suc(&mut data)
            .assert();
        assert_eq!(res[0], DataField::from_chars("name", "abc efg hij"));
    }

    #[test]
    fn test_char3() {
        let mut data = "{abc efg hij}  xxx yyy";
        let conf = WplField::try_parse("chars<{,}>").assert();
        let res = ParserTUnit::new(CharsP::default(), conf)
            .verify_parse_suc(&mut data)
            .assert();
        assert_eq!(res[0], DataField::from_chars("chars", "abc efg hij"));
    }

    #[test]
    fn test_from_case() -> WplCodeResult<()> {
        let mut data = "  -[UMSyncService fetchPersona:forPid:completionHandler:]_block_invoke:";
        let conf = WplField::try_parse("chars<-[,]>").assert();
        let res = ParserTUnit::new(CharsP::default(), conf)
            .verify_parse_suc(&mut data)
            .assert();
        assert_eq!(
            res[0],
            DataField::from_chars(
                "chars",
                "UMSyncService fetchPersona:forPid:completionHandler:",
            )
        );
        assert_eq!(data, "_block_invoke:");
        Ok(())
    }

    #[test]
    fn test_gen() -> WplCodeResult<()> {
        let conf = WplField::try_parse("chars<[,]>").assert();

        ParserTUnit::new(CharsP::default(), conf).verify_gen_parse_suc();

        let conf = WplField::try_parse("chars").assert();
        ParserTUnit::new(CharsP::default(), conf).verify_gen_parse_suc();

        let conf = WplField::try_parse("chars\\,").assert();
        ParserTUnit::new(CharsP::default(), conf).verify_gen_parse_suc();
        Ok(())
    }
}