esl_compiler/builder/
variable.rs

1//! Variable instances builder module
2
3use crate::builder::subject::{build_some_subject, Subject};
4use crate::context::Context;
5use crate::cursor::{Cursor, Error, Token};
6use crate::location::FileLocation;
7use crate::parser::Rule;
8use crate::reference::{Reference, TypeDefinitionTarget, VariableTarget};
9
10/// Single variable.
11#[derive(Clone, Debug, PartialEq)]
12pub struct Variable {
13    /// Name of this variable.
14    pub name: Token,
15    /// Location of the variable's instantiation.
16    pub loc: FileLocation,
17    /// Type definition of this variable.
18    pub definition: Reference<Token, TypeDefinitionTarget>,
19    /// Whether this is a property of some component.
20    pub is_property: bool,
21}
22impl std::fmt::Display for Variable {
23    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
24        write!(f, "{}", self.name)
25    }
26}
27
28/// An ad-hoc variable group.
29#[derive(Clone, Debug, PartialEq)]
30pub struct VariableGroup {
31    /// Name of this variable group.
32    pub name: Token,
33    /// Location of the group's instantiation.
34    pub loc: FileLocation,
35    /// Members of this group.
36    pub members: Vec<Reference<Subject, VariableTarget>>,
37}
38impl std::fmt::Display for VariableGroup {
39    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
40        write!(f, "{}", self.name)
41    }
42}
43
44/// A "one or more" variables of some type.
45#[derive(Clone, Debug, PartialEq)]
46pub struct UnboundedVariable {
47    /// Name of the "one or more" variable.
48    pub name: Token,
49    /// Location of the unbounded variable.
50    pub loc: FileLocation,
51    /// Type definition that each of the variables should have.
52    pub definition: Reference<Token, TypeDefinitionTarget>,
53}
54impl std::fmt::Display for UnboundedVariable {
55    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
56        write!(f, "{}", self.name)
57    }
58}
59
60/// Build a variable declaration.
61pub fn build_variable_declaration(
62    ctx: &mut Context,
63    variable_declaration: Cursor,
64    is_property: bool,
65) -> Result<Vec<Variable>, Error> {
66    let mut variables = vec![];
67    let mut cs = variable_declaration.into_inner();
68
69    let some_names = cs.req_first(Rule::some_names)?;
70
71    let some_type = cs.req_first(Rule::some_type)?;
72    let definition = Reference::new(some_type.into());
73
74    for some_name in some_names.into_inner().get_all(Rule::some_name) {
75        let name = some_name.into();
76        variables.push(Variable {
77            name,
78            loc: cs.as_location(),
79            definition: definition.clone(),
80            is_property,
81        });
82    }
83
84    Ok(variables)
85}
86
87/// Build a parameter declaration.
88pub fn build_parameter_declaration(
89    ctx: &mut Context,
90    parameter_declaration: Cursor,
91) -> Result<Vec<Variable>, Error> {
92    let mut cs = parameter_declaration.into_inner();
93    let variable_declaration = cs.req_first(Rule::variable_declaration)?;
94    let is_property = cs.find_first(Rule::kw_class_property).is_some();
95    build_variable_declaration(ctx, variable_declaration, is_property)
96}
97
98/// Build a variable group declaration.
99pub fn build_variable_group_declaration(
100    ctx: &mut Context,
101    variable_group_line: Cursor,
102) -> Result<Vec<VariableGroup>, Error> {
103    let mut groups = vec![];
104    let mut cs = variable_group_line.into_inner();
105
106    let some_names = cs.req_first(Rule::some_names)?;
107
108    let mut members = vec![];
109    let arguments = cs.req_first(Rule::arguments)?;
110    for some_variable in arguments.into_inner().get_all(Rule::some_variable) {
111        members.push(build_some_variable(ctx, some_variable)?);
112    }
113
114    for some_name in some_names.into_inner().get_all(Rule::some_name) {
115        let name = some_name.into();
116        groups.push(VariableGroup {
117            name,
118            loc: cs.as_location(),
119            members: members.clone(),
120        })
121    }
122
123    Ok(groups)
124}
125
126/// Build an unbounded variable declaration (one or more foo is a Foo).
127pub fn build_variable_unbounded_declaration(
128    ctx: &mut Context,
129    variable_line_unbounded: Cursor,
130) -> Result<UnboundedVariable, Error> {
131    let mut cs = variable_line_unbounded.into_inner();
132    let name = cs
133        .req_first(Rule::some_name)
134        .map(|some_name| some_name.into())?;
135
136    let some_type = cs.req_first(Rule::some_type)?;
137    let definition = Reference::new(some_type.into());
138    Ok(UnboundedVariable {
139        name,
140        loc: cs.as_location(),
141        definition,
142    })
143}
144
145/// Build some variables enumeration.
146pub fn build_some_variables(
147    ctx: &mut Context,
148    some_variables: Cursor,
149) -> Result<Vec<Reference<Subject, VariableTarget>>, Error> {
150    some_variables
151        .into_inner()
152        .get_all(Rule::some_variable)
153        .map(|c| build_some_variable(ctx, c))
154        .collect()
155}
156
157/// Build some variable.
158pub fn build_some_variable(
159    ctx: &mut Context,
160    some_variable: Cursor,
161) -> Result<Reference<Subject, VariableTarget>, Error> {
162    let reference = some_variable
163        .into_inner()
164        .req_first(Rule::some_subject)
165        .and_then(|c| build_some_subject(ctx, c))?
166        .into();
167    Ok(reference)
168}