esl_compiler/builder/
def_component.rs

1//! Component builder module
2use crate::builder::behavior::{build_behavior_instantiation, Behavior};
3use crate::builder::component::{build_component_instantiation, Component};
4use crate::builder::design::{build_design_instantiation, Design};
5use crate::builder::goal::{build_goal_instantiation, Goal};
6use crate::builder::need::{build_need_instantiation, Need};
7use crate::builder::relation::{build_relation_instantiation, Relation};
8use crate::builder::transformation::{build_transformation_instantiation, Transformation};
9use crate::builder::variable::{
10    build_parameter_declaration, build_variable_declaration, build_variable_group_declaration,
11    Variable, VariableGroup,
12};
13use crate::builder::Stringency;
14use crate::context::Context;
15use crate::cursor::{Cursor, Error, ExhaustedSnafu, Token, UnexpectedRuleSnafu};
16use crate::diagnostics::{DiagnosticError, DiagnosticWarning};
17use crate::location::FileLocation;
18use crate::map::Map;
19use crate::parser::Rule;
20
21/// Component definition.
22#[derive(Clone, Debug, Default, PartialEq)]
23pub struct ComponentDefinition {
24    /// Name of this component definition.
25    pub name: Token,
26    /// Textual location of this component definition.
27    pub loc: FileLocation,
28    /// Map of parameter variables.
29    pub parameters: Map<String, Variable>,
30    /// Map of internal variables.
31    pub variables: Map<String, Variable>,
32    /// Map of internal variable groupings.
33    pub groups: Map<String, VariableGroup>,
34    /// Map of instantiated relations.
35    pub relations: Map<String, Relation>,
36    /// Map of instantiated components.
37    pub components: Map<String, Component>,
38    /// Map of design requirements and constraints.
39    pub designs: Map<String, Design>,
40    /// Map of goal requirements and constraints.
41    pub goals: Map<String, Goal>,
42    /// Map of transformation requirements and constraints.
43    pub transformations: Map<String, Transformation>,
44    /// Map of behavior requirements and constraints.
45    pub behaviors: Map<String, Behavior>,
46    /// Map of needs.
47    pub needs: Map<String, Need>,
48}
49impl std::fmt::Display for ComponentDefinition {
50    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
51        write!(f, "{}", self.name)
52    }
53}
54
55/// Build a component definition from a cursor over the input.
56pub fn build_component_definition(
57    ctx: &mut Context,
58    component_definition: Cursor,
59) -> Result<(), Error> {
60    let mut cs = component_definition.into_inner();
61    let header = cs.req_first(Rule::component_definition_header)?;
62    let name = build_component_definition_header(ctx, header)?;
63
64    let mut def = ComponentDefinition {
65        name,
66        loc: cs.as_location(),
67        ..Default::default()
68    };
69
70    if let Some(component_definition_contents) = cs.find_first(Rule::component_definition_contents)
71    {
72        build_component_definition_contents(ctx, &mut def, component_definition_contents)?;
73    } else {
74        ctx.warn(DiagnosticWarning::ImplicitEmpty, &cs.as_location());
75    }
76
77    if let Err(dupe) = ctx.specification.components.insert(def.to_string(), def) {
78        ctx.error(DiagnosticError::DuplicateDefinition, &dupe.loc);
79    }
80
81    Ok(())
82}
83
84/// Build the component definition's header from a cursor.
85pub fn build_component_definition_header(
86    ctx: &mut Context,
87    component_definition_header: Cursor,
88) -> Result<Token, Error> {
89    let loc = component_definition_header.as_location();
90    for cursor in component_definition_header.into_inner() {
91        match cursor.as_rule() {
92            Rule::kw_definition_world => return Ok(cursor.into()),
93            Rule::some_name => return Ok(cursor.into()),
94            _ => (),
95        }
96    }
97    ExhaustedSnafu { loc }.fail()
98}
99
100/// Build a component definition's contents.
101pub fn build_component_definition_contents(
102    ctx: &mut Context,
103    def: &mut ComponentDefinition,
104    component_definition_contents: Cursor,
105) -> Result<(), Error> {
106    for c in component_definition_contents.into_inner() {
107        match c.as_rule() {
108            Rule::kw_control_empty => Ok(()),
109            Rule::parameters_section => build_parameters_section(ctx, &mut def.parameters, c),
110            Rule::variables_section => build_variables_section(ctx, &mut def.variables, c),
111            Rule::variable_groups_section => build_variable_groups_section(ctx, &mut def.groups, c),
112            Rule::relations_section => build_relations_section(ctx, &mut def.relations, c),
113            Rule::components_section => build_components_section(ctx, &mut def.components, c),
114            Rule::designs_section => build_designs_section(ctx, &mut def.designs, c),
115            Rule::goals_section => build_goals_section(ctx, &mut def.goals, c),
116            Rule::transformations_section => {
117                build_transformations_section(ctx, &mut def.transformations, c)
118            }
119            Rule::behaviors_section => build_behaviors_section(ctx, &mut def.behaviors, c),
120            Rule::needs_section => build_needs_section(ctx, &mut def.needs, c),
121            Rule::comments_section => Ok(()),
122            _ => UnexpectedRuleSnafu::from(c).fail(),
123        }?;
124    }
125    Ok(())
126}
127
128/// Build a parameters section from a cursor and add it to the mapping.
129pub fn build_parameters_section(
130    ctx: &mut Context,
131    parameters: &mut Map<String, Variable>,
132    parameters_section: Cursor,
133) -> Result<(), Error> {
134    let cs = parameters_section.into_inner();
135    for parameter_declaration in cs.get_all(Rule::parameter_declaration) {
136        for parameter in build_parameter_declaration(ctx, parameter_declaration)? {
137            if let Err(dupe) = parameters.insert(parameter.to_string(), parameter) {
138                ctx.error(DiagnosticError::DuplicateDefinition, &dupe.loc);
139            }
140        }
141    }
142    Ok(())
143}
144
145/// Build a variables section from a cursor and add it to the mapping.
146pub fn build_variables_section(
147    ctx: &mut Context,
148    variables: &mut Map<String, Variable>,
149    variables_section: Cursor,
150) -> Result<(), Error> {
151    let cs = variables_section.into_inner();
152    for variable_declaration in cs.get_all(Rule::variable_declaration) {
153        for variable in build_variable_declaration(ctx, variable_declaration, false)? {
154            if let Err(dupe) = variables.insert(variable.to_string(), variable) {
155                ctx.error(DiagnosticError::DuplicateDefinition, &dupe.loc);
156            }
157        }
158    }
159    Ok(())
160}
161
162/// Build a variable groups section and add it to the mapping.
163pub fn build_variable_groups_section(
164    ctx: &mut Context,
165    groups: &mut Map<String, VariableGroup>,
166    variable_groups_section: Cursor,
167) -> Result<(), Error> {
168    let cs = variable_groups_section.into_inner();
169    for variable_group_declaration in cs.get_all(Rule::variable_group_declaration) {
170        for group in build_variable_group_declaration(ctx, variable_group_declaration)? {
171            if let Err(dupe) = groups.insert(group.to_string(), group) {
172                ctx.error(DiagnosticError::DuplicateDefinition, &dupe.loc);
173            }
174        }
175    }
176    Ok(())
177}
178
179/// Build a relations section and add the relation instances to the mapping.
180pub fn build_relations_section(
181    ctx: &mut Context,
182    relations: &mut Map<String, Relation>,
183    relations_section: Cursor,
184) -> Result<(), Error> {
185    let cs = relations_section.into_inner();
186    for relation_instantiation in cs.get_all(Rule::relation_instantiation) {
187        let inst = build_relation_instantiation(ctx, relation_instantiation)?;
188        if let Err(dupe) = relations.insert(inst.to_string(), inst) {
189            ctx.error(DiagnosticError::DuplicateDefinition, &dupe.loc);
190        }
191    }
192    Ok(())
193}
194
195/// Build a components section and add the component instances to the mapping.
196pub fn build_components_section(
197    ctx: &mut Context,
198    components: &mut Map<String, Component>,
199    components_section: Cursor,
200) -> Result<(), Error> {
201    let cs = components_section.into_inner();
202    for component_instantiation in cs.get_all(Rule::component_instantiation) {
203        let inst = build_component_instantiation(ctx, component_instantiation)?;
204        if let Err(dupe) = components.insert(inst.to_string(), inst) {
205            ctx.error(DiagnosticError::DuplicateDefinition, &dupe.loc);
206        }
207    }
208    Ok(())
209}
210
211/// Build a designs section and add the design instances to the mapping.
212pub fn build_designs_section(
213    ctx: &mut Context,
214    designs: &mut Map<String, Design>,
215    designs_section: Cursor,
216) -> Result<(), Error> {
217    let mut cs = designs_section.into_inner();
218    let stringency: Stringency = cs
219        .req_first(Rule::kw_section_designs)
220        .map(|c| c.into_inner().into())?;
221    for design_instantiation in cs.get_all(Rule::design_instantiation) {
222        let inst = build_design_instantiation(ctx, design_instantiation, stringency.clone())?;
223        if let Err(dupe) = designs.insert(inst.to_string(), inst) {
224            ctx.error(DiagnosticError::DuplicateDefinition, &dupe.loc);
225        }
226    }
227    Ok(())
228}
229
230/// Build a goals section and add the goal instances to the mapping.
231pub fn build_goals_section(
232    ctx: &mut Context,
233    goals: &mut Map<String, Goal>,
234    goals_section: Cursor,
235) -> Result<(), Error> {
236    let mut cs = goals_section.into_inner();
237    let stringency: Stringency = cs
238        .req_first(Rule::kw_section_goals)
239        .map(|c| c.into_inner().into())?;
240    for goal_instantiation in cs.get_all(Rule::goal_instantiation) {
241        let inst = build_goal_instantiation(ctx, goal_instantiation, stringency.clone())?;
242        if let Err(dupe) = goals.insert(inst.to_string(), inst) {
243            ctx.error(DiagnosticError::DuplicateDefinition, &dupe.loc);
244        }
245    }
246    Ok(())
247}
248
249/// Build a transformations section and add the transformation instances to the mapping.
250pub fn build_transformations_section(
251    ctx: &mut Context,
252    transformations: &mut Map<String, Transformation>,
253    transformations_section: Cursor,
254) -> Result<(), Error> {
255    let mut cs = transformations_section.into_inner();
256    let stringency: Stringency = cs
257        .req_first(Rule::kw_section_transformations)
258        .map(|c| c.into_inner().into())?;
259    for transformation_instantiation in cs.get_all(Rule::transformation_instantiation) {
260        let inst = build_transformation_instantiation(
261            ctx,
262            transformation_instantiation,
263            stringency.clone(),
264        )?;
265        if let Err(dupe) = transformations.insert(inst.to_string(), inst) {
266            ctx.error(DiagnosticError::DuplicateDefinition, &dupe.loc);
267        }
268    }
269    Ok(())
270}
271
272/// Build a behaviors section that might contain multiple behavior requirements.
273pub fn build_behaviors_section(
274    ctx: &mut Context,
275    behaviors: &mut Map<String, Behavior>,
276    behaviors_section: Cursor,
277) -> Result<(), Error> {
278    let mut cs = behaviors_section.into_inner();
279    let stringency: Stringency = cs
280        .req_first(Rule::kw_section_behaviors)
281        .map(|c| c.into_inner().into())?;
282    for behavior_instantiation in cs.get_all(Rule::behavior_instantiation) {
283        let behavior = build_behavior_instantiation(ctx, behavior_instantiation, &stringency)?;
284        if let Err(dupe) = behaviors.insert(behavior.to_string(), behavior) {
285            ctx.error(DiagnosticError::DuplicateDefinition, &dupe.loc);
286        }
287    }
288    Ok(())
289}
290
291/// Build a needs section and add the need instances to the mapping.
292pub fn build_needs_section(
293    ctx: &mut Context,
294    needs: &mut Map<String, Need>,
295    needs_section: Cursor,
296) -> Result<(), Error> {
297    let cs = needs_section.into_inner();
298    for need_instantiation in cs.get_all(Rule::need_instantiation) {
299        let need = build_need_instantiation(ctx, need_instantiation)?;
300        if let Err(dupe) = needs.insert(need.to_string(), need) {
301            ctx.error(DiagnosticError::DuplicateDefinition, &dupe.loc);
302        }
303    }
304    Ok(())
305}