1use std::error::Error;
4use std::fmt::{Display, Formatter};
5use lexigram_core::log::{BufLog, LogReader, LogStatus};
6
7#[derive(Debug)]
10pub enum BuildErrorSource {
11 RuleTreeSet,
12 Dfa,
13 DfaBuilder,
14 LexerGen,
15 Lexi,
16 ProdRuleSet,
17 ParserGen,
18 Gram,
19 Lexigram,
20 BuildGram,
21}
22
23#[derive(Debug)]
24pub struct BuildError {
25 log: BufLog,
26 source: BuildErrorSource,
27}
28
29impl BuildError {
30 pub fn new(log: BufLog, source: BuildErrorSource) -> Self {
31 BuildError { log, source }
32 }
33
34 pub fn get_log(self) -> BufLog {
35 self.log
36 }
37}
38
39impl Display for BuildError {
40 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
41 writeln!(f, "Errors have occurred in {:?}:\n{}", self.source, self.log.get_messages_str())
42 }
43}
44
45impl Error for BuildError {
46}
47
48pub trait HasBuildErrorSource {
49 const SOURCE: BuildErrorSource;
50
51 fn get_build_error_source() -> BuildErrorSource {
52 Self::SOURCE
53 }
54}
55
56pub trait BuildFrom<S>: Sized {
64 #[must_use]
66 fn build_from(source: S) -> Self;
67}
68
69pub trait BuildInto<T>: Sized {
70 #[must_use]
72 fn build_into(self) -> T;
73}
74
75impl<S, T> BuildInto<T> for S
76where
77 T: BuildFrom<S>,
78{
79 #[inline]
81 fn build_into(self) -> T { T::build_from(self) }
82}
83
84impl<S> BuildFrom<S> for S {
85 fn build_from(source: S) -> Self {
86 source
87 }
88}
89
90pub trait TryBuildFrom<T>: Sized {
93 type Error;
95
96 fn try_build_from(source: T) -> Result<Self, Self::Error>;
98}
99
100pub trait TryBuildInto<T>: Sized {
101 type Error;
103
104 fn try_build_into(self) -> Result<T, Self::Error>;
106}
107
108impl<S, T> TryBuildInto<T> for S
109where
110 T: TryBuildFrom<S>,
111{
112 type Error = T::Error;
113
114 #[inline]
115 fn try_build_into(self) -> Result<T, T::Error> { T::try_build_from(self) }
116}
117
118impl<S, T> TryBuildFrom<S> for T
119where
120 S: LogReader<Item = BufLog> + HasBuildErrorSource,
121 T: LogReader<Item = BufLog> + BuildFrom<S> + HasBuildErrorSource,
122{
123 type Error = BuildError;
124
125 fn try_build_from(source: S) -> Result<Self, Self::Error> {
126 const VERBOSE: bool = false;
127 if VERBOSE {
128 println!("try_build_from <{}> -> <{}>: source messages\n{}",
129 std::any::type_name::<S>(), std::any::type_name::<T>(),
130 source.get_log().get_messages_str());
131 }
132 if source.get_log().has_no_errors() {
133 let target = T::build_from(source);
134 if VERBOSE {
135 println!("try_build_from <{}> -> <{}>: target messages\n{}",
136 std::any::type_name::<S>(), std::any::type_name::<T>(),
137 target.get_log().get_messages_str());
138 }
139 if target.get_log().has_no_errors() {
140 Ok(target)
141 } else {
142 Err(BuildError::new(target.give_log(), S::get_build_error_source()))
143 }
144 } else {
145 Err(BuildError::new(source.give_log(), S::get_build_error_source()))
146 }
147 }
148}