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 WplCodeError::from(WplCodeReason::Syntax(format!("comment proc error {} ", e)))
49 })?;
50
51 Ok(Self {
52 path,
53 code: pure_code.to_string(),
54 })
55 }
56 pub fn get_code(&self) -> &String {
57 &self.code
58 }
59 pub fn parse_pkg(&self) -> WplCodeResult<WplPackage> {
60 let package = wpl_package
61 .parse(self.code.as_str())
62 .map_err(|err| WplCodeError::from(WplCodeReason::Syntax(error_detail(err))))?;
63 Ok(package)
64 }
65 pub fn parse_rule(&self) -> WplCodeResult<WplPackage> {
66 let rule = wpl_rule
67 .parse(self.code.as_str())
68 .map_err(|err| WplCodeError::from(WplCodeReason::Syntax(error_detail(err))))?;
69 let mut target = WplPackage::default();
70 target.rules.push_back(rule);
71 Ok(target)
72 }
73 pub fn empty_ins() -> WplCodeResult<Self> {
74 WplCode::try_from((PathBuf::new(), ""))
75 }
76 pub fn is_empty(&self) -> bool {
77 self.code.is_empty()
78 }
79 pub fn load<P: AsRef<Path> + Clone>(wpl_file: P) -> WplCodeResult<Self> {
80 let mut buffer = Vec::with_capacity(10240);
81 let mut f = File::open(wpl_file.clone())
82 .owe(WplCodeReason::from_conf())
84 .at(wpl_file.as_ref())?;
85 f.read_to_end(&mut buffer).expect("read conf file error");
87 let file_data = String::from_utf8(buffer).expect("conf file is not utf8");
88 let code = WplCode::build(PathBuf::from(wpl_file.as_ref()), file_data.as_str())?;
89 Ok(code)
90 }
91
92 pub fn mix_load<P: AsRef<Path> + Clone>(
93 arg_file: Option<P>,
94 src_rule: Option<String>,
95 ) -> WplCodeResult<Self> {
96 if let Some(rule) = src_rule {
97 let code = format!("rule cli {{ {} }}", rule);
98 return WplCode::try_from((PathBuf::from("src"), code.as_str()));
99 }
100 if let Some(rule_file) = arg_file {
101 return WplCode::load(rule_file);
102 }
103 Err(WplCodeReason::from_not_found()
104 .to_err()
105 .with_detail("miss wpl file"))
106 }
107}