customasm/asm/parser/
fields.rs1use 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}