1use crate::errors::{SemanticError, ValidateError};
2use crate::parser::sdc_grammar_trait as grammar;
3use crate::sdc::util::Validate;
4use std::fmt;
5
6pub mod argument;
7pub mod command;
8pub mod sdc_error;
9pub mod util;
10pub use argument::Argument;
11pub use command::*;
12
13#[derive(Clone, Debug, Default, PartialEq)]
15pub struct Sdc {
16 pub header: Vec<String>,
17 pub version: Option<SdcVersion>,
18 pub commands: Vec<Command>,
19}
20
21impl Sdc {
22 pub fn validate(&self, force_version: Option<SdcVersion>) -> Vec<ValidateError> {
23 let version = self.version.unwrap_or(SdcVersion::SDC2_1);
24 let version = force_version.unwrap_or(version);
25 let mut ret = vec![];
26 for command in &self.commands {
27 ret.append(&mut command.validate(version));
28 }
29 ret
30 }
31
32 pub fn normalize(&mut self) {
33 self.commands.sort()
34 }
35}
36
37impl fmt::Display for Sdc {
38 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39 for s in &self.header {
40 write!(f, "{}", s)?;
41 }
42 if let Some(version) = self.version {
43 writeln!(f, "{}", version)?;
44 }
45 for c in &self.commands {
46 writeln!(f, "{}", c)?;
47 }
48
49 Ok(())
50 }
51}
52
53impl TryFrom<&grammar::Source<'_>> for Sdc {
54 type Error = SemanticError;
55
56 fn try_from(value: &grammar::Source<'_>) -> Result<Self, SemanticError> {
57 let mut sdc = Sdc::default();
58 let mut is_header = true;
59 let mut is_first_command = true;
60 for source in &value.source_list {
61 match source.source_list_group.as_ref() {
62 grammar::SourceListGroup::CommandLine(x) => {
63 is_header = false;
64 let command = x.command_line.command.as_ref().try_into()?;
65
66 match command {
67 Command::Set(x) if x.variable_name.as_str() == "sdc_version" => {
68 if is_first_command {
69 if let Ok(sdc_version) = x.value.as_str().try_into() {
70 sdc.version = Some(sdc_version);
71 } else {
72 return Err(SemanticError::UnknownVersion(
73 x.location().clone(),
74 ));
75 }
76 } else {
77 return Err(SemanticError::SdcVersionPlacement(
78 x.location().clone(),
79 ));
80 }
81 }
82 _ => sdc.commands.push(command),
83 }
84
85 if is_first_command {
86 is_first_command = false;
87 }
88 }
89 grammar::SourceListGroup::TermComment(x) => {
90 if is_header {
91 sdc.header.push(x.term_comment.term_comment.text().into());
92 }
93 }
94 _ => (),
95 }
96 }
97 Ok(sdc)
98 }
99}
100
101#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
103pub enum SdcVersion {
104 SDC1_1 = 0,
105 SDC1_2 = 1,
106 SDC1_3 = 2,
107 SDC1_4 = 3,
108 SDC1_5 = 4,
109 SDC1_6 = 5,
110 SDC1_7 = 6,
111 SDC1_8 = 7,
112 SDC1_9 = 8,
113 SDC2_0 = 9,
114 SDC2_1 = 10,
115}
116
117impl SdcVersion {
118 pub fn within(&self, from: SdcVersion, to: SdcVersion) -> (bool, SdcVersion) {
119 (&from <= self && self <= &to, *self)
120 }
121
122 pub fn version_string(&self) -> &str {
123 match self {
124 SdcVersion::SDC1_1 => "1.1",
125 SdcVersion::SDC1_2 => "1.2",
126 SdcVersion::SDC1_3 => "1.3",
127 SdcVersion::SDC1_4 => "1.4",
128 SdcVersion::SDC1_5 => "1.5",
129 SdcVersion::SDC1_6 => "1.6",
130 SdcVersion::SDC1_7 => "1.7",
131 SdcVersion::SDC1_8 => "1.8",
132 SdcVersion::SDC1_9 => "1.9",
133 SdcVersion::SDC2_0 => "2.0",
134 SdcVersion::SDC2_1 => "2.1",
135 }
136 }
137}
138
139impl fmt::Display for SdcVersion {
140 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
141 match self {
142 SdcVersion::SDC1_1 => "set sdc_version 1.1".fmt(f),
143 SdcVersion::SDC1_2 => "set sdc_version 1.2".fmt(f),
144 SdcVersion::SDC1_3 => "set sdc_version 1.3".fmt(f),
145 SdcVersion::SDC1_4 => "set sdc_version 1.4".fmt(f),
146 SdcVersion::SDC1_5 => "set sdc_version 1.5".fmt(f),
147 SdcVersion::SDC1_6 => "set sdc_version 1.6".fmt(f),
148 SdcVersion::SDC1_7 => "set sdc_version 1.7".fmt(f),
149 SdcVersion::SDC1_8 => "set sdc_version 1.8".fmt(f),
150 SdcVersion::SDC1_9 => "set sdc_version 1.9".fmt(f),
151 SdcVersion::SDC2_0 => "set sdc_version 2.0".fmt(f),
152 SdcVersion::SDC2_1 => "set sdc_version 2.1".fmt(f),
153 }
154 }
155}
156
157impl TryFrom<&str> for SdcVersion {
158 type Error = ();
159
160 fn try_from(value: &str) -> Result<Self, Self::Error> {
161 match value {
162 "1.1" => Ok(SdcVersion::SDC1_1),
163 "1.2" => Ok(SdcVersion::SDC1_2),
164 "1.3" => Ok(SdcVersion::SDC1_3),
165 "1.4" => Ok(SdcVersion::SDC1_4),
166 "1.5" => Ok(SdcVersion::SDC1_5),
167 "1.6" => Ok(SdcVersion::SDC1_6),
168 "1.7" => Ok(SdcVersion::SDC1_7),
169 "1.8" => Ok(SdcVersion::SDC1_8),
170 "1.9" => Ok(SdcVersion::SDC1_9),
171 "2.0" => Ok(SdcVersion::SDC2_0),
172 "2.1" => Ok(SdcVersion::SDC2_1),
173 _ => Err(()),
174 }
175 }
176}