esl_compiler/builder/
design.rs

1//! Design rule builder module
2
3use crate::builder::auxiliary::{build_kw_aux_verb, AuxiliaryVerb};
4use crate::builder::subject::Subject;
5use crate::builder::value::{build_some_value, Value};
6use crate::builder::variable::build_some_variable;
7use crate::builder::Stringency;
8use crate::context::Context;
9use crate::cursor::{Cursor, Error, ExhaustedSnafu, Token, UnexpectedRuleSnafu};
10use crate::diagnostics::DiagnosticError;
11use crate::location::FileLocation;
12use crate::map::Map;
13use crate::parser::Rule;
14use crate::reference::{Reference, VariableTarget};
15
16/// Design requirement or constraint.
17#[derive(Clone, Debug, PartialEq)]
18pub struct Design {
19    /// Design's name or label.
20    pub name: Token,
21    /// Complete design's textual location.
22    pub loc: FileLocation,
23    /// Vector of OR concatenated main rules of this design requirement.
24    pub rules: DesignRules,
25    /// Mapping of AND concatenated subclauses of this design requirement.
26    pub subclauses: DesignClauses,
27    /// Whether this is a requirement or a constraint.
28    pub stringency: Stringency,
29}
30impl std::fmt::Display for Design {
31    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
32        write!(f, "{}", self.name)
33    }
34}
35
36/// Vector of OR concatenated unlabeled design rules.
37pub type DesignRules = Vec<DesignRule>;
38
39/// Mapping of AND concatenated labeled sets of design rules.
40pub type DesignClauses = Map<String, DesignClause>;
41
42/// Named design clause consisting of a name and a OR concatenated set of rules.
43#[derive(Clone, Debug, PartialEq)]
44pub struct DesignClause {
45    /// Design clause's name or label.
46    pub name: Token,
47    /// Complete clause's textual location.
48    pub loc: FileLocation,
49    /// Vector of OR concatenated rules of this clause.
50    pub rules: DesignRules,
51}
52impl std::fmt::Display for DesignClause {
53    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
54        write!(f, "{}", self.name)
55    }
56}
57
58/// Design rule.
59#[derive(Clone, Debug, PartialEq)]
60pub enum DesignRule {
61    /// Comparison design rule.
62    Comparison(Comparison),
63    /// An objective design rule.
64    Objective(Objective),
65}
66
67/// Comparison consisting of a subject, a comparison kind, and a value or reference.
68#[derive(Clone, Debug, PartialEq)]
69pub struct Comparison {
70    /// Complete comparison's textual location.
71    pub loc: FileLocation,
72    /// Comparison subject.
73    pub subject: Reference<Subject, VariableTarget>,
74    /// Auxiliary verb used in this comparison.
75    pub auxiliary: AuxiliaryVerb,
76    /// Operator of this comparison (i.e. larger than etcetera).
77    pub operator: ComparisonOperator,
78    /// COmparison reference.
79    pub reference: ComparisonReference,
80}
81
82/// Kinds of value comparison that are supported.
83#[derive(Clone, Debug, PartialEq)]
84pub enum ComparisonOperator {
85    /// Approximately equal to.
86    Approximately,
87    /// Exactly equal to.
88    EqualTo,
89    /// Not equal to.
90    NotEqualTo,
91    /// Inclusive lower bound comparison.
92    AtLeast,
93    /// Exclusive lower bound comparison.
94    GreaterThan,
95    /// Inclusive upper bound comparison.
96    AtMost,
97    /// Exclusive upper bound comparison.
98    SmallerThan,
99}
100
101/// Comparison reference.
102#[derive(Clone, Debug, PartialEq)]
103pub enum ComparisonReference {
104    /// Value comparison reference.
105    Value(Value),
106    /// Variable comparison reference.
107    Variable(Reference<Subject, VariableTarget>),
108}
109
110/// Design rule objective.
111#[derive(Clone, Debug, PartialEq)]
112pub struct Objective {
113    /// Complete textual location of this objective rule.
114    pub loc: FileLocation,
115    /// Subject of this objective.
116    pub subject: Reference<Subject, VariableTarget>,
117    /// Auxiliary verb used in this objective.
118    pub auxiliary: AuxiliaryVerb,
119    /// Objective operator (i.e. maximized).
120    pub operator: ObjectiveOperator,
121}
122
123/// Design rule objective operator.
124#[derive(Clone, Debug, PartialEq)]
125pub enum ObjectiveOperator {
126    /// Subject should be minimized.
127    Minimized,
128    /// Subject should be maximized.
129    Maximized,
130}
131
132/// Build a design requirement or constraint.
133pub fn build_design_instantiation(
134    ctx: &mut Context,
135    design_instantiation: Cursor,
136    stringency: Stringency,
137) -> Result<Design, Error> {
138    let mut cs = design_instantiation.into_inner();
139    let loc = cs.as_location();
140
141    let clause = build_design_clause(ctx, cs.req_first(Rule::design_clause)?)?;
142    let subclauses = match cs.find_first(Rule::with_subclauses) {
143        Some(with_subclauses) => build_all_design_clauses(
144            ctx,
145            with_subclauses.into_inner().get_all(Rule::design_clause),
146        )?,
147        None => Default::default(),
148    };
149
150    Ok(Design {
151        name: clause.name,
152        loc,
153        rules: clause.rules,
154        subclauses,
155        stringency,
156    })
157}
158
159/// Build a single design rule clause.
160pub fn build_design_clause(
161    ctx: &mut Context,
162    design_clause: Cursor,
163) -> Result<DesignClause, Error> {
164    let loc = design_clause.as_location();
165    let mut cs = design_clause.into_inner();
166    let name = cs
167        .req_first(Rule::some_label)?
168        .into_inner()
169        .req_first(Rule::some_name)?
170        .into();
171    let rules = cs
172        .get_all(Rule::design_rule)
173        .map(|design_rule| build_design_rule(ctx, design_rule))
174        .collect::<Result<DesignRules, Error>>()?;
175    Ok(DesignClause { name, loc, rules })
176}
177
178/// Build a with subclauses section.
179pub fn build_with_subclauses(
180    ctx: &mut Context,
181    with_subclauses: Cursor,
182) -> Result<DesignClauses, Error> {
183    build_all_design_clauses(
184        ctx,
185        with_subclauses.into_inner().get_all(Rule::design_clause),
186    )
187}
188
189/// Build any "design_clause" rules that are to be found in this cursor.
190pub fn build_all_design_clauses<'a, T: Iterator<Item = Cursor<'a>>>(
191    ctx: &mut Context,
192    design_clauses: T,
193) -> Result<DesignClauses, Error> {
194    let mut clauses: DesignClauses = Default::default();
195    for c in design_clauses {
196        let clause = build_design_clause(ctx, c)?;
197        if let Err(dupe) = clauses.insert(clause.to_string(), clause) {
198            ctx.error(DiagnosticError::DuplicateDefinition, &dupe.loc);
199        }
200    }
201    Ok(clauses)
202}
203
204/// Build a single design rule.
205pub fn build_design_rule(ctx: &mut Context, design_rule: Cursor) -> Result<DesignRule, Error> {
206    let mut cs = design_rule.into_inner();
207    let subject = cs
208        .req_first(Rule::some_variable)
209        .and_then(|some_variable| build_some_variable(ctx, some_variable))?;
210    let auxiliary = cs
211        .req_first(Rule::design_rule_aux_verb)
212        .and_then(|design_rule_aux_verb| build_design_rule_aux_verb(ctx, design_rule_aux_verb))?;
213
214    let next = cs.req_next()?;
215    let loc = next.as_location();
216    let design_rule: DesignRule = match next.as_rule() {
217        Rule::design_rule_objective => {
218            let operator = build_design_rule_objective(ctx, next)?;
219            DesignRule::Objective(Objective {
220                loc,
221                subject,
222                auxiliary,
223                operator,
224            })
225        }
226        Rule::design_rule_comparison => {
227            let mut cs = next.into_inner();
228            let operator =
229                cs.req_first(Rule::design_rule_operator)
230                    .and_then(|design_rule_operator| {
231                        build_design_rule_operator(ctx, design_rule_operator)
232                    })?;
233            let reference = cs.req_next().and_then(|p| match p.as_rule() {
234                Rule::some_value => build_some_value(ctx, p).map(ComparisonReference::Value),
235                Rule::some_variable => {
236                    build_some_variable(ctx, p).map(ComparisonReference::Variable)
237                }
238                _ => UnexpectedRuleSnafu::from(p).fail()?,
239            })?;
240
241            DesignRule::Comparison(Comparison {
242                loc,
243                subject,
244                auxiliary,
245                operator,
246                reference,
247            })
248        }
249        _ => UnexpectedRuleSnafu::from(next).fail()?,
250    };
251    Ok(design_rule)
252}
253
254/// Build a design rule auxiliary verb.
255pub fn build_design_rule_aux_verb(
256    ctx: &mut Context,
257    design_rule_aux_verb: Cursor,
258) -> Result<AuxiliaryVerb, Error> {
259    let first = design_rule_aux_verb.into_inner().req_next()?;
260    match first.as_rule() {
261        Rule::kw_aux_is => Ok(AuxiliaryVerb::Is),
262        Rule::kw_aux_verb => Ok(build_kw_aux_verb(ctx, first)?),
263        _ => UnexpectedRuleSnafu::from(first).fail()?,
264    }
265}
266
267/// Build a design rule objective.
268pub fn build_design_rule_objective(
269    ctx: &mut Context,
270    design_rule_objective: Cursor,
271) -> Result<ObjectiveOperator, Error> {
272    let c = design_rule_objective.into_inner().req_next()?;
273    match c.as_rule() {
274        Rule::kw_comparison_minimized => Ok(ObjectiveOperator::Minimized),
275        Rule::kw_comparison_maximized => Ok(ObjectiveOperator::Maximized),
276        _ => UnexpectedRuleSnafu::from(c).fail()?,
277    }
278}
279
280/// Build a design rule operator.
281pub fn build_design_rule_operator(
282    ctx: &mut Context,
283    design_rule_operator: Cursor,
284) -> Result<ComparisonOperator, Error> {
285    let loc = design_rule_operator.as_location();
286    for c in design_rule_operator.into_inner() {
287        match c.as_rule() {
288            Rule::kw_comparison_at => continue,
289            Rule::kw_comparison_to => continue,
290            Rule::kw_comparison_approximately => return Ok(ComparisonOperator::Approximately),
291            Rule::kw_comparison_greater => return Ok(ComparisonOperator::GreaterThan),
292            Rule::kw_comparison_smaller => return Ok(ComparisonOperator::SmallerThan),
293            Rule::kw_comparison_not => return Ok(ComparisonOperator::NotEqualTo),
294            Rule::kw_comparison_equal => return Ok(ComparisonOperator::EqualTo),
295            Rule::kw_comparison_least => return Ok(ComparisonOperator::AtLeast),
296            Rule::kw_comparison_most => return Ok(ComparisonOperator::AtMost),
297            _ => UnexpectedRuleSnafu::from(c).fail()?,
298        };
299    }
300    ExhaustedSnafu { loc }.fail()
301}