dpscript/dpscript/lexer/analysis/
func.rs

1use 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            // cursor.skip(1);
106
107            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}