customasm/asm/parser/
fields.rs

1use crate::*;
2
3
4pub struct AstFields
5{
6    span: diagn::Span,
7    fields: Vec<AstField>,
8}
9
10
11#[derive(Debug)]
12pub struct AstField
13{
14    pub span: diagn::Span,
15    pub name: String,
16    pub maybe_expr: Option<expr::Expr>,
17}
18
19
20pub fn parse(
21    report: &mut diagn::Report,
22    walker: &mut syntax::Walker)
23    -> Result<AstFields, ()>
24{
25    let mut fields = AstFields {
26        span: diagn::Span::new_dummy(),
27        fields: Vec::new(),
28    };
29
30    while !walker.next_useful_is(0, syntax::TokenKind::BraceClose)
31    {
32        let deprecated_hash =
33            walker.maybe_expect(syntax::TokenKind::Hash).is_some();
34
35        let tk_name = walker.expect(report, syntax::TokenKind::Identifier)?;
36        let name = walker.get_span_excerpt(tk_name.span).to_string();
37
38        if let Some(_) = fields.fields.iter().find(|f| f.name == name)
39        {
40            report.error_span(
41                format!("duplicate field `{}`", name),
42                tk_name.span);
43
44            return Err(());
45        }
46
47
48        let maybe_expr = {
49            if (deprecated_hash && !walker.next_linebreak().is_some()) ||
50                walker.maybe_expect(syntax::TokenKind::Equal).is_some()
51            {
52                let expr = expr::parse(report, walker)?;
53                fields.span = fields.span.join(expr.span());
54                Some(expr)
55            }
56            else
57            {
58                None
59            }
60        };
61
62
63        fields.span = fields.span.join(tk_name.span);
64
65        fields.fields.push(AstField {
66            span: tk_name.span,
67            name,
68            maybe_expr,
69        });
70        
71
72        if !walker.maybe_expect(syntax::TokenKind::Comma).is_some() &&
73            !walker.maybe_expect_linebreak().is_some()
74        {
75            break;
76        }
77    }
78
79    Ok(fields)
80}
81
82
83impl AstFields
84{
85    pub fn extract_optional(
86        &mut self,
87        field_name: &str)
88        -> Option<AstField>
89    {
90        let maybe_field = self.fields
91            .iter()
92            .enumerate()
93            .find(|f| f.1.name == field_name);
94
95        if let Some((index, _)) = maybe_field
96        {
97            let field = self.fields.remove(index);
98            Some(field)
99        }
100        else
101        {
102            None
103        }
104    }
105
106
107    pub fn extract(
108        &mut self,
109        report: &mut diagn::Report,
110        field_name: &str)
111        -> Result<AstField, ()>
112    {
113        match self.extract_optional(field_name)
114        {
115            Some(field) => Ok(field),
116            None =>
117            {
118                report.error_span(
119                    format!("missing field `{}`", field_name),
120                    self.span);
121
122                Err(())
123            }
124        }
125    }
126
127
128    pub fn extract_as_expr(
129        &mut self,
130        report: &mut diagn::Report,
131        field_name: &str)
132        -> Result<Option<expr::Expr>, ()>
133    {
134        let field = self.extract(report, field_name)?;
135        Ok(field.maybe_expr)
136    }
137
138
139    pub fn extract_as_optional_expr(
140        &mut self,
141        _report: &mut diagn::Report,
142        field_name: &str)
143        -> Result<Option<expr::Expr>, ()>
144    {
145        let maybe_field = self.extract_optional(field_name);
146        match maybe_field
147        {
148            Some(field) => Ok(field.maybe_expr),
149            None => Ok(None),
150        }
151    }
152
153
154    pub fn extract_as_bool(
155        &mut self,
156        _report: &mut diagn::Report,
157        field_name: &str)
158        -> Result<bool, ()>
159    {
160        let field = self.extract_optional(field_name);
161        match field
162        {
163            Some(_) => Ok(true),
164            None => Ok(false),
165        }
166    }
167
168
169    pub fn report_remaining(
170        &self,
171        report: &mut diagn::Report)
172        -> Result<(), ()>
173    {
174        for field in &self.fields
175        {
176            report.error_span(
177                format!("invalid field `{}`", field.name),
178                field.span);
179        }
180
181        if self.fields.len() > 0
182        {
183            Err(())
184        }
185        else
186        {
187            Ok(())
188        }
189    }
190}