esl_compiler/builder/
behavior.rs1use crate::builder::design::{build_all_design_clauses, DesignClauses};
3use crate::builder::Stringency;
4use crate::context::Context;
5use crate::cursor::{Cursor, Error, Token};
6use crate::diagnostics::DiagnosticError;
7use crate::location::FileLocation;
8use crate::map::Map;
9use crate::parser::Rule;
10
11#[derive(Clone, Debug, PartialEq)]
14pub struct Behavior {
15 pub name: Token,
17 pub loc: FileLocation,
19 pub cases: Map<String, BehaviorCase>,
21 pub stringency: Stringency,
23}
24impl std::fmt::Display for Behavior {
25 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
26 write!(f, "{}", self.name)
27 }
28}
29
30#[derive(Clone, Debug, PartialEq)]
32pub struct BehaviorCase {
33 pub name: Token,
35 pub loc: FileLocation,
37 pub when: BehaviorWhen,
39 pub then: BehaviorThen,
41}
42impl std::fmt::Display for BehaviorCase {
43 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
44 write!(f, "{}", self.name)
45 }
46}
47
48#[derive(Clone, Debug, PartialEq)]
51pub enum BehaviorWhen {
52 Fallback,
53 Clauses(DesignClauses),
54}
55
56pub type BehaviorThen = DesignClauses;
58
59pub fn build_behavior_instantiation(
61 ctx: &mut Context,
62 behavior_requirement: Cursor,
63 stringency: &Stringency,
64) -> Result<Behavior, Error> {
65 let mut cursors = behavior_requirement.into_inner();
66 let name = cursors
67 .req_first(Rule::some_label)?
68 .into_inner()
69 .req_first(Rule::some_name)?
70 .into();
71 let mut behavior = Behavior {
72 name,
73 loc: cursors.as_location(),
74 stringency: stringency.clone(),
75 cases: Default::default(),
76 };
77
78 for behavior_case in cursors.get_all(Rule::behavior_case) {
79 let case = build_behavior_case(ctx, behavior_case)?;
80 if let Err(dupe) = behavior.cases.insert(case.to_string(), case) {
81 ctx.error(DiagnosticError::DuplicateDefinition, &dupe.loc);
82 }
83 }
84
85 Ok(behavior)
86}
87
88pub fn build_behavior_case(
90 ctx: &mut Context,
91 behavior_case: Cursor,
92) -> Result<BehaviorCase, Error> {
93 let mut cursors = behavior_case.into_inner();
94 let name = cursors
95 .req_first(Rule::some_label)?
96 .into_inner()
97 .req_first(Rule::some_name)?
98 .into();
99
100 let when = cursors
101 .req_first(Rule::behavior_when)
102 .and_then(|behavior_when| build_behavior_when(ctx, behavior_when))?;
103
104 let then = cursors
105 .req_first(Rule::behavior_then)
106 .and_then(|behavior_then| build_behavior_then(ctx, behavior_then))?;
107
108 Ok(BehaviorCase {
109 name,
110 loc: cursors.as_location(),
111 when,
112 then,
113 })
114}
115
116pub fn build_behavior_when(
118 ctx: &mut Context,
119 behavior_when: Cursor,
120) -> Result<BehaviorWhen, Error> {
121 let mut cursors = behavior_when.into_inner();
122 let first = { cursors.req_next()? };
124 if first.as_rule() == Rule::kw_section_behavior_fallback {
125 Ok(BehaviorWhen::Fallback)
126 } else {
127 let clauses = build_all_design_clauses(ctx, cursors.get_all(Rule::design_clause))?;
128 Ok(BehaviorWhen::Clauses(clauses))
129 }
130}
131
132pub fn build_behavior_then(
134 ctx: &mut Context,
135 behavior_then: Cursor,
136) -> Result<BehaviorThen, Error> {
137 build_all_design_clauses(ctx, behavior_then.into_inner().get_all(Rule::design_clause))
138}