dpscript/dpscript/lexer/analysis/
func.rs1use crate::{
2 check_token, AddSpan, Attribute, Function, FunctionArg, LexerError, Node, Result, Spanned,
3 Token, TokenCursor, Type,
4};
5
6use super::Analyzer;
7
8impl Analyzer<Function> for Function {
9 fn analyze(
10 mut item: Spanned<Token>,
11 cursor: &mut TokenCursor,
12 nodes: &mut Vec<Node>,
13 ) -> Result<Option<Function>> {
14 match item.0 {
15 Token::Fn
16 | Token::Pub
17 | Token::Inline
18 | Token::Facade
19 | Token::Component
20 | Token::Hash => {}
21 _ => return Ok(None),
22 }
23
24 let attrs = Attribute::analyze(item.clone(), cursor, nodes)?;
25
26 let attrs = if let Some(attrs) = attrs {
27 item = cursor.next_or_die(item.1)?;
28 vec![attrs]
29 } else {
30 Vec::new()
31 };
32
33 let is_pub = match item.0 {
34 Token::Pub => true,
35 Token::Fn | Token::Facade | Token::Inline | Token::Compiler => false,
36 _ => return Ok(None),
37 };
38
39 if is_pub {
40 if !cursor.peek().is_some_and(|(v, _)| {
41 v == Token::Fn || v == Token::Inline || v == Token::Facade || v == Token::Compiler
42 }) {
43 return Ok(None);
44 }
45
46 item = cursor.next().unwrap();
47 }
48
49 let is_inline = match item.0 {
50 Token::Inline => true,
51 Token::Fn | Token::Facade | Token::Compiler => false,
52 _ => return Ok(None),
53 };
54
55 if is_inline {
56 check_token!(cursor == Fn);
57 item = cursor.next().unwrap();
58 }
59
60 let is_facade = match item.0 {
61 Token::Facade => true,
62 Token::Fn | Token::Compiler => false,
63 _ => return Ok(None),
64 };
65
66 if is_facade {
67 check_token!(cursor == Fn);
68 item = cursor.next().unwrap();
69 }
70
71 let is_compiler = match item.0 {
72 Token::Compiler => true,
73 Token::Fn => false,
74 _ => return Ok(None),
75 };
76
77 if is_compiler {
78 check_token!(cursor == Fn);
79 item = cursor.next().unwrap();
80 }
81
82 check_token!(cursor => item == Fn);
83
84 let (name, name_span) = cursor.next_or_die(item.1)?;
85
86 let name = match name {
87 Token::Ident(id) => (id, name_span),
88
89 _ => {
90 return Err(LexerError {
91 src: cursor.source(),
92 at: name_span,
93 err: format!("Unexpected token while parsing a function: {}", name),
94 }
95 .into())
96 }
97 };
98
99 let it = check_token!(remove cursor == LeftParen).unwrap();
100
101 let mut args = Vec::new();
102 let mut span = item.1.add(it.1);
103
104 if cursor.peek().is_some_and(|(v, _)| v != Token::RightParen) {
105 let mut buf = Vec::new();
108 let mut cur = Vec::new();
109 let mut opens = 0;
110
111 while let Some((token, span)) = cursor.next() {
112 if token == Token::LeftParen {
113 opens += 1;
114 }
115
116 if token == Token::RightParen {
117 if opens == 0 {
118 if !cur.is_empty() {
119 buf.push(cur);
120 }
121
122 break;
123 } else {
124 opens -= 1;
125 }
126 }
127
128 if token == Token::Comma {
129 buf.push(cur);
130 cur = Vec::new();
131 continue;
132 }
133
134 cur.push((token, span));
135 }
136
137 for buf in buf {
138 let mut arg_cursor = TokenCursor::new_from_src(
139 cursor.source().name(),
140 cursor.source().inner().clone(),
141 buf,
142 );
143
144 if let Some(arg) =
145 FunctionArg::analyze(arg_cursor.next().unwrap(), &mut arg_cursor, nodes)?
146 {
147 args.push(arg);
148 }
149 }
150
151 if let Some(arg) = args.last() {
152 span = span.add(arg.span);
153 }
154 } else {
155 span = span.add(check_token!(remove cursor == RightParen).unwrap().1);
156 }
157
158 let mut ret = None;
159
160 if cursor.peek().is_some_and(|(v, _)| v == Token::Minus)
161 && cursor
162 .peek_ahead(1)
163 .is_some_and(|(v, _)| v == Token::RightAngle)
164 {
165 let (_, span_) = cursor.next_or_die(item.1)?;
166 let (_, span_) = cursor.next_or_die(span_)?;
167
168 ret = Type::analyze(cursor.next_or_die(span_)?, cursor, nodes)?;
169
170 if let Some(ref ret) = ret {
171 span = span.add(ret.span);
172 };
173 }
174
175 let mut body = Vec::new();
176
177 if !is_facade && !is_compiler {
178 check_token!(remove cursor == LeftBrace);
179
180 let mut buf = Vec::new();
181 let mut opens = 0;
182
183 while let Some((token, span)) = cursor.next() {
184 if token == Token::LeftBrace {
185 opens += 1;
186 }
187
188 if token == Token::RightBrace {
189 if opens == 0 {
190 break;
191 } else {
192 opens -= 1;
193 }
194 }
195
196 buf.push((token, span));
197 }
198
199 if let Some(tkn) = buf.last() {
200 span = span.add(tkn.1);
201 }
202
203 let mut buf_cursor = TokenCursor::new_from_src(
204 cursor.source().name(),
205 cursor.source().inner().clone(),
206 buf,
207 );
208
209 while let Some(item) = buf_cursor.next() {
210 Node::analyze(item, &mut buf_cursor, &mut body)?;
211 }
212 }
213
214 Ok(Some(Self {
215 args,
216 attrs,
217 body,
218 is_compiler,
219 is_facade,
220 is_pub,
221 is_inline,
222 name,
223 ret,
224 span,
225 locals: None,
226 }))
227 }
228}
229
230impl Analyzer<FunctionArg> for FunctionArg {
231 fn analyze(
232 mut item: Spanned<Token>,
233 cursor: &mut TokenCursor,
234 nodes: &mut Vec<Node>,
235 ) -> Result<Option<FunctionArg>> {
236 let attr = match item.0 {
237 Token::Hash => {
238 let it = Some(Attribute::analyze(item, cursor, nodes)?);
239 item = cursor.next().unwrap();
240 it.flatten()
241 }
242
243 _ => None,
244 };
245
246 let name = match item.0 {
247 Token::Ident(id) => (id, item.1),
248
249 _ => {
250 return Err(LexerError {
251 src: cursor.source(),
252 at: item.1,
253 err: format!("Unexpected token while parsing a function: {}", item.0),
254 }
255 .into())
256 }
257 };
258
259 let colon = check_token!(remove cursor == Colon).unwrap();
260
261 let ty = match cursor.peek() {
262 Some(item) => match Type::analyze(item.clone(), cursor, nodes)? {
263 Some(ty) => ty,
264 None => {
265 return Err(LexerError {
266 src: cursor.source(),
267 at: item.1,
268 err: "Function arguments require a type!".into(),
269 }
270 .into())
271 }
272 },
273
274 _ => {
275 return Err(LexerError {
276 src: cursor.source(),
277 at: colon.1,
278 err: "Unexpected end of file!".into(),
279 }
280 .into())
281 }
282 };
283
284 Ok(Some(Self {
285 attrs: attr.map(|v| vec![v]).unwrap_or_default(),
286 name,
287 span: item.1.add(ty.span),
288 ty,
289 }))
290 }
291}