leo_parser/
conversions.rs

1// Copyright (C) 2019-2025 Provable Inc.
2// This file is part of the Leo library.
3
4// The Leo library is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// The Leo library is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
16
17use indexmap::IndexMap;
18
19use snarkvm::prelude::{Address, TestnetV0};
20
21use leo_ast::{Expression, Intrinsic, NodeBuilder};
22use leo_errors::{Handler, ParserError, Result, TypeCheckerError};
23use leo_parser_lossless::{
24    ExpressionKind,
25    IntegerLiteralKind,
26    IntegerTypeKind,
27    LiteralKind,
28    StatementKind,
29    SyntaxKind,
30    SyntaxNode,
31    TypeKind,
32};
33use leo_span::{
34    Span,
35    Symbol,
36    sym::{self},
37};
38
39fn to_identifier(node: &SyntaxNode<'_>, builder: &NodeBuilder) -> leo_ast::Identifier {
40    let name = Symbol::intern(node.text);
41    leo_ast::Identifier { name, span: node.span, id: builder.next_id() }
42}
43
44fn path_to_parts(node: &SyntaxNode<'_>, builder: &NodeBuilder) -> Vec<leo_ast::Identifier> {
45    let mut identifiers = Vec::new();
46    let mut i = node.span.lo;
47    for text in node.text.split("::") {
48        let end = i + text.len() as u32;
49        let span = leo_span::Span { lo: i, hi: end };
50        let name = Symbol::intern(text);
51        identifiers.push(leo_ast::Identifier { name, span, id: builder.next_id() });
52        // Account for the "::".
53        i = end + 2;
54    }
55    identifiers
56}
57
58fn to_mode(node: &SyntaxNode<'_>) -> leo_ast::Mode {
59    match node.text {
60        "constant" => leo_ast::Mode::Constant,
61        "private" => leo_ast::Mode::Private,
62        "public" => leo_ast::Mode::Public,
63        _ => leo_ast::Mode::None,
64    }
65}
66
67fn to_type(node: &SyntaxNode<'_>, builder: &NodeBuilder, handler: &Handler) -> Result<leo_ast::Type> {
68    let SyntaxKind::Type(type_kind) = node.kind else { todo!() };
69
70    let type_ = match type_kind {
71        TypeKind::Address => leo_ast::Type::Address,
72        TypeKind::Array => {
73            let [_l, type_, _s, length, _r] = &node.children[..] else {
74                // This "Can't happen" panic, like others in this file, will not be triggered unless
75                // there is an error in grammar.lalrpop.
76                panic!("Can't happen");
77            };
78            let element_type = to_type(type_, builder, handler)?;
79            let length = to_expression(length, builder, handler)?;
80            leo_ast::ArrayType { element_type: Box::new(element_type), length: Box::new(length) }.into()
81        }
82        TypeKind::Boolean => leo_ast::Type::Boolean,
83        TypeKind::Composite => {
84            let name = &node.children[0];
85            if let Some((program, name_str)) = name.text.split_once(".aleo/") {
86                // This is a locator.
87                let name_id = leo_ast::Identifier {
88                    name: Symbol::intern(name_str),
89                    span: leo_span::Span {
90                        lo: name.span.lo + program.len() as u32 + 5,
91                        hi: name.span.lo + name.text.len() as u32,
92                    },
93                    id: builder.next_id(),
94                };
95                leo_ast::CompositeType {
96                    path: leo_ast::Path::new(Vec::new(), name_id, false, None, name_id.span, builder.next_id()),
97                    const_arguments: Vec::new(),
98                    program: Some(Symbol::intern(program)),
99                }
100                .into()
101            } else {
102                // It's a path.
103                let mut path_components = path_to_parts(name, builder);
104                let mut const_arguments = Vec::new();
105                if let Some(arg_list) = node.children.get(1) {
106                    const_arguments = arg_list
107                        .children
108                        .iter()
109                        .filter(|child| matches!(child.kind, SyntaxKind::Expression(..)))
110                        .map(|child| to_expression(child, builder, handler))
111                        .collect::<Result<Vec<_>>>()?;
112                }
113                let identifier = path_components.pop().unwrap();
114                let path = leo_ast::Path::new(path_components, identifier, false, None, name.span, builder.next_id());
115                leo_ast::CompositeType { path, const_arguments, program: None }.into()
116            }
117        }
118        TypeKind::Field => leo_ast::Type::Field,
119        TypeKind::Future => {
120            if node.children.len() == 1 {
121                leo_ast::FutureType::default().into()
122            } else {
123                let types = node
124                    .children
125                    .iter()
126                    .filter(|child| matches!(child.kind, SyntaxKind::Type(..)))
127                    .map(|child| to_type(child, builder, handler))
128                    .collect::<Result<Vec<_>>>()?;
129                leo_ast::FutureType::new(types, None, true).into()
130            }
131        }
132        TypeKind::Group => leo_ast::Type::Group,
133        TypeKind::Identifier => todo!(),
134        TypeKind::Integer(int_type_kind) => {
135            let int_type = match int_type_kind {
136                IntegerTypeKind::U8 => leo_ast::IntegerType::U8,
137                IntegerTypeKind::U16 => leo_ast::IntegerType::U16,
138                IntegerTypeKind::U32 => leo_ast::IntegerType::U32,
139                IntegerTypeKind::U64 => leo_ast::IntegerType::U64,
140                IntegerTypeKind::U128 => leo_ast::IntegerType::U128,
141                IntegerTypeKind::I8 => leo_ast::IntegerType::I8,
142                IntegerTypeKind::I16 => leo_ast::IntegerType::I16,
143                IntegerTypeKind::I32 => leo_ast::IntegerType::I32,
144                IntegerTypeKind::I64 => leo_ast::IntegerType::I64,
145                IntegerTypeKind::I128 => leo_ast::IntegerType::I128,
146            };
147            leo_ast::Type::Integer(int_type)
148        }
149        TypeKind::Mapping => {
150            todo!()
151        }
152        TypeKind::Optional => {
153            let [inner_type, _q] = &node.children[..] else {
154                // This "Can't happen" panic, like others in this file, will not be triggered unless
155                // there is an error in grammar.lalrpop.
156                panic!("Can't happen");
157            };
158            leo_ast::Type::Optional(leo_ast::OptionalType { inner: Box::new(to_type(inner_type, builder, handler)?) })
159        }
160        TypeKind::Scalar => leo_ast::Type::Scalar,
161        TypeKind::Signature => leo_ast::Type::Signature,
162        TypeKind::String => leo_ast::Type::String,
163        TypeKind::Tuple => {
164            let elements = node
165                .children
166                .iter()
167                .filter(|child| matches!(child.kind, SyntaxKind::Type(..)))
168                .map(|child| to_type(child, builder, handler))
169                .collect::<Result<Vec<_>>>()?;
170            leo_ast::TupleType::new(elements).into()
171        }
172        TypeKind::Vector => {
173            let [_l, type_, _r] = &node.children[..] else {
174                // This "Can't happen" panic, like others in this file, will not be triggered unless
175                // there is an error in grammar.lalrpop.
176                panic!("Can't happen");
177            };
178            let element_type = to_type(type_, builder, handler)?;
179            leo_ast::VectorType { element_type: Box::new(element_type) }.into()
180        }
181        TypeKind::Numeric => leo_ast::Type::Numeric,
182        TypeKind::Unit => leo_ast::Type::Unit,
183    };
184
185    Ok(type_)
186}
187
188fn to_block(node: &SyntaxNode<'_>, builder: &NodeBuilder, handler: &Handler) -> Result<leo_ast::Block> {
189    assert_eq!(node.kind, SyntaxKind::Statement(StatementKind::Block));
190
191    let statements = node
192        .children
193        .iter()
194        .filter(|child| matches!(child.kind, SyntaxKind::Statement(..)))
195        .map(|child| to_statement(child, builder, handler))
196        .collect::<Result<Vec<_>>>()?;
197    Ok(leo_ast::Block { statements, span: node.span, id: builder.next_id() })
198}
199
200pub fn to_statement(node: &SyntaxNode<'_>, builder: &NodeBuilder, handler: &Handler) -> Result<leo_ast::Statement> {
201    let SyntaxKind::Statement(statement_kind) = node.kind else { todo!() };
202
203    let span = node.span;
204    let id = builder.next_id();
205
206    let value = match statement_kind {
207        StatementKind::Assert => {
208            let [_a, _left, expr, _right, _s] = &node.children[..] else {
209                panic!("Can't happen");
210            };
211
212            let expr = to_expression(expr, builder, handler)?;
213            let variant = leo_ast::AssertVariant::Assert(expr);
214
215            leo_ast::AssertStatement { variant, span, id }.into()
216        }
217        StatementKind::AssertEq => {
218            let [_a, _left, e0, _c, e1, _right, _s] = &node.children[..] else {
219                panic!("Can't happen");
220            };
221
222            let e0 = to_expression(e0, builder, handler)?;
223            let e1 = to_expression(e1, builder, handler)?;
224            let variant = leo_ast::AssertVariant::AssertEq(e0, e1);
225
226            leo_ast::AssertStatement { variant, span, id }.into()
227        }
228        StatementKind::AssertNeq => {
229            let [_a, _left, e0, _c, e1, _right, _s] = &node.children[..] else {
230                panic!("Can't happen");
231            };
232
233            let e0 = to_expression(e0, builder, handler)?;
234            let e1 = to_expression(e1, builder, handler)?;
235            let variant = leo_ast::AssertVariant::AssertNeq(e0, e1);
236
237            leo_ast::AssertStatement { variant, span, id }.into()
238        }
239        StatementKind::Assign => {
240            let [lhs, a, rhs, _s] = &node.children[..] else {
241                panic!("Can't happen");
242            };
243
244            let left = to_expression(lhs, builder, handler)?;
245            let right = to_expression(rhs, builder, handler)?;
246            if a.text == "=" {
247                // Just a regular assignment.
248                leo_ast::AssignStatement { place: left, value: right, span, id }.into()
249            } else {
250                // We have to translate it into a binary operation and assignment.
251                let op = match a.text {
252                    "+=" => leo_ast::BinaryOperation::Add,
253                    "-=" => leo_ast::BinaryOperation::Sub,
254                    "*=" => leo_ast::BinaryOperation::Mul,
255                    "/=" => leo_ast::BinaryOperation::Div,
256                    "%=" => leo_ast::BinaryOperation::Rem,
257                    "**=" => leo_ast::BinaryOperation::Pow,
258                    "<<=" => leo_ast::BinaryOperation::Shl,
259                    ">>=" => leo_ast::BinaryOperation::Shr,
260                    "&=" => leo_ast::BinaryOperation::BitwiseAnd,
261                    "|=" => leo_ast::BinaryOperation::BitwiseOr,
262                    "^=" => leo_ast::BinaryOperation::Xor,
263                    "&&=" => leo_ast::BinaryOperation::And,
264                    "||=" => leo_ast::BinaryOperation::Or,
265                    _ => panic!("Can't happen"),
266                };
267
268                let binary_expr = leo_ast::BinaryExpression { left: left.clone(), right, op, span, id };
269
270                leo_ast::AssignStatement { place: left, value: binary_expr.into(), span, id }.into()
271            }
272        }
273        StatementKind::Block => to_block(node, builder, handler)?.into(),
274        StatementKind::Conditional => {
275            match &node.children[..] {
276                [_if, c, block] => {
277                    // No else.
278                    let condition = to_expression(c, builder, handler)?;
279                    let then = to_block(block, builder, handler)?;
280                    leo_ast::ConditionalStatement { condition, then, otherwise: None, span, id }.into()
281                }
282                [_if, c, block, _else, otherwise] => {
283                    // An else clause.
284                    let condition = to_expression(c, builder, handler)?;
285                    let then = to_block(block, builder, handler)?;
286                    let otherwise = to_statement(otherwise, builder, handler)?;
287                    leo_ast::ConditionalStatement { condition, then, otherwise: Some(Box::new(otherwise)), span, id }
288                        .into()
289                }
290
291                _ => panic!("Can't happen"),
292            }
293        }
294        StatementKind::Const => {
295            let [_const, name, _c, type_, _a, rhs, _s] = &node.children[..] else {
296                panic!("Can't happen");
297            };
298
299            let place = to_identifier(name, builder);
300            let type_ = to_type(type_, builder, handler)?;
301            let value = to_expression(rhs, builder, handler)?;
302
303            leo_ast::ConstDeclaration { place, type_, value, span, id }.into()
304        }
305        StatementKind::Definition => {
306            match &node.children[..] {
307                [_let, name, _c, type_, _assign, e, _s] => {
308                    // Singe place, type.
309                    let name = to_identifier(name, builder);
310                    let place = leo_ast::DefinitionPlace::Single(name);
311                    let value = to_expression(e, builder, handler)?;
312                    let type_ = Some(to_type(type_, builder, handler)?);
313                    leo_ast::DefinitionStatement { place, type_, value, span, id }.into()
314                }
315                [_let, name, _assign, e, _s] => {
316                    // Single place, no type.
317                    let name = to_identifier(name, builder);
318                    let place = leo_ast::DefinitionPlace::Single(name);
319                    let value = to_expression(e, builder, handler)?;
320                    leo_ast::DefinitionStatement { place, type_: None, value, span, id }.into()
321                }
322                children => {
323                    // Multiple place, with or without type.
324                    let right_paren_index = children.iter().position(|child| child.text == ")").unwrap();
325
326                    // The items between parens.
327                    let names = children[2..right_paren_index].iter()
328                        // The ones that aren't commas - the identifiers.
329                        .filter(|child| child.text != ",")
330                        .map(|child| to_identifier(child, builder))
331                    .collect();
332
333                    // Get the type, if there is one.
334                    let type_ = children
335                        .iter()
336                        .find(|child| matches!(child.kind, SyntaxKind::Type(..)))
337                        .map(|child| to_type(child, builder, handler))
338                        .transpose()?;
339
340                    let expr = &children[children.len() - 2];
341                    let value = to_expression(expr, builder, handler)?;
342                    let place = leo_ast::DefinitionPlace::Multiple(names);
343                    leo_ast::DefinitionStatement { place, type_, value, span, id }.into()
344                }
345            }
346        }
347        StatementKind::Expression => {
348            let expression = to_expression(&node.children[0], builder, handler)?;
349            leo_ast::ExpressionStatement { expression, span, id }.into()
350        }
351        StatementKind::Iteration => {
352            match &node.children[..] {
353                [_f, i, _n, low, _d, hi, block] => {
354                    // No type.
355                    leo_ast::IterationStatement {
356                        variable: to_identifier(i, builder),
357                        type_: None,
358                        start: to_expression(low, builder, handler)?,
359                        stop: to_expression(hi, builder, handler)?,
360                        inclusive: false,
361                        block: to_block(block, builder, handler)?,
362                        span,
363                        id,
364                    }
365                    .into()
366                }
367                [_f, i, _c, type_, _n, low, _d, hi, block] => {
368                    // With type.
369                    leo_ast::IterationStatement {
370                        variable: to_identifier(i, builder),
371                        type_: Some(to_type(type_, builder, handler)?),
372                        start: to_expression(low, builder, handler)?,
373                        stop: to_expression(hi, builder, handler)?,
374                        inclusive: false,
375                        block: to_block(block, builder, handler)?,
376                        span,
377                        id,
378                    }
379                    .into()
380                }
381                _ => panic!("Can't happen"),
382            }
383        }
384        StatementKind::Return => {
385            match &node.children[..] {
386                [_r, e, _s] => {
387                    // With expression.
388                    let expression = to_expression(e, builder, handler)?;
389                    leo_ast::ReturnStatement { expression, span, id }.into()
390                }
391                [_r, _s] => {
392                    // No expression.
393                    leo_ast::ReturnStatement {
394                        expression: leo_ast::UnitExpression { span, id: builder.next_id() }.into(),
395                        span,
396                        id,
397                    }
398                    .into()
399                }
400                _ => panic!("Can't happen"),
401            }
402        }
403    };
404
405    Ok(value)
406}
407
408pub fn to_expression(node: &SyntaxNode<'_>, builder: &NodeBuilder, handler: &Handler) -> Result<Expression> {
409    let SyntaxKind::Expression(expression_kind) = node.kind else { panic!("Can't happen") };
410
411    let span = node.span;
412    let id = builder.next_id();
413    let text = || node.text.to_string();
414
415    let value = match expression_kind {
416        ExpressionKind::ArrayAccess => {
417            let [array, _left, index, _right] = &node.children[..] else {
418                panic!("Can't happen");
419            };
420
421            let array = to_expression(array, builder, handler)?;
422            let index = to_expression(index, builder, handler)?;
423
424            leo_ast::ArrayAccess { array, index, span, id }.into()
425        }
426
427        ExpressionKind::Intrinsic => {
428            let name = Symbol::intern(node.children[0].text);
429
430            let mut type_parameters = Vec::new();
431            if let Some(parameter_list) =
432                node.children.iter().find(|child| matches!(child.kind, SyntaxKind::ConstArgumentList))
433            {
434                type_parameters = parameter_list
435                    .children
436                    .iter()
437                    .filter(|child| match child.kind {
438                        SyntaxKind::Type(..) => true,
439                        SyntaxKind::Expression(..) => {
440                            handler.emit_err(ParserError::custom(
441                                "Intrinsics may only have type parameters as generic arguments",
442                                child.span,
443                            ));
444                            false
445                        }
446                        _ => false,
447                    })
448                    .map(|child| Ok((to_type(child, builder, handler)?, child.span)))
449                    .collect::<Result<Vec<_>>>()?;
450            }
451            let arguments = node
452                .children
453                .iter()
454                .filter(|child| matches!(child.kind, SyntaxKind::Expression(..)))
455                .map(|child| to_expression(child, builder, handler))
456                .collect::<Result<Vec<_>>>()?;
457
458            leo_ast::IntrinsicExpression { name, type_parameters, arguments, span, id }.into()
459        }
460
461        ExpressionKind::AssociatedConstant => {
462            // This is the only associated constant parsed.
463            leo_ast::IntrinsicExpression { name: sym::_group_gen, type_parameters: vec![], arguments: vec![], span, id }
464                .into()
465        }
466        ExpressionKind::AssociatedFunctionCall => {
467            let mut components = path_to_parts(&node.children[0], builder);
468            let name = components.pop().unwrap();
469            let variant = components.pop().unwrap();
470
471            let mut type_parameters = Vec::new();
472            if let Some(parameter_list) =
473                node.children.iter().find(|child| matches!(child.kind, SyntaxKind::ConstArgumentList))
474            {
475                type_parameters = parameter_list
476                    .children
477                    .iter()
478                    .filter(|child| match child.kind {
479                        SyntaxKind::Type(..) => true,
480                        SyntaxKind::Expression(..) => {
481                            handler.emit_err(ParserError::custom(
482                                "Associated function calls may only have type parameters as generic arguments",
483                                child.span,
484                            ));
485                            false
486                        }
487                        _ => false,
488                    })
489                    .map(|child| Ok((to_type(child, builder, handler)?, child.span)))
490                    .collect::<Result<Vec<_>>>()?;
491            }
492            let arguments = node
493                .children
494                .iter()
495                .filter(|child| matches!(child.kind, SyntaxKind::Expression(..)))
496                .map(|child| to_expression(child, builder, handler))
497                .collect::<Result<Vec<_>>>()?;
498
499            if let Some(converted_name) = Intrinsic::convert_path_symbols(variant.name, name.name) {
500                leo_ast::IntrinsicExpression { name: converted_name, type_parameters, arguments, span, id }.into()
501            } else {
502                handler.emit_err(ParserError::custom(
503                    format!("Unknown associated function: {}::{}", variant, name,),
504                    span,
505                ));
506                leo_ast::ErrExpression { span, id }.into()
507            }
508        }
509        ExpressionKind::Async => {
510            let [_a, block] = &node.children[..] else {
511                panic!("Can't happen");
512            };
513            leo_ast::AsyncExpression { block: to_block(block, builder, handler)?, span, id }.into()
514        }
515        ExpressionKind::Array => {
516            let elements = node
517                .children
518                .iter()
519                .filter(|child| matches!(child.kind, SyntaxKind::Expression(..)))
520                .map(|child| to_expression(child, builder, handler))
521                .collect::<Result<Vec<_>>>()?;
522            leo_ast::ArrayExpression { elements, span, id }.into()
523        }
524        ExpressionKind::Binary => {
525            let [lhs, op, rhs] = &node.children[..] else {
526                panic!("Can't happen");
527            };
528            // Matches against strings like this are linear searches
529            // which could potentially be improved to constant time by
530            // storing the logos token in the LALRPOP token and matching
531            // against it here.
532            let op = match op.text {
533                "==" => leo_ast::BinaryOperation::Eq,
534                "!=" => leo_ast::BinaryOperation::Neq,
535                "<" => leo_ast::BinaryOperation::Lt,
536                "<=" => leo_ast::BinaryOperation::Lte,
537                ">" => leo_ast::BinaryOperation::Gt,
538                ">=" => leo_ast::BinaryOperation::Gte,
539                "+" => leo_ast::BinaryOperation::Add,
540                "-" => leo_ast::BinaryOperation::Sub,
541                "*" => leo_ast::BinaryOperation::Mul,
542                "/" => leo_ast::BinaryOperation::Div,
543                "%" => leo_ast::BinaryOperation::Rem,
544                "||" => leo_ast::BinaryOperation::Or,
545                "&&" => leo_ast::BinaryOperation::And,
546                "|" => leo_ast::BinaryOperation::BitwiseOr,
547                "&" => leo_ast::BinaryOperation::BitwiseAnd,
548                "**" => leo_ast::BinaryOperation::Pow,
549                "<<" => leo_ast::BinaryOperation::Shl,
550                ">>" => leo_ast::BinaryOperation::Shr,
551                "^" => leo_ast::BinaryOperation::Xor,
552                _ => panic!("Can't happen"),
553            };
554            let left = to_expression(lhs, builder, handler)?;
555            let right = to_expression(rhs, builder, handler)?;
556
557            leo_ast::BinaryExpression { left, right, op, span, id }.into()
558        }
559        ExpressionKind::Call => {
560            let name = &node.children[0];
561
562            let arguments = node
563                .children
564                .iter()
565                .filter(|child| matches!(child.kind, SyntaxKind::Expression(..)))
566                .map(|child| to_expression(child, builder, handler))
567                .collect::<Result<Vec<_>>>()?;
568
569            let (function, program) = if let Some((first, second)) = name.text.split_once(".aleo/") {
570                // This is a locator.
571                let symbol = Symbol::intern(second);
572                let lo = node.span.lo + first.len() as u32 + ".aleo/".len() as u32;
573                let second_span = Span { lo, hi: lo + second.len() as u32 };
574                let identifier = leo_ast::Identifier { name: symbol, span: second_span, id: builder.next_id() };
575                let function = leo_ast::Path::new(Vec::new(), identifier, false, None, span, builder.next_id());
576                (function, Some(Symbol::intern(first)))
577            } else {
578                // It's a path.
579                let mut components = path_to_parts(name, builder);
580                let identifier = components.pop().unwrap();
581                let function = leo_ast::Path::new(components, identifier, false, None, name.span, builder.next_id());
582                (function, None)
583            };
584
585            let mut const_arguments = Vec::new();
586            if let Some(argument_list) =
587                node.children.iter().find(|child| matches!(child.kind, SyntaxKind::ConstArgumentList))
588            {
589                const_arguments = argument_list
590                    .children
591                    .iter()
592                    .filter(|child| match child.kind {
593                        SyntaxKind::Expression(..) => true,
594                        SyntaxKind::Type(..) => {
595                            handler.emit_err(ParserError::custom(
596                                "Function calls may only have constant expressions as generic arguments",
597                                child.span,
598                            ));
599                            false
600                        }
601                        _ => false,
602                    })
603                    .map(|child| to_expression(child, builder, handler))
604                    .collect::<Result<Vec<_>>>()?;
605            }
606
607            leo_ast::CallExpression { function, const_arguments, arguments, program, span, id }.into()
608        }
609        ExpressionKind::Cast => {
610            let [expression, _as, type_] = &node.children[..] else {
611                panic!("Can't happen");
612            };
613
614            let expression = to_expression(expression, builder, handler)?;
615            let type_ = to_type(type_, builder, handler)?;
616
617            leo_ast::CastExpression { expression, type_, span, id }.into()
618        }
619        ExpressionKind::Path => {
620            // We need to find the spans of the individual path components, since the
621            // lossless tree just has the span of the entire path.
622            let mut identifiers = path_to_parts(&node.children[0], builder);
623            let identifier = identifiers.pop().unwrap();
624            leo_ast::Path::new(identifiers, identifier, false, None, span, id).into()
625        }
626        ExpressionKind::Literal(literal_kind) => match literal_kind {
627            LiteralKind::Address => {
628                let t = text();
629                if !t.contains(".aleo") && t.parse::<Address<TestnetV0>>().is_err() {
630                    // We do this check here rather than in `leo-parser-lossless` simply
631                    // to avoid a dependency on snarkvm for `leo-parser-lossless`.
632                    handler.emit_err(ParserError::invalid_address_lit(&t, span));
633                }
634                leo_ast::Literal::address(t, span, id).into()
635            }
636            LiteralKind::Boolean => match node.text {
637                "true" => leo_ast::Literal::boolean(true, span, id).into(),
638                "false" => leo_ast::Literal::boolean(false, span, id).into(),
639                _ => panic!("Can't happen"),
640            },
641            LiteralKind::Field => leo_ast::Literal::field(text(), span, id).into(),
642            LiteralKind::Group => leo_ast::Literal::group(text(), span, id).into(),
643            LiteralKind::Integer(integer_literal_kind) => {
644                let integer_type = match integer_literal_kind {
645                    IntegerLiteralKind::U8 => leo_ast::IntegerType::U8,
646                    IntegerLiteralKind::U16 => leo_ast::IntegerType::U16,
647                    IntegerLiteralKind::U32 => leo_ast::IntegerType::U32,
648                    IntegerLiteralKind::U64 => leo_ast::IntegerType::U64,
649                    IntegerLiteralKind::U128 => leo_ast::IntegerType::U128,
650                    IntegerLiteralKind::I8 => leo_ast::IntegerType::I8,
651                    IntegerLiteralKind::I16 => leo_ast::IntegerType::I16,
652                    IntegerLiteralKind::I32 => leo_ast::IntegerType::I32,
653                    IntegerLiteralKind::I64 => leo_ast::IntegerType::I64,
654                    IntegerLiteralKind::I128 => leo_ast::IntegerType::I128,
655                };
656                leo_ast::Literal::integer(integer_type, text(), span, id).into()
657            }
658            LiteralKind::None => leo_ast::Literal::none(span, id).into(),
659            LiteralKind::Scalar => leo_ast::Literal::scalar(text(), span, id).into(),
660            LiteralKind::Unsuffixed => leo_ast::Literal::unsuffixed(text(), span, id).into(),
661            LiteralKind::String => leo_ast::Literal::string(text(), span, id).into(),
662        },
663        ExpressionKind::Locator => {
664            let text = node.children[0].text;
665
666            // Parse the locator string in format "some_program.aleo/some_name"
667            if let Some((program_part, name_part)) = text.split_once(".aleo/") {
668                // Create the program identifier
669                let program_name_symbol = Symbol::intern(program_part);
670                let program_name_span = Span { lo: node.span.lo, hi: node.span.lo + program_part.len() as u32 };
671                let program_name =
672                    leo_ast::Identifier { name: program_name_symbol, span: program_name_span, id: builder.next_id() };
673
674                // Create the network identifier (always "aleo")
675                let network_start = node.span.lo + program_part.len() as u32 + 1; // +1 for the dot
676                let network_span = Span {
677                    lo: network_start,
678                    hi: network_start + 4, // "aleo" is 4 characters
679                };
680                let network =
681                    leo_ast::Identifier { name: Symbol::intern("aleo"), span: network_span, id: builder.next_id() };
682
683                // Create the program ID
684                let program_id = leo_ast::ProgramId { name: program_name, network };
685
686                // Create the resource name
687                let name_symbol = Symbol::intern(name_part);
688
689                leo_ast::LocatorExpression { program: program_id, name: name_symbol, span, id }.into()
690            } else {
691                // Invalid locator format - this should have been caught by the parser
692                handler.emit_err(ParserError::custom("Invalid locator format", span));
693                leo_ast::ErrExpression { span, id }.into()
694            }
695        }
696        ExpressionKind::MemberAccess => {
697            let [struct_, _dot, name] = &node.children[..] else {
698                panic!("Can't happen.");
699            };
700            let inner = to_expression(struct_, builder, handler)?;
701            let name = to_identifier(name, builder);
702
703            leo_ast::MemberAccess { inner, name, span, id }.into()
704        }
705        ExpressionKind::MethodCall => {
706            let [expr, _dot, name, ..] = &node.children[..] else {
707                panic!("Can't happen");
708            };
709
710            let name = to_identifier(name, builder);
711            let receiver = to_expression(expr, builder, handler)?;
712
713            let mut args = node.children[3..]
714                .iter()
715                .filter(|child| matches!(child.kind, SyntaxKind::Expression(..)))
716                .map(|child| to_expression(child, builder, handler))
717                .collect::<Result<Vec<_>>>()?;
718
719            if let (true, Some(op)) = (args.is_empty(), leo_ast::UnaryOperation::from_symbol(name.name)) {
720                // Found an unary operator and the argument list is empty.
721                leo_ast::UnaryExpression { span, op, receiver, id }.into()
722            } else if let (1, Some(op)) = (args.len(), leo_ast::BinaryOperation::from_symbol(name.name)) {
723                // Found a binary operator and the argument list contains a single argument.
724                leo_ast::BinaryExpression { span, op, left: receiver, right: args.pop().unwrap(), id }.into()
725            } else if let (2, Some(name @ sym::_signature_verify)) =
726                (args.len(), leo_ast::Intrinsic::convert_path_symbols(sym::signature, name.name))
727            {
728                leo_ast::IntrinsicExpression {
729                    name,
730                    type_parameters: Vec::new(),
731                    arguments: std::iter::once(receiver).chain(args).collect(),
732                    span,
733                    id,
734                }
735                .into()
736            } else if let (0, Some(name @ sym::_future_await)) =
737                (args.len(), leo_ast::Intrinsic::convert_path_symbols(sym::Future, name.name))
738            {
739                leo_ast::IntrinsicExpression {
740                    name,
741                    type_parameters: Vec::new(),
742                    arguments: vec![receiver],
743                    span,
744                    id: builder.next_id(),
745                }
746                .into()
747            } else if let (0, Some(name @ sym::_optional_unwrap)) =
748                (args.len(), leo_ast::Intrinsic::convert_path_symbols(sym::Optional, name.name))
749            {
750                leo_ast::IntrinsicExpression {
751                    name,
752                    type_parameters: Vec::new(),
753                    arguments: vec![receiver],
754                    span,
755                    id: builder.next_id(),
756                }
757                .into()
758            } else if let (1, Some(name @ sym::_optional_unwrap_or)) =
759                (args.len(), leo_ast::Intrinsic::convert_path_symbols(sym::Optional, name.name))
760            {
761                leo_ast::IntrinsicExpression {
762                    name,
763                    type_parameters: Vec::new(),
764                    arguments: std::iter::once(receiver).chain(args).collect(),
765                    span,
766                    id: builder.next_id(),
767                }
768                .into()
769            } else if let (1, sym::get) = (args.len(), name.name) {
770                leo_ast::IntrinsicExpression {
771                    name: Symbol::intern("__unresolved_get"),
772                    type_parameters: Vec::new(),
773                    arguments: std::iter::once(receiver).chain(args).collect(),
774                    span,
775                    id: builder.next_id(),
776                }
777                .into()
778            } else if let (2, sym::set) = (args.len(), name.name) {
779                leo_ast::IntrinsicExpression {
780                    name: Symbol::intern("__unresolved_set"),
781                    type_parameters: Vec::new(),
782                    arguments: std::iter::once(receiver).chain(args).collect(),
783                    span,
784                    id,
785                }
786                .into()
787            } else if let (1, Some(name @ sym::_vector_push)) =
788                (args.len(), leo_ast::Intrinsic::convert_path_symbols(sym::Vector, name.name))
789            {
790                leo_ast::IntrinsicExpression {
791                    name,
792                    type_parameters: Vec::new(),
793                    arguments: std::iter::once(receiver).chain(args).collect(),
794                    span,
795                    id: builder.next_id(),
796                }
797                .into()
798            } else if let (0, Some(name @ sym::_vector_len)) =
799                (args.len(), leo_ast::Intrinsic::convert_path_symbols(sym::Vector, name.name))
800            {
801                leo_ast::IntrinsicExpression {
802                    name,
803                    type_parameters: Vec::new(),
804                    arguments: vec![receiver],
805                    span,
806                    id: builder.next_id(),
807                }
808                .into()
809            } else if let (0, Some(name @ sym::_vector_pop)) =
810                (args.len(), leo_ast::Intrinsic::convert_path_symbols(sym::Vector, name.name))
811            {
812                leo_ast::IntrinsicExpression {
813                    name,
814                    type_parameters: Vec::new(),
815                    arguments: vec![receiver],
816                    span,
817                    id: builder.next_id(),
818                }
819                .into()
820            } else if let (0, Some(name @ sym::_vector_clear)) =
821                (args.len(), leo_ast::Intrinsic::convert_path_symbols(sym::Vector, name.name))
822            {
823                leo_ast::IntrinsicExpression {
824                    name,
825                    type_parameters: Vec::new(),
826                    arguments: vec![receiver],
827                    span,
828                    id: builder.next_id(),
829                }
830                .into()
831            } else if let (1, Some(name @ sym::_vector_swap_remove)) =
832                (args.len(), leo_ast::Intrinsic::convert_path_symbols(sym::Vector, name.name))
833            {
834                leo_ast::IntrinsicExpression {
835                    name,
836                    type_parameters: Vec::new(),
837                    arguments: std::iter::once(receiver).chain(args).collect(),
838                    span,
839                    id: builder.next_id(),
840                }
841                .into()
842            } else {
843                // Attempt to parse the method call as a mapping operation.
844                match (args.len(), leo_ast::Intrinsic::convert_path_symbols(sym::Mapping, name.name)) {
845                    (2, Some(name @ sym::_mapping_get_or_use))
846                    | (1, Some(name @ sym::_mapping_remove))
847                    | (1, Some(name @ sym::_mapping_contains)) => {
848                        // Found an instance of `<mapping>.get`, `<mapping>.get_or_use`, `<mapping>.set`, `<mapping>.remove`, or `<mapping>.contains`.
849                        leo_ast::IntrinsicExpression {
850                            name,
851                            type_parameters: Vec::new(),
852                            arguments: std::iter::once(receiver).chain(args).collect(),
853                            span,
854                            id: builder.next_id(),
855                        }
856                        .into()
857                    }
858                    _ => {
859                        // Either an invalid unary/binary operator, or more arguments given.
860                        handler.emit_err(ParserError::invalid_method_call(receiver, name, args.len(), span));
861                        leo_ast::ErrExpression { span, id: builder.next_id() }.into()
862                    }
863                }
864            }
865        }
866        ExpressionKind::Parenthesized => {
867            let [_left, expr, _right] = &node.children[..] else {
868                panic!("Can't happen");
869            };
870            to_expression(expr, builder, handler)?
871        }
872        ExpressionKind::Repeat => {
873            let [_left, expr, _s, count, _right] = &node.children[..] else {
874                panic!("Can't happen");
875            };
876            let expr = to_expression(expr, builder, handler)?;
877            let count = to_expression(count, builder, handler)?;
878            leo_ast::RepeatExpression { expr, count, span, id }.into()
879        }
880        ExpressionKind::SpecialAccess => {
881            let [qualifier, _dot, name] = &node.children[..] else {
882                panic!("Can't happen");
883            };
884
885            let name = match (qualifier.text, name.text) {
886                ("self", "address") => Some(sym::_self_address),
887                ("self", "caller") => Some(sym::_self_caller),
888                ("self", "checksum") => Some(sym::_self_checksum),
889                ("self", "edition") => Some(sym::_self_edition),
890                ("self", "id") => Some(sym::_self_id),
891                ("self", "program_owner") => Some(sym::_self_program_owner),
892                ("self", "signer") => Some(sym::_self_signer),
893                ("block", "height") => Some(sym::_block_height),
894                ("block", "timestamp") => Some(sym::_block_timestamp),
895                ("network", "id") => Some(sym::_network_id),
896                _ => {
897                    handler.emit_err(ParserError::custom("Unsupported special access", node.span));
898                    None
899                }
900            };
901
902            if let Some(name) = name {
903                leo_ast::IntrinsicExpression { name, type_parameters: vec![], arguments: vec![], span, id }.into()
904            } else {
905                leo_ast::ErrExpression { span, id: builder.next_id() }.into()
906            }
907        }
908
909        ExpressionKind::Struct => {
910            let name = &node.children[0];
911            let mut members = Vec::new();
912            for initializer in node.children.iter().filter(|node| node.kind == SyntaxKind::StructMemberInitializer) {
913                let (init_name, expression) = match &initializer.children[..] {
914                    [init_name] => (init_name, None),
915                    [init_name, _c, expr] => (init_name, Some(to_expression(expr, builder, handler)?)),
916                    _ => panic!("Can't happen"),
917                };
918                let init_name = to_identifier(init_name, builder);
919
920                members.push(leo_ast::StructVariableInitializer {
921                    identifier: init_name,
922                    expression,
923                    span: initializer.span,
924                    id: builder.next_id(),
925                });
926            }
927
928            let mut const_arguments = Vec::new();
929            let maybe_const_params = &node.children[1];
930            if maybe_const_params.kind == SyntaxKind::ConstArgumentList {
931                for argument in &maybe_const_params.children {
932                    match argument.kind {
933                        SyntaxKind::Type(..) => {
934                            handler.emit_err(ParserError::custom(
935                                "Struct expressions may only have constant expressions as generic arguments",
936                                argument.span,
937                            ));
938                        }
939                        SyntaxKind::Expression(..) => {
940                            let expr = to_expression(argument, builder, handler)?;
941                            const_arguments.push(expr);
942                        }
943                        _ => {}
944                    }
945                }
946            }
947
948            let mut identifiers = path_to_parts(name, builder);
949            let identifier = identifiers.pop().unwrap();
950            let path = leo_ast::Path::new(identifiers, identifier, false, None, name.span, builder.next_id());
951
952            leo_ast::StructExpression { path, const_arguments, members, span, id }.into()
953        }
954        ExpressionKind::Ternary => {
955            let [cond, _q, if_, _c, then] = &node.children[..] else {
956                panic!("Can't happen");
957            };
958            let condition = to_expression(cond, builder, handler)?;
959            let if_true = to_expression(if_, builder, handler)?;
960            let if_false = to_expression(then, builder, handler)?;
961            leo_ast::TernaryExpression { condition, if_true, if_false, span, id }.into()
962        }
963        ExpressionKind::Tuple => {
964            let elements = node
965                .children
966                .iter()
967                .filter(|expr| matches!(expr.kind, SyntaxKind::Expression(..)))
968                .map(|expr| to_expression(expr, builder, handler))
969                .collect::<Result<Vec<_>>>()?;
970            leo_ast::TupleExpression { elements, span, id }.into()
971        }
972        ExpressionKind::TupleAccess => {
973            let [expr, _dot, integer] = &node.children[..] else {
974                panic!("Can't happen");
975            };
976
977            let tuple = to_expression(expr, builder, handler)?;
978            let integer_text = integer.text.replace("_", "");
979            let value: usize = integer_text.parse().expect("Integer should parse.");
980            let index = value.into();
981
982            leo_ast::TupleAccess { tuple, index, span, id }.into()
983        }
984        ExpressionKind::Unary => {
985            let [op, operand] = &node.children[..] else {
986                panic!("Can't happen");
987            };
988            let mut operand_expression = to_expression(operand, builder, handler)?;
989            let op_variant = match op.text {
990                "!" => leo_ast::UnaryOperation::Not,
991                "-" => leo_ast::UnaryOperation::Negate,
992                _ => panic!("Can't happen"),
993            };
994            if op_variant == leo_ast::UnaryOperation::Negate {
995                use leo_ast::LiteralVariant::*;
996                if let Expression::Literal(leo_ast::Literal {
997                    variant: Integer(_, string) | Field(string) | Group(string) | Scalar(string),
998                    span,
999                    ..
1000                }) = &mut operand_expression
1001                    && !string.starts_with('-')
1002                {
1003                    // The operation was a negation and the literal was not already negative, so fold it in
1004                    // and discard the unary expression.
1005                    string.insert(0, '-');
1006                    *span = op.span + operand.span;
1007                    return Ok(operand_expression);
1008                }
1009            }
1010            leo_ast::UnaryExpression { receiver: operand_expression, op: op_variant, span, id }.into()
1011        }
1012        ExpressionKind::Unit => leo_ast::UnitExpression { span, id }.into(),
1013    };
1014
1015    Ok(value)
1016}
1017
1018fn to_const_parameters(
1019    node: &SyntaxNode<'_>,
1020    builder: &NodeBuilder,
1021    handler: &Handler,
1022) -> Result<Vec<leo_ast::ConstParameter>> {
1023    assert_eq!(node.kind, SyntaxKind::ConstParameterList);
1024
1025    node.children
1026        .iter()
1027        .filter(|child| matches!(child.kind, SyntaxKind::ConstParameter))
1028        .map(|child| {
1029            let [id, _c, type_] = &child.children[..] else {
1030                panic!("Can't happen");
1031            };
1032
1033            Ok(leo_ast::ConstParameter {
1034                identifier: to_identifier(id, builder),
1035                type_: to_type(type_, builder, handler)?,
1036                span: child.span,
1037                id: builder.next_id(),
1038            })
1039        })
1040        .collect::<Result<Vec<_>>>()
1041}
1042
1043fn to_annotation(node: &SyntaxNode<'_>, builder: &NodeBuilder) -> Result<leo_ast::Annotation> {
1044    assert_eq!(node.kind, SyntaxKind::Annotation);
1045    let name = to_identifier(&node.children[1], builder);
1046
1047    let mut map = IndexMap::new();
1048    node.children.get(2).inspect(|list| {
1049        for member in list.children.iter() {
1050            if member.kind != SyntaxKind::AnnotationMember {
1051                continue;
1052            }
1053
1054            let [key, _assign, value] = &member.children[..] else {
1055                panic!("Can't happen");
1056            };
1057            let key = Symbol::intern(key.text);
1058            // Get rid of the delimiting double quotes on the string.
1059            let value = value.text[1..value.text.len() - 1].to_string();
1060            map.insert(key, value);
1061        }
1062    });
1063    Ok(leo_ast::Annotation { identifier: name, map, span: node.span, id: builder.next_id() })
1064}
1065
1066fn to_function(node: &SyntaxNode<'_>, builder: &NodeBuilder, handler: &Handler) -> Result<leo_ast::Function> {
1067    assert_eq!(node.kind, SyntaxKind::Function);
1068
1069    let annotations = node
1070        .children
1071        .iter()
1072        .filter(|child| matches!(child.kind, SyntaxKind::Annotation))
1073        .map(|child| to_annotation(child, builder))
1074        .collect::<Result<Vec<_>>>()?;
1075    let async_index = annotations.len();
1076    let is_async = node.children[async_index].text == "async";
1077
1078    let function_variant_index = if is_async { async_index + 1 } else { async_index };
1079
1080    // The behavior here matches the old parser - "inline" and "script" may be marked async,
1081    // but async is ignored. Presumably we should fix this but it's theoretically a breaking change.
1082    let variant = match (is_async, node.children[function_variant_index].text) {
1083        (true, "function") => leo_ast::Variant::AsyncFunction,
1084        (false, "function") => leo_ast::Variant::Function,
1085        (_, "inline") => leo_ast::Variant::Inline,
1086        (_, "script") => leo_ast::Variant::Script,
1087        (true, "transition") => leo_ast::Variant::AsyncTransition,
1088        (false, "transition") => leo_ast::Variant::Transition,
1089        _ => panic!("Can't happen"),
1090    };
1091
1092    let name = &node.children[function_variant_index + 1];
1093    let id = to_identifier(name, builder);
1094
1095    let mut const_parameters = Vec::new();
1096    if let Some(const_param_list) =
1097        node.children.iter().find(|child| matches!(child.kind, SyntaxKind::ConstParameterList))
1098    {
1099        const_parameters = to_const_parameters(const_param_list, builder, handler)?;
1100    }
1101
1102    let parameter_list = node.children.iter().find(|child| matches!(child.kind, SyntaxKind::ParameterList)).unwrap();
1103    let input = parameter_list
1104        .children
1105        .iter()
1106        .filter(|child| matches!(child.kind, SyntaxKind::Parameter))
1107        .map(|child| {
1108            let mode = to_mode(&child.children[0]);
1109            let index = if mode == leo_ast::Mode::None { 0 } else { 1 };
1110            let [name, _c, type_] = &child.children[index..] else {
1111                panic!("Can't happen");
1112            };
1113            Ok(leo_ast::Input {
1114                identifier: to_identifier(name, builder),
1115                mode,
1116                type_: to_type(type_, builder, handler)?,
1117                span: child.span,
1118                id: builder.next_id(),
1119            })
1120        })
1121        .collect::<Result<Vec<_>>>()?;
1122
1123    let [.., maybe_outputs, block] = &node.children[..] else {
1124        panic!("Can't happen");
1125    };
1126    let block = to_block(block, builder, handler)?;
1127
1128    let to_output = |node: &SyntaxNode<'_>| -> Result<leo_ast::Output> {
1129        let mode = to_mode(&node.children[0]);
1130        let type_ = node.children.last().unwrap();
1131
1132        Ok(leo_ast::Output { mode, type_: to_type(type_, builder, handler)?, span: node.span, id: builder.next_id() })
1133    };
1134
1135    let output = match maybe_outputs.kind {
1136        SyntaxKind::FunctionOutput => {
1137            let output = to_output(maybe_outputs)?;
1138            vec![output]
1139        }
1140        SyntaxKind::FunctionOutputs => maybe_outputs
1141            .children
1142            .iter()
1143            .filter(|child| matches!(child.kind, SyntaxKind::FunctionOutput))
1144            .map(|child| to_output(child))
1145            .collect::<Result<Vec<_>>>()?,
1146        _ => Vec::new(),
1147    };
1148
1149    Ok(leo_ast::Function::new(
1150        annotations,
1151        variant,
1152        id,
1153        const_parameters,
1154        input,
1155        output,
1156        block,
1157        node.span,
1158        builder.next_id(),
1159    ))
1160}
1161
1162fn to_composite(node: &SyntaxNode<'_>, builder: &NodeBuilder, handler: &Handler) -> Result<leo_ast::Composite> {
1163    assert_eq!(node.kind, SyntaxKind::StructDeclaration);
1164
1165    let [struct_or_record, i, .., members] = &node.children[..] else {
1166        panic!("Can't happen");
1167    };
1168
1169    let members = members
1170        .children
1171        .iter()
1172        .filter(|child| matches!(child.kind, SyntaxKind::StructMemberDeclaration))
1173        .map(|child| {
1174            let (mode, ident, type_) = match &child.children[..] {
1175                [ident, _c, type_] => (leo_ast::Mode::None, ident, type_),
1176                [privacy, ident, _c, type_] => (to_mode(privacy), ident, type_),
1177                _ => panic!("Can't happen"),
1178            };
1179
1180            Ok(leo_ast::Member {
1181                mode,
1182                identifier: to_identifier(ident, builder),
1183                type_: to_type(type_, builder, handler)?,
1184                span: child.span,
1185                id: builder.next_id(),
1186            })
1187        })
1188        .collect::<Result<Vec<_>>>()?;
1189
1190    let mut const_parameters = Vec::new();
1191    if let Some(const_param_list) =
1192        node.children.iter().find(|child| matches!(child.kind, SyntaxKind::ConstParameterList))
1193    {
1194        const_parameters = to_const_parameters(const_param_list, builder, handler)?;
1195    }
1196
1197    Ok(leo_ast::Composite {
1198        identifier: to_identifier(i, builder),
1199        const_parameters,
1200        members,
1201        external: None,
1202        is_record: struct_or_record.text == "record",
1203        span: node.span,
1204        id: builder.next_id(),
1205    })
1206}
1207
1208fn to_global_const(
1209    node: &SyntaxNode<'_>,
1210    builder: &NodeBuilder,
1211    handler: &Handler,
1212) -> Result<leo_ast::ConstDeclaration> {
1213    assert_eq!(node.kind, SyntaxKind::GlobalConst);
1214
1215    let [_l, ident, _colon, type_, _a, expr, _s] = &node.children[..] else {
1216        panic!("Can't happen");
1217    };
1218
1219    Ok(leo_ast::ConstDeclaration {
1220        place: to_identifier(ident, builder),
1221        type_: to_type(type_, builder, handler)?,
1222        value: to_expression(expr, builder, handler)?,
1223        span: node.span,
1224        id: builder.next_id(),
1225    })
1226}
1227
1228fn to_constructor(node: &SyntaxNode<'_>, builder: &NodeBuilder, handler: &Handler) -> Result<leo_ast::Constructor> {
1229    assert_eq!(node.kind, SyntaxKind::Constructor);
1230    let annotations = node
1231        .children
1232        .iter()
1233        .filter(|child| matches!(child.kind, SyntaxKind::Annotation))
1234        .map(|child| to_annotation(child, builder))
1235        .collect::<Result<Vec<_>>>()?;
1236    let block = to_block(node.children.last().unwrap(), builder, handler)?;
1237
1238    Ok(leo_ast::Constructor { annotations, block, span: node.span, id: builder.next_id() })
1239}
1240
1241fn to_mapping(node: &SyntaxNode<'_>, builder: &NodeBuilder, handler: &Handler) -> Result<leo_ast::Mapping> {
1242    assert_eq!(node.kind, SyntaxKind::Mapping);
1243
1244    let [_mapping, name, _colon, key_type, _arrow, value_type, _s] = &node.children[..] else {
1245        panic!("Can't happen");
1246    };
1247
1248    Ok(leo_ast::Mapping {
1249        identifier: to_identifier(name, builder),
1250        key_type: to_type(key_type, builder, handler)?,
1251        value_type: to_type(value_type, builder, handler)?,
1252        span: node.span,
1253        id: builder.next_id(),
1254    })
1255}
1256
1257fn to_storage_variable(
1258    node: &SyntaxNode<'_>,
1259    builder: &NodeBuilder,
1260    handler: &Handler,
1261) -> Result<leo_ast::StorageVariable> {
1262    assert_eq!(node.kind, SyntaxKind::Storage);
1263
1264    let [_storage, name, _colon, type_, _s] = &node.children[..] else {
1265        panic!("Can't happen");
1266    };
1267
1268    Ok(leo_ast::StorageVariable {
1269        identifier: to_identifier(name, builder),
1270        type_: to_type(type_, builder, handler)?,
1271        span: node.span,
1272        id: builder.next_id(),
1273    })
1274}
1275
1276pub fn to_module(
1277    node: &SyntaxNode<'_>,
1278    builder: &NodeBuilder,
1279    program_name: Symbol,
1280    path: Vec<Symbol>,
1281    handler: &Handler,
1282) -> Result<leo_ast::Module> {
1283    assert_eq!(node.kind, SyntaxKind::ModuleContents);
1284
1285    let mut functions = node
1286        .children
1287        .iter()
1288        .filter(|child| matches!(child.kind, SyntaxKind::Function))
1289        .map(|child| {
1290            let function = to_function(child, builder, handler)?;
1291            Ok((function.identifier.name, function))
1292        })
1293        .collect::<Result<Vec<_>>>()?;
1294    // Passes like type checking expect transitions to come first.
1295    // Irrelevant for modules at the moment.
1296    functions.sort_by_key(|func| if func.1.variant.is_transition() { 0u8 } else { 1u8 });
1297
1298    let structs = node
1299        .children
1300        .iter()
1301        .filter(|child| matches!(child.kind, SyntaxKind::StructDeclaration))
1302        .map(|child| {
1303            let composite = to_composite(child, builder, handler)?;
1304            Ok((composite.identifier.name, composite))
1305        })
1306        .collect::<Result<Vec<_>>>()?;
1307
1308    let consts = node
1309        .children
1310        .iter()
1311        .filter(|child| matches!(child.kind, SyntaxKind::GlobalConst))
1312        .map(|child| {
1313            let global_const = to_global_const(child, builder, handler)?;
1314            Ok((global_const.place.name, global_const))
1315        })
1316        .collect::<Result<Vec<_>>>()?;
1317
1318    Ok(leo_ast::Module { program_name, path, consts, structs, functions })
1319}
1320
1321pub fn to_main(node: &SyntaxNode<'_>, builder: &NodeBuilder, handler: &Handler) -> Result<leo_ast::Program> {
1322    assert_eq!(node.kind, SyntaxKind::MainContents);
1323
1324    let imports = node
1325        .children
1326        .iter()
1327        .filter(|child| matches!(child.kind, SyntaxKind::Import))
1328        .map(|child| {
1329            let name = Symbol::intern(child.children[1].text.strip_suffix(".aleo").unwrap());
1330            (name, (leo_ast::Program::default(), child.span))
1331        })
1332        .collect::<IndexMap<_, _>>();
1333
1334    let program_node = node.children.last().unwrap();
1335
1336    let mut functions = program_node
1337        .children
1338        .iter()
1339        .filter(|child| matches!(child.kind, SyntaxKind::Function))
1340        .map(|child| {
1341            let function = to_function(child, builder, handler)?;
1342            Ok((function.identifier.name, function))
1343        })
1344        .collect::<Result<Vec<_>>>()?;
1345    // Passes like type checking expect transitions to come first.
1346    functions.sort_by_key(|func| if func.1.variant.is_transition() { 0u8 } else { 1u8 });
1347
1348    let structs = program_node
1349        .children
1350        .iter()
1351        .filter(|child| matches!(child.kind, SyntaxKind::StructDeclaration))
1352        .map(|child| {
1353            let composite = to_composite(child, builder, handler)?;
1354            Ok((composite.identifier.name, composite))
1355        })
1356        .collect::<Result<Vec<_>>>()?;
1357
1358    let consts = program_node
1359        .children
1360        .iter()
1361        .filter(|child| matches!(child.kind, SyntaxKind::GlobalConst))
1362        .map(|child| {
1363            let global_const = to_global_const(child, builder, handler)?;
1364            Ok((global_const.place.name, global_const))
1365        })
1366        .collect::<Result<Vec<_>>>()?;
1367
1368    let mappings = program_node
1369        .children
1370        .iter()
1371        .filter(|child| matches!(child.kind, SyntaxKind::Mapping))
1372        .map(|child| {
1373            let mapping = to_mapping(child, builder, handler)?;
1374            Ok((mapping.identifier.name, mapping))
1375        })
1376        .collect::<Result<Vec<_>>>()?;
1377
1378    let storage_variables = program_node
1379        .children
1380        .iter()
1381        .filter(|child| matches!(child.kind, SyntaxKind::Storage))
1382        .map(|child| {
1383            let storage_variable = to_storage_variable(child, builder, handler)?;
1384            Ok((storage_variable.identifier.name, storage_variable))
1385        })
1386        .collect::<Result<Vec<_>>>()?;
1387
1388    // This follows the behavior of the old parser - if multiple constructors are
1389    // present, we silently throw out all but the last. Probably this should be
1390    // changed but it would theoretically be a breaking change.
1391    let mut constructors = program_node
1392        .children
1393        .iter()
1394        .filter(|child| matches!(child.kind, SyntaxKind::Constructor))
1395        .map(|child| to_constructor(child, builder, handler))
1396        .collect::<Result<Vec<_>>>()?;
1397
1398    if let Some(extra) = constructors.get(1) {
1399        return Err(TypeCheckerError::custom("A program can only have one constructor.", extra.span).into());
1400    }
1401
1402    let program_id_node = &program_node.children[1];
1403    let program_name_text = program_id_node.text.strip_suffix(".aleo").unwrap();
1404    let program_name_symbol = Symbol::intern(program_name_text);
1405    let hi = program_id_node.span.lo + program_name_text.len() as u32;
1406    let program_id = leo_ast::ProgramId {
1407        name: leo_ast::Identifier {
1408            name: program_name_symbol,
1409            span: Span { lo: program_id_node.span.lo, hi },
1410            id: builder.next_id(),
1411        },
1412        network: leo_ast::Identifier { name: sym::aleo, span: Span { lo: hi + 1, hi: hi + 5 }, id: builder.next_id() },
1413    };
1414    let program_scope = leo_ast::ProgramScope {
1415        program_id,
1416        consts,
1417        structs,
1418        mappings,
1419        storage_variables,
1420        functions,
1421        constructor: constructors.pop(),
1422        span: node.span,
1423    };
1424    Ok(leo_ast::Program {
1425        modules: Default::default(),
1426        imports,
1427        stubs: Default::default(),
1428        program_scopes: std::iter::once((program_name_symbol, program_scope)).collect(),
1429    })
1430}