Skip to main content

wpl/ast/
code.rs

1use std::fs::File;
2use std::io::Read;
3use std::path::{Path, PathBuf};
4
5use crate::ast::WplPackage;
6
7use crate::parser::error::{WplCodeError, WplCodeReason, WplCodeResult, error_detail};
8use crate::parser::wpl_pkg::wpl_package;
9use crate::parser::wpl_rule::wpl_rule;
10use crate::winnow::Parser;
11use derive_getters::Getters;
12use orion_error::ErrorWith;
13use orion_error::UvsFrom;
14use orion_error::compat_traits::ErrorOweBase;
15use orion_error::conversion::ToStructError;
16use wp_primitives::comment::CommentParser;
17
18#[derive(Debug, Clone, Getters)]
19pub struct WplCode {
20    path: PathBuf,
21    code: String,
22}
23
24impl TryFrom<(PathBuf, String)> for WplCode {
25    type Error = WplCodeError;
26    fn try_from(v: (PathBuf, String)) -> WplCodeResult<Self> {
27        Self::build(v.0, v.1.as_str())
28    }
29}
30
31impl TryFrom<(PathBuf, &str)> for WplCode {
32    type Error = WplCodeError;
33    fn try_from(v: (PathBuf, &str)) -> WplCodeResult<Self> {
34        Self::build(v.0, v.1)
35    }
36}
37impl TryFrom<&str> for WplCode {
38    type Error = WplCodeError;
39    fn try_from(v: &str) -> WplCodeResult<Self> {
40        Self::build(PathBuf::new(), v)
41    }
42}
43
44impl WplCode {
45    pub fn build(path: PathBuf, code: &str) -> WplCodeResult<Self> {
46        let mut in_code = code;
47        let pure_code = CommentParser::ignore_comment(&mut in_code).map_err(|e| {
48            let msg = format!("comment proc error {} ", e);
49            WplCodeError::builder(WplCodeReason::Syntax)
50                .detail(msg)
51                .finish()
52        })?;
53
54        Ok(Self {
55            path,
56            code: pure_code.to_string(),
57        })
58    }
59    pub fn get_code(&self) -> &String {
60        &self.code
61    }
62    pub fn parse_pkg(&self) -> WplCodeResult<WplPackage> {
63        let package = wpl_package.parse(self.code.as_str()).map_err(|err| {
64            let msg = error_detail(err);
65            WplCodeError::builder(WplCodeReason::Syntax)
66                .detail(msg)
67                .finish()
68        })?;
69        Ok(package)
70    }
71    pub fn parse_rule(&self) -> WplCodeResult<WplPackage> {
72        let rule = wpl_rule.parse(self.code.as_str()).map_err(|err| {
73            let msg = error_detail(err);
74            WplCodeError::builder(WplCodeReason::Syntax)
75                .detail(msg)
76                .finish()
77        })?;
78        let mut target = WplPackage::default();
79        target.rules.push_back(rule);
80        Ok(target)
81    }
82    pub fn empty_ins() -> WplCodeResult<Self> {
83        WplCode::try_from((PathBuf::new(), ""))
84    }
85    pub fn is_empty(&self) -> bool {
86        self.code.is_empty()
87    }
88    pub fn load<P: AsRef<Path> + Clone>(wpl_file: P) -> WplCodeResult<Self> {
89        let mut buffer = Vec::with_capacity(10240);
90        let mut f = File::open(wpl_file.clone())
91            //.with_context(|| format!("conf file not found: {:?}", wpl_file))
92            .owe(WplCodeReason::from_conf())
93            .at(wpl_file.as_ref())?;
94        //.owe_conf::<WPLCodeError>()?;
95        f.read_to_end(&mut buffer).expect("read conf file error");
96        let file_data = String::from_utf8(buffer).expect("conf file is not utf8");
97        let code = WplCode::build(PathBuf::from(wpl_file.as_ref()), file_data.as_str())?;
98        Ok(code)
99    }
100
101    pub fn mix_load<P: AsRef<Path> + Clone>(
102        arg_file: Option<P>,
103        src_rule: Option<String>,
104    ) -> WplCodeResult<Self> {
105        if let Some(rule) = src_rule {
106            let code = format!("rule cli {{  {} }}", rule);
107            return WplCode::try_from((PathBuf::from("src"), code.as_str()));
108        }
109        if let Some(rule_file) = arg_file {
110            return WplCode::load(rule_file);
111        }
112        Err(WplCodeReason::from_not_found()
113            .to_err()
114            .with_detail("miss wpl file"))
115    }
116}