1use itertools::Itertools as _;
31use snarkvm::prelude::{Address, Signature, TestnetV0};
32
33use leo_ast::{NetworkName, NodeBuilder, NodeID, TypeInterner};
34use leo_errors::{Handler, Result};
35use leo_parser_rowan::{SyntaxElement, SyntaxKind, SyntaxKind::*, SyntaxNode, SyntaxToken, TextRange};
36use leo_span::{
37 Span,
38 Symbol,
39 source_map::{FileName, SourceFile},
40 sym,
41};
42
43type ConstArgList = (Vec<(leo_ast::TypeKind, Span)>, Vec<leo_ast::Expression>);
45
46type AnnotatedTypes = Vec<(leo_ast::Mode, leo_ast::TypeKind, Span)>;
48
49type Parents = Vec<(Span, leo_ast::TypeKind)>;
51
52struct ConversionContext<'a> {
58 handler: &'a Handler,
59 builder: &'a NodeBuilder,
60 interner: &'a TypeInterner,
61 start_pos: u32,
63 suppress_cascade: bool,
69}
70
71impl<'a> ConversionContext<'a> {
72 fn new(
74 handler: &'a Handler,
75 builder: &'a NodeBuilder,
76 interner: &'a TypeInterner,
77 start_pos: u32,
78 suppress_cascade: bool,
79 ) -> Self {
80 Self { handler, builder, interner, start_pos, suppress_cascade }
81 }
82
83 fn emit_unexpected_str(&self, expected: &str, found: impl std::fmt::Display, span: Span) {
85 if !self.suppress_cascade {
86 self.handler.emit_err(crate::errors::unexpected_str(expected, found, span));
87 }
88 }
89
90 fn to_span(&self, node: &SyntaxNode) -> Span {
96 let range = node.text_range();
97 Span::new(u32::from(range.start()) + self.start_pos, u32::from(range.end()) + self.start_pos)
98 }
99
100 fn token_span(&self, token: &SyntaxToken) -> Span {
102 let range = token.text_range();
103 Span::new(u32::from(range.start()) + self.start_pos, u32::from(range.end()) + self.start_pos)
104 }
105
106 fn non_trivia_span(&self, node: &SyntaxNode) -> Span {
109 let start = first_non_trivia_token(node).map(|t| t.text_range().start()).unwrap_or(node.text_range().start());
110 let end = node.text_range().end();
111 Span::new(u32::from(start) + self.start_pos, u32::from(end) + self.start_pos)
112 }
113
114 fn trimmed_span(&self, node: &SyntaxNode) -> Span {
118 let start = first_non_trivia_token(node).map(|t| t.text_range().start()).unwrap_or(node.text_range().start());
119 let end = last_non_trivia_token(node).map(|t| t.text_range().end()).unwrap_or(node.text_range().end());
120 Span::new(u32::from(start) + self.start_pos, u32::from(end) + self.start_pos)
121 }
122
123 fn content_span(&self, node: &SyntaxNode) -> Span {
127 let mut first = node.text_range().start();
128 let mut last = node.text_range().end();
129 let mut found_first = false;
130 for elem in node.descendants_with_tokens() {
131 if let Some(t) = elem.as_token()
132 && !t.kind().is_trivia()
133 {
134 if !found_first {
135 first = t.text_range().start();
136 found_first = true;
137 }
138 last = t.text_range().end();
139 }
140 }
141 Span::new(u32::from(first) + self.start_pos, u32::from(last) + self.start_pos)
142 }
143
144 fn span_including_annotations(&self, node: &SyntaxNode, span: Span) -> Span {
146 children(node)
147 .find(|n| n.kind() == ANNOTATION)
148 .map(|ann| Span::new(self.trimmed_span(&ann).lo, span.hi))
149 .unwrap_or(span)
150 }
151
152 fn to_identifier(&self, token: &SyntaxToken) -> leo_ast::Identifier {
154 debug_assert_eq!(token.kind(), IDENT);
155 leo_ast::Identifier {
156 name: Symbol::intern(token.text()),
157 span: self.token_span(token),
158 id: self.builder.next_id(),
159 }
160 }
161
162 fn error_identifier(&self, span: Span) -> leo_ast::Identifier {
164 leo_ast::Identifier { name: Symbol::intern("_error"), span, id: self.builder.next_id() }
165 }
166
167 fn error_expression(&self, span: Span) -> leo_ast::Expression {
169 leo_ast::ErrExpression { span, id: self.builder.next_id() }.into()
170 }
171
172 fn intrinsic_expression(
174 &self,
175 name: Symbol,
176 arguments: Vec<leo_ast::Expression>,
177 span: Span,
178 ) -> leo_ast::Expression {
179 leo_ast::IntrinsicExpression {
180 name,
181 type_parameters: Vec::new(),
182 input_types: Vec::new(),
183 return_types: Vec::new(),
184 arguments,
185 span,
186 id: self.builder.next_id(),
187 }
188 .into()
189 }
190
191 fn error_block(&self, span: Span) -> leo_ast::Block {
193 leo_ast::Block { statements: Vec::new(), span, id: self.builder.next_id() }
194 }
195
196 fn validate_hexbin_literal(&self, text: &str, suffix_len: u32, span: Span) {
199 if text.starts_with("0x") || text.starts_with("0o") || text.starts_with("0b") {
200 self.handler.emit_err(crate::errors::hexbin_literal_nonintegers(Span::new(span.lo, span.hi - suffix_len)));
201 }
202 }
203
204 fn require_ident(&self, node: &SyntaxNode, label: &str) -> leo_ast::Identifier {
206 let span = self.to_span(node);
207 match tokens(node).find(|t| t.kind() == IDENT) {
208 Some(token) => self.to_identifier(&token),
209 None => {
210 self.emit_unexpected_str(label, node.text(), span);
211 self.error_identifier(span)
212 }
213 }
214 }
215
216 fn require_expression(&self, node: &SyntaxNode, label: &str) -> Result<leo_ast::Expression> {
218 match children(node).find(|n| n.kind().is_expression()) {
219 Some(expr_node) => self.to_expression(&expr_node),
220 None => {
221 let span = self.to_span(node);
222 self.emit_unexpected_str(label, node.text(), span);
223 Ok(self.error_expression(span))
224 }
225 }
226 }
227
228 fn validate_identifier(&self, ident: &leo_ast::Identifier) {
230 const MAX_IDENTIFIER_LEN: usize = 31;
231 let text = ident.name.to_string();
232 if text.len() > MAX_IDENTIFIER_LEN {
233 self.handler.emit_err(crate::errors::identifier_too_long(
234 &text,
235 text.len(),
236 MAX_IDENTIFIER_LEN,
237 ident.span,
238 ));
239 }
240 if text.contains("__") {
241 self.handler.emit_err(crate::errors::identifier_cannot_contain_double_underscore(&text, ident.span));
242 }
243 }
244
245 fn validate_definition_identifier(&self, ident: &leo_ast::Identifier) {
249 if ident.name == Symbol::intern("_error") {
251 return;
252 }
253 self.validate_identifier(ident);
254 let text = ident.name.to_string();
255 if text.starts_with('_') {
256 self.handler.emit_err(crate::errors::identifier_cannot_start_with_underscore(ident.span));
257 }
258 if leo_parser_rowan::is_keyword(&text) {
259 self.emit_unexpected_str("an identifier", &text, ident.span);
260 }
261 }
262
263 fn to_type(&self, node: &SyntaxNode) -> Result<leo_ast::TypeKind> {
269 let ty = match node.kind() {
270 TYPE_PRIMITIVE => self.type_primitive_to_type(node)?,
271 TYPE_LOCATOR => self.type_locator_to_type(node)?,
272 TYPE_PATH => self.type_path_to_type(node)?,
273 TYPE_ARRAY => self.type_array_to_type(node)?,
274 TYPE_VECTOR => self.type_vector_to_type(node)?,
275 TYPE_TUPLE => self.type_tuple_to_type(node)?,
276 TYPE_OPTIONAL => self.type_optional_to_type(node)?,
277 TYPE_FINAL => self.type_final_to_type(node)?,
278 TYPE_MAPPING => self.type_mapping_to_type(node)?,
279 TYPE_DYN_RECORD => leo_ast::TypeKind::DynRecord,
280 ERROR => {
281 leo_ast::TypeKind::Err
283 }
284 kind => panic!("unexpected type node kind: {:?}", kind),
285 };
286 Ok(ty)
287 }
288
289 fn to_type_repr(&self, node: &SyntaxNode) -> Result<leo_ast::TypeNode> {
291 let span = self.to_span(node);
292 let kind = self.to_type(node)?;
293 Ok(leo_ast::TypeNode::new(self.interner, kind, span))
294 }
295
296 fn require_type_repr(&self, node: &SyntaxNode, label: &str) -> Result<leo_ast::TypeNode> {
298 match children(node).find(|n| n.kind().is_type()) {
299 Some(type_node) => self.to_type_repr(&type_node),
300 None => {
301 let span = self.to_span(node);
302 self.emit_unexpected_str(label, node.text(), span);
303 Ok(leo_ast::TypeNode::new(self.interner, leo_ast::TypeKind::Err, span))
304 }
305 }
306 }
307
308 fn type_primitive_to_type(&self, node: &SyntaxNode) -> Result<leo_ast::TypeKind> {
310 debug_assert_eq!(node.kind(), TYPE_PRIMITIVE);
311 let prim = tokens(node)
312 .next()
313 .and_then(|t| keyword_to_primitive_type(t.kind()))
314 .expect("TYPE_PRIMITIVE should contain a type keyword");
315 Ok(prim)
316 }
317
318 fn type_locator_to_type(&self, node: &SyntaxNode) -> Result<leo_ast::TypeKind> {
322 debug_assert_eq!(node.kind(), TYPE_LOCATOR);
323
324 let all_idents: Vec<_> = tokens(node).filter(|t| t.kind() == IDENT).collect();
327 let Some(program_token) = all_idents.first() else {
328 panic!("TYPE_LOCATOR should contain at least a program IDENT: {:?}", node.text())
329 };
330
331 let kw_aleo_token =
333 tokens(node).find(|t| t.kind() == KW_ALEO).expect("TYPE_LOCATOR should contain `aleo` keyword");
334
335 let network_ident = leo_ast::Identifier {
336 name: Symbol::intern("aleo"),
337 span: self.token_span(&kw_aleo_token),
338 id: self.builder.next_id(),
339 };
340
341 let program_ident = self.to_identifier(program_token);
342 let program_id = leo_ast::ProgramId { name: program_ident, network: network_ident };
343
344 if all_idents.len() < 2 {
345 let span = self.content_span(node);
347 let path = leo_ast::Path::new(Some(program_id), Vec::new(), program_ident, span, self.builder.next_id());
348 Ok(leo_ast::CompositeType { path, const_arguments: Vec::new() }.into())
349 } else {
350 let name_token = all_idents.last().unwrap(); let qualifier: Vec<_> = all_idents[1..all_idents.len() - 1].iter().map(|t| self.to_identifier(t)).collect();
354 let type_ident = self.to_identifier(name_token);
355 let path_span = Span::new(program_id.name.span.lo, type_ident.span.hi);
356 let path = leo_ast::Path::new(Some(program_id), qualifier, type_ident, path_span, self.builder.next_id());
357 let (_type_parameters, const_arguments) = self.extract_const_arg_list(node)?;
358 Ok(leo_ast::CompositeType { path, const_arguments }.into())
359 }
360 }
361
362 fn type_path_to_type(&self, node: &SyntaxNode) -> Result<leo_ast::TypeKind> {
366 debug_assert_eq!(node.kind(), TYPE_PATH);
367
368 let mut path_components = Vec::new();
370
371 for token in tokens(node) {
373 match token.kind() {
374 IDENT => {
375 path_components.push(self.to_identifier(&token));
376 }
377 COLON_COLON | L_BRACKET | R_BRACKET | LT | GT | COMMA | INTEGER => {}
379 kind if kind.is_trivia() => {}
380 kind => panic!("unexpected token in TYPE_PATH: {:?}", kind),
381 }
382 }
383
384 let (_type_parameters, const_arguments) = self.extract_const_arg_list(node)?;
386
387 let name = path_components.pop().expect("TYPE_PATH should have at least one identifier");
390 let path_span =
391 if let Some(first) = path_components.first() { Span::new(first.span.lo, name.span.hi) } else { name.span };
392 let path = leo_ast::Path::new(None, path_components, name, path_span, self.builder.next_id());
393 Ok(leo_ast::CompositeType { path, const_arguments }.into())
394 }
395
396 fn type_array_to_type(&self, node: &SyntaxNode) -> Result<leo_ast::TypeKind> {
398 debug_assert_eq!(node.kind(), TYPE_ARRAY);
399
400 match children(node).find(|n| n.kind().is_type()) {
401 Some(element_node) => {
402 let element_type = self.to_type(&element_node)?;
403 let length_expr = self.array_length_to_expression(node)?;
404 Ok(leo_ast::ArrayType { element_type: Box::new(element_type), length: Box::new(length_expr) }.into())
405 }
406 None => {
407 let span = self.to_span(node);
409 self.emit_unexpected_str("element type", node.text(), span);
410 Ok(leo_ast::TypeKind::Err)
411 }
412 }
413 }
414
415 fn type_vector_to_type(&self, node: &SyntaxNode) -> Result<leo_ast::TypeKind> {
417 debug_assert_eq!(node.kind(), TYPE_VECTOR);
418
419 match children(node).find(|n| n.kind().is_type()) {
420 Some(element_node) => {
421 let element_type = self.to_type(&element_node)?;
422 Ok(leo_ast::VectorType { element_type: Box::new(element_type) }.into())
423 }
424 None => {
425 let span = self.to_span(node);
428 self.emit_unexpected_str("element type", node.text(), span);
429 Ok(leo_ast::TypeKind::Err)
430 }
431 }
432 }
433
434 fn array_length_to_expression(&self, node: &SyntaxNode) -> Result<leo_ast::Expression> {
436 match children(node).find(|n| n.kind() == ARRAY_LENGTH) {
437 Some(length_node) => self.require_expression(&length_node, "array length"),
438 None => {
439 let span = self.to_span(node);
441 self.emit_unexpected_str("array length", node.text(), span);
442 Ok(self.error_expression(span))
443 }
444 }
445 }
446
447 fn integer_token_to_expression(&self, token: &SyntaxToken) -> Result<leo_ast::Expression> {
449 debug_assert_eq!(token.kind(), INTEGER);
450 let text = token.text();
451 let span = self.token_span(token);
452 let id = self.builder.next_id();
453
454 let suffixes = [
456 ("u128", leo_ast::IntegerType::U128),
457 ("u64", leo_ast::IntegerType::U64),
458 ("u32", leo_ast::IntegerType::U32),
459 ("u16", leo_ast::IntegerType::U16),
460 ("u8", leo_ast::IntegerType::U8),
461 ("i128", leo_ast::IntegerType::I128),
462 ("i64", leo_ast::IntegerType::I64),
463 ("i32", leo_ast::IntegerType::I32),
464 ("i16", leo_ast::IntegerType::I16),
465 ("i8", leo_ast::IntegerType::I8),
466 ];
467
468 for (suffix, int_type) in suffixes {
469 if text.ends_with(suffix) {
470 let value = text.strip_suffix(suffix).unwrap().to_string();
472 return Ok(leo_ast::Literal::integer(int_type, value, span, id).into());
473 }
474 }
475
476 Ok(leo_ast::Literal::unsuffixed(text.to_string(), span, id).into())
478 }
479
480 fn type_tuple_to_type(&self, node: &SyntaxNode) -> Result<leo_ast::TypeKind> {
482 debug_assert_eq!(node.kind(), TYPE_TUPLE);
483 let span = self.to_span(node);
484
485 let type_nodes: Vec<_> = children(node).filter(|n| n.kind().is_type()).collect();
486
487 if type_nodes.is_empty() {
488 return Ok(leo_ast::TypeKind::Unit);
490 }
491
492 let elements = type_nodes.iter().map(|n| self.to_type(n)).collect::<Result<Vec<_>>>()?;
493
494 if elements.len() == 1 {
495 self.handler.emit_err(crate::errors::tuple_must_have_at_least_two_elements("type", span));
497 return Ok(elements.into_iter().next().unwrap());
499 }
500
501 Ok(leo_ast::TupleType::new(elements).into())
502 }
503
504 fn type_optional_to_type(&self, node: &SyntaxNode) -> Result<leo_ast::TypeKind> {
506 debug_assert_eq!(node.kind(), TYPE_OPTIONAL);
507
508 let inner_node = children(node).find(|n| n.kind().is_type()).expect("optional type should have inner type");
509
510 let inner = self.to_type(&inner_node)?;
511 Ok(leo_ast::TypeKind::Optional(leo_ast::OptionalType { inner: Box::new(inner) }))
512 }
513
514 fn type_final_to_type(&self, node: &SyntaxNode) -> Result<leo_ast::TypeKind> {
516 debug_assert_eq!(node.kind(), TYPE_FINAL);
517
518 let type_nodes: Vec<_> = children(node).filter(|n| n.kind().is_type()).collect();
520
521 if type_nodes.is_empty() {
522 return Ok(leo_ast::FutureType::default().into());
524 }
525
526 let types = type_nodes.iter().map(|n| self.to_type(n)).collect::<Result<Vec<_>>>()?;
528
529 Ok(leo_ast::FutureType::new(types, None, true).into())
530 }
531
532 fn type_mapping_to_type(&self, node: &SyntaxNode) -> Result<leo_ast::TypeKind> {
533 debug_assert_eq!(node.kind(), TYPE_MAPPING);
534 let mut type_nodes = children(node).filter(|n| n.kind().is_type());
535 let key = type_nodes.next().map(|n| self.to_type(&n)).transpose()?.unwrap_or(leo_ast::TypeKind::Err);
536 let value = type_nodes.next().map(|n| self.to_type(&n)).transpose()?.unwrap_or(leo_ast::TypeKind::Err);
537 Ok(leo_ast::TypeKind::Mapping(leo_ast::MappingType { key: Box::new(key), value: Box::new(value) }))
538 }
539
540 fn to_expression(&self, node: &SyntaxNode) -> Result<leo_ast::Expression> {
546 let span = self.content_span(node);
547
548 let expr = match node.kind() {
549 LITERAL_FIELD => self.suffixed_literal_to_expression(node, "field", leo_ast::Literal::field)?,
550 LITERAL_GROUP => self.suffixed_literal_to_expression(node, "group", leo_ast::Literal::group)?,
551 LITERAL_SCALAR => self.suffixed_literal_to_expression(node, "scalar", leo_ast::Literal::scalar)?,
552 LITERAL_INT => self.int_literal_to_expression(node)?,
553 LITERAL_STRING => self.string_literal_to_expression(node)?,
554 LITERAL_ADDRESS => self.address_literal_to_expression(node)?,
555 LITERAL_BOOL => self.bool_literal_to_expression(node)?,
556 LITERAL_NONE => leo_ast::Literal::none(span, self.builder.next_id()).into(),
557 LITERAL_IDENT => self.identifier_literal_to_expression(node)?,
558 BINARY_EXPR => self.binary_expr_to_expression(node)?,
559 UNARY_EXPR => self.unary_expr_to_expression(node)?,
560 CALL_EXPR => self.call_expr_to_expression(node)?,
561 DYNAMIC_OP_EXPR => self.dynamic_op_expr_to_expression(node)?,
562 METHOD_CALL_EXPR => self.method_call_expr_to_expression(node)?,
563 FIELD_EXPR => self.field_expr_to_expression(node)?,
564 TUPLE_ACCESS_EXPR => self.tuple_access_expr_to_expression(node)?,
565 INDEX_EXPR => self.index_expr_to_expression(node)?,
566 CAST_EXPR => self.cast_expr_to_expression(node)?,
567 TERNARY_EXPR => self.ternary_expr_to_expression(node)?,
568 ARRAY_EXPR => self.array_expr_to_expression(node)?,
569 REPEAT_EXPR => self.repeat_expr_to_expression(node)?,
570 TUPLE_EXPR => self.tuple_expr_to_expression(node)?,
571 STRUCT_EXPR => self.struct_expr_to_expression(node)?,
572 STRUCT_LOCATOR_EXPR => self.struct_locator_expr_to_expression(node)?,
573 PATH_EXPR => self.path_expr_to_expression(node)?,
574 PATH_LOCATOR_EXPR => self.path_locator_expr_to_expression(node)?,
575 PROGRAM_REF_EXPR => self.program_ref_expr_to_expression(node)?,
576 SELF_EXPR => self.error_removed_context_keyword(node, sym::SelfLower),
577 BLOCK_KW_EXPR => self.error_removed_context_keyword(node, sym::block),
578 NETWORK_KW_EXPR => self.error_removed_context_keyword(node, sym::network),
579 SELF_UPPER_EXPR => {
580 self.handler.emit_err(crate::errors::reserved_identifier("Self", self.trimmed_span(node)));
581 self.error_expression(span)
582 }
583 PAREN_EXPR => {
584 if let Some(inner) = children(node).find(|n| n.kind().is_expression()) {
586 self.to_expression(&inner)?
587 } else {
588 self.emit_unexpected_str("expression in parentheses", node.text(), span);
590 self.error_expression(span)
591 }
592 }
593 FINAL_EXPR => self.final_expr_to_expression(node)?,
595 ROOT => {
597 if let Some(inner) = children(node).find(|n| n.kind().is_expression()) {
598 self.to_expression(&inner)?
599 } else {
600 self.error_expression(span)
602 }
603 }
604 ERROR => self.error_expression(span),
607 kind => panic!("unexpected expression kind: {:?}", kind),
608 };
609
610 Ok(expr)
611 }
612
613 fn suffixed_literal_to_expression(
615 &self,
616 node: &SyntaxNode,
617 suffix: &str,
618 ctor: fn(String, Span, leo_ast::NodeID) -> leo_ast::Literal,
619 ) -> Result<leo_ast::Expression> {
620 let span = self.content_span(node);
621 let id = self.builder.next_id();
622 let token = tokens(node).next().expect("literal node should have a token");
623 let text = token.text();
624 self.validate_hexbin_literal(text, suffix.len() as u32, span);
625 let value = text.strip_suffix(suffix).unwrap();
626 Ok(ctor(value.to_string(), span, id).into())
627 }
628
629 fn int_literal_to_expression(&self, node: &SyntaxNode) -> Result<leo_ast::Expression> {
631 let token = tokens(node).next().expect("LITERAL_INT should have a token");
632 self.integer_token_to_expression(&token)
633 }
634
635 fn string_literal_to_expression(&self, node: &SyntaxNode) -> Result<leo_ast::Expression> {
637 let span = self.content_span(node);
638 let id = self.builder.next_id();
639 let token = tokens(node).next().expect("LITERAL_STRING should have a token");
640 Ok(leo_ast::Literal::string(token.text().to_string(), span, id).into())
641 }
642
643 fn identifier_literal_to_expression(&self, node: &SyntaxNode) -> Result<leo_ast::Expression> {
645 let span = self.content_span(node);
646 let id = self.builder.next_id();
647 let token = tokens(node).next().expect("LITERAL_IDENT should have a token");
648 let text = token.text();
650 let content = &text[1..text.len() - 1];
651 Ok(leo_ast::Literal::identifier(content.to_string(), span, id).into())
652 }
653
654 fn address_literal_to_expression(&self, node: &SyntaxNode) -> Result<leo_ast::Expression> {
656 let span = self.content_span(node);
657 let id = self.builder.next_id();
658 let token = tokens(node).next().expect("LITERAL_ADDRESS should have a token");
659 let text = token.text();
660 if !text.contains(".aleo") && text.parse::<Address<TestnetV0>>().is_err() {
662 self.handler.emit_err(crate::errors::invalid_address_lit(text, span));
663 }
664 Ok(leo_ast::Literal::address(text.to_string(), span, id).into())
665 }
666
667 fn bool_literal_to_expression(&self, node: &SyntaxNode) -> Result<leo_ast::Expression> {
669 let span = self.content_span(node);
670 let id = self.builder.next_id();
671 let token = tokens(node).next().expect("LITERAL_BOOL should have a token");
672 let value = token.kind() == KW_TRUE;
673 Ok(leo_ast::Literal::boolean(value, span, id).into())
674 }
675
676 fn binary_expr_to_expression(&self, node: &SyntaxNode) -> Result<leo_ast::Expression> {
678 debug_assert_eq!(node.kind(), BINARY_EXPR);
679 let span = self.content_span(node);
680 let id = self.builder.next_id();
681
682 let mut operands = children(node).filter(|n| n.kind().is_expression() || n.kind().is_type());
683
684 let op_token = match tokens(node).find(|t| t.kind().is_operator() || t.kind() == KW_AS) {
686 Some(token) => token,
687 None => {
688 self.emit_unexpected_str("operator in binary expression", node.text(), span);
689 return Ok(self.error_expression(span));
690 }
691 };
692
693 let op = token_to_binary_op(op_token.kind());
694
695 let left = match operands.next() {
697 Some(left_node) => self.to_expression(&left_node)?,
698 None => {
699 self.emit_unexpected_str("left operand in binary expression", node.text(), span);
700 return Ok(self.error_expression(span));
701 }
702 };
703
704 if op_token.kind() == KW_AS {
706 self.emit_unexpected_str("cast expression", "binary AS expression", span);
707 return Ok(self.error_expression(span));
708 }
709
710 let right = match operands.next() {
712 Some(right_node) => self.to_expression(&right_node)?,
713 None => {
714 self.emit_unexpected_str("right operand in binary expression", node.text(), span);
715 return Ok(self.error_expression(span));
716 }
717 };
718
719 Ok(leo_ast::BinaryExpression { left, right, op, span, id }.into())
720 }
721
722 fn unary_expr_to_expression(&self, node: &SyntaxNode) -> Result<leo_ast::Expression> {
724 debug_assert_eq!(node.kind(), UNARY_EXPR);
725 let span = self.content_span(node);
726 let id = self.builder.next_id();
727
728 let Some(op_token) = tokens(node).find(|t| matches!(t.kind(), BANG | MINUS)) else {
730 self.emit_unexpected_str("operator in unary expression", node.text(), span);
731 return Ok(self.error_expression(span));
732 };
733
734 let op = if op_token.kind() == BANG { leo_ast::UnaryOperation::Not } else { leo_ast::UnaryOperation::Negate };
735
736 let Some(operand) = children(node).find(|n| n.kind().is_expression()) else {
738 self.emit_unexpected_str("operand in unary expression", node.text(), span);
739 return Ok(self.error_expression(span));
740 };
741
742 let mut receiver = self.to_expression(&operand)?;
743
744 if op == leo_ast::UnaryOperation::Negate
746 && let leo_ast::Expression::Literal(leo_ast::Literal {
747 variant:
748 leo_ast::LiteralVariant::Integer(_, ref mut string)
749 | leo_ast::LiteralVariant::Field(ref mut string)
750 | leo_ast::LiteralVariant::Group(ref mut string)
751 | leo_ast::LiteralVariant::Scalar(ref mut string),
752 span: ref mut lit_span,
753 ..
754 }) = receiver
755 && !string.starts_with('-')
756 {
757 string.insert(0, '-');
758 *lit_span = span;
759 return Ok(receiver);
760 }
761
762 Ok(leo_ast::UnaryExpression { receiver, op, span, id }.into())
763 }
764
765 fn extract_const_arg_list(&self, node: &SyntaxNode) -> Result<ConstArgList> {
772 let mut type_parameters = Vec::new();
773 let mut const_arguments = Vec::new();
774 if let Some(arg_list) = children(node).find(|n| n.kind() == CONST_ARG_LIST) {
775 for child in children(&arg_list) {
776 if child.kind() == DYNAMIC_CALL_RETURN_TYPE {
777 if let Some(type_node) = children(&child).find(|n| n.kind().is_type()) {
780 let span = self.content_span(&child);
781 let ty = self.to_type(&type_node)?;
782 type_parameters.push((ty, span));
783 }
784 } else if child.kind().is_type() {
785 let span = self.content_span(&child);
786 let ty = self.to_type(&child)?;
787 type_parameters.push((ty, span));
788 } else if child.kind().is_expression() {
789 let expr = self.to_expression(&child)?;
790 const_arguments.push(expr);
791 }
792 }
793 }
794 Ok((type_parameters, const_arguments))
795 }
796
797 fn extract_dynamic_call_types(
807 &self,
808 callee_node: &SyntaxNode,
809 type_parameters: &[(leo_ast::TypeKind, Span)],
810 ) -> Result<(AnnotatedTypes, AnnotatedTypes)> {
811 let Some(arg_list) = children(callee_node).find(|n| n.kind() == CONST_ARG_LIST) else {
812 return Ok((Vec::new(), Vec::new()));
813 };
814
815 let mut all_entries = Vec::new();
817
818 for child in children(&arg_list) {
819 if child.kind() == DYNAMIC_CALL_RETURN_TYPE {
820 let mode = tokens(&child).find_map(|tok| token_kind_to_mode(tok.kind())).unwrap_or(leo_ast::Mode::None);
821 all_entries.push(mode);
822 } else if child.kind().is_type() {
823 all_entries.push(leo_ast::Mode::None);
824 }
825 }
826
827 if type_parameters.is_empty() {
829 return Ok((Vec::new(), Vec::new()));
830 }
831
832 let mut input_types = Vec::new();
833 let mut return_types = Vec::new();
834
835 let last_idx = type_parameters.len() - 1;
836 for (i, ((ty, sp), mode)) in type_parameters.iter().zip(all_entries.iter()).enumerate() {
837 if i < last_idx {
838 input_types.push((*mode, ty.clone(), *sp));
840 } else {
841 match ty {
846 leo_ast::TypeKind::Unit => {}
847 leo_ast::TypeKind::Tuple(tuple) => {
848 for elem in tuple.elements() {
849 return_types.push((*mode, elem.clone(), *sp));
850 }
851 }
852 _ => {
853 return_types.push((*mode, ty.clone(), *sp));
854 }
855 }
856 }
857 }
858
859 Ok((input_types, return_types))
860 }
861
862 fn call_expr_to_expression(&self, node: &SyntaxNode) -> Result<leo_ast::Expression> {
864 debug_assert_eq!(node.kind(), CALL_EXPR);
865 let span = self.content_span(node);
866 let id = self.builder.next_id();
867
868 let mut child_iter = children(node);
870 let callee_node = child_iter.next().expect("call expr should have callee");
871
872 let function = match callee_node.kind() {
873 PATH_LOCATOR_EXPR => self.locator_tokens_to_path(&callee_node)?,
874 _ => self.path_expr_to_path(&callee_node)?,
875 };
876
877 let arguments = children(node)
879 .skip(1) .filter(|n| n.kind().is_expression())
881 .map(|n| self.to_expression(&n))
882 .collect::<Result<Vec<_>>>()?;
883
884 let (type_parameters, const_arguments) = self.extract_const_arg_list(&callee_node)?;
887
888 if function.user_program().is_none() && function.qualifier().len() == 1 {
892 let module = function.qualifier()[0].name;
893 let name = function.identifier().name;
894 if let Some(intrinsic_name) = leo_ast::Intrinsic::convert_path_symbols(module, name) {
895 return Ok(leo_ast::IntrinsicExpression {
896 name: intrinsic_name,
897 type_parameters,
898 input_types: Vec::new(),
899 return_types: Vec::new(),
900 arguments,
901 span,
902 id,
903 }
904 .into());
905 }
906 if module == sym::ProgramCore {
909 let replacement = match name {
910 sym::checksum => Some("std::prog::checksum::[PROG_ID]()"),
911 sym::edition => Some("std::prog::edition::[PROG_ID]()"),
912 sym::program_owner => Some("std::prog::program_owner::[PROG_ID]()"),
913 sym::function_checksum => Some("std::prog::function_checksum::[PROG_ID, FN_NAME]()"),
914 _ => None,
915 };
916 if let Some(replacement) = replacement {
917 self.handler.emit_err(crate::errors::obsolete_context_access(
918 format!("Program::{}", name),
919 replacement,
920 span,
921 ));
922 return Ok(self.error_expression(span));
923 }
924 }
925 }
926
927 if function.user_program().is_none() && function.qualifier().is_empty() {
930 let name = function.identifier().name;
931 if leo_ast::Intrinsic::from_symbol(name, &type_parameters).is_some() {
932 let (input_types, return_types) = if name == leo_span::sym::_dynamic_call {
935 self.extract_dynamic_call_types(&callee_node, &type_parameters)?
936 } else {
937 (Vec::new(), Vec::new())
938 };
939 return Ok(leo_ast::IntrinsicExpression {
940 name,
941 type_parameters,
942 input_types,
943 return_types,
944 arguments,
945 span,
946 id,
947 }
948 .into());
949 }
950 }
951
952 Ok(leo_ast::CallExpression { function, const_arguments, arguments, span, id }.into())
953 }
954
955 fn dynamic_op_expr_to_expression(&self, node: &SyntaxNode) -> Result<leo_ast::Expression> {
962 debug_assert_eq!(node.kind(), DYNAMIC_OP_EXPR);
963 let span = self.content_span(node);
964 let id = self.builder.next_id();
965
966 let interface = children(node)
967 .filter(|n| n.kind().is_type())
968 .map(|n| self.to_type(&n))
969 .next()
970 .expect("Parser guarantees a type")?;
971
972 let separator_offset = tokens(node).filter(|t| t.kind() == COLON_COLON).last().map(|t| t.text_range().start());
975
976 let dot_offset = tokens(node).find(|t| t.kind() == DOT).map(|t| t.text_range().start());
978
979 let has_call_parens =
981 tokens(node).any(|t| t.kind() == L_PAREN && Some(t.text_range().start()) > separator_offset);
982
983 let expr_children: Vec<_> = children(node).filter(|n| n.kind().is_expression()).collect();
984
985 let (pre_sep, post_sep): (Vec<_>, Vec<_>) = expr_children.iter().partition(|child| match separator_offset {
986 Some(sep_off) => child.text_range().start() < sep_off,
987 None => true,
988 });
989
990 let target = match pre_sep.first() {
991 Some(target_node) => self.to_expression(target_node)?,
992 None => self.error_expression(span),
993 };
994
995 let network =
996 if let Some(network_node) = pre_sep.get(1) { Some(self.to_expression(network_node)?) } else { None };
997
998 let arguments = post_sep.iter().map(|n| self.to_expression(n)).collect::<Result<Vec<_>>>()?;
999
1000 let kind = if let Some(dot_pos) = dot_offset {
1001 let member = tokens(node)
1003 .find(|t| t.kind() == IDENT && t.text_range().start() < dot_pos)
1004 .map(|t| self.to_identifier(&t))
1005 .unwrap_or_else(|| self.error_identifier(span));
1006 let op = tokens(node)
1007 .find(|t| t.kind() == IDENT && t.text_range().start() > dot_pos)
1008 .map(|t| self.to_identifier(&t))
1009 .unwrap_or_else(|| self.error_identifier(span));
1010 leo_ast::DynamicOpKind::Op { member, op, arguments }
1011 } else if has_call_parens {
1012 let function = tokens(node)
1014 .find(|t| t.kind() == IDENT)
1015 .map(|t| self.to_identifier(&t))
1016 .unwrap_or_else(|| self.error_identifier(span));
1017 leo_ast::DynamicOpKind::Call { function, arguments }
1018 } else {
1019 let storage = tokens(node)
1021 .find(|t| t.kind() == IDENT)
1022 .map(|t| self.to_identifier(&t))
1023 .unwrap_or_else(|| self.error_identifier(span));
1024 leo_ast::DynamicOpKind::Read { storage }
1025 };
1026
1027 Ok(leo_ast::DynamicOpExpression { interface, target_program: target, network, kind, span, id }.into())
1028 }
1029
1030 fn method_call_expr_to_expression(&self, node: &SyntaxNode) -> Result<leo_ast::Expression> {
1034 debug_assert_eq!(node.kind(), METHOD_CALL_EXPR);
1035 let span = self.content_span(node);
1036 let id = self.builder.next_id();
1037
1038 let mut expr_children = children(node).filter(|n| n.kind().is_expression());
1040 let receiver = match expr_children.next() {
1041 Some(receiver_node) => self.to_expression(&receiver_node)?,
1042 None => {
1043 self.emit_unexpected_str("receiver in method call", node.text(), span);
1044 return Ok(self.error_expression(span));
1045 }
1046 };
1047
1048 let method_name = match find_name_after_dot(node) {
1054 Some(method_token) if method_token.kind() == IDENT => self.to_identifier(&method_token),
1055 Some(method_token) => {
1056 let token_span = self.token_span(&method_token);
1057 self.emit_unexpected_str("identifier", method_token.text(), token_span);
1058 self.error_identifier(token_span)
1059 }
1060 None => {
1061 self.emit_unexpected_str("method name in method call", node.text(), span);
1062 return Ok(self.error_expression(span));
1063 }
1064 };
1065
1066 let mut args: Vec<_> = expr_children.map(|n| self.to_expression(&n)).collect::<Result<Vec<_>>>()?;
1068
1069 if args.is_empty() {
1071 if let Some(op) = leo_ast::UnaryOperation::from_symbol(method_name.name) {
1072 return Ok(leo_ast::UnaryExpression { span, op, receiver, id }.into());
1073 }
1074 } else if args.len() == 1
1075 && let Some(op) = leo_ast::BinaryOperation::from_symbol(method_name.name)
1076 {
1077 return Ok(leo_ast::BinaryExpression { span, op, left: receiver, right: args.pop().unwrap(), id }.into());
1078 }
1079
1080 let method = method_name.name;
1086 let all_args = || std::iter::once(receiver.clone()).chain(args.clone()).collect::<Vec<_>>();
1087
1088 let intrinsic_name = match args.len() {
1090 2 => leo_ast::Intrinsic::convert_path_symbols(sym::signature, method),
1091 0 => leo_ast::Intrinsic::convert_path_symbols(sym::Final, method)
1092 .or_else(|| leo_ast::Intrinsic::convert_path_symbols(sym::Optional, method)),
1093 1 => leo_ast::Intrinsic::convert_path_symbols(sym::Optional, method),
1094 _ => None,
1095 };
1096 if let Some(intrinsic_name) = intrinsic_name {
1097 return Ok(self.intrinsic_expression(intrinsic_name, all_args(), span));
1098 }
1099
1100 if method == sym::get && args.len() == 1 {
1103 return Ok(self.intrinsic_expression(Symbol::intern("__unresolved_get"), all_args(), span));
1104 }
1105 if method == sym::set && args.len() == 2 {
1106 return Ok(self.intrinsic_expression(Symbol::intern("__unresolved_set"), all_args(), span));
1107 }
1108
1109 for module in [sym::Vector, sym::Mapping] {
1111 if let Some(intrinsic_name) = leo_ast::Intrinsic::convert_path_symbols(module, method) {
1112 return Ok(self.intrinsic_expression(intrinsic_name, all_args(), span));
1113 }
1114 }
1115
1116 self.handler.emit_err(crate::errors::invalid_method_call(receiver, method_name, args.len(), span));
1118 Ok(self.error_expression(span))
1119 }
1120
1121 fn tuple_access_expr_to_expression(&self, node: &SyntaxNode) -> Result<leo_ast::Expression> {
1123 debug_assert_eq!(node.kind(), TUPLE_ACCESS_EXPR);
1124 let span = self.content_span(node);
1125 let id = self.builder.next_id();
1126
1127 let inner = if let Some(inner_node) = children(node).find(|n| n.kind().is_expression()) {
1128 self.to_expression(&inner_node)?
1129 } else {
1130 self.emit_unexpected_str("expression in tuple access", node.text(), span);
1131 return Ok(self.error_expression(span));
1132 };
1133
1134 let index_token = match tokens(node).find(|t| t.kind() == INTEGER) {
1135 Some(token) => token,
1136 None => {
1137 self.emit_unexpected_str("tuple index", node.text(), span);
1138 return Ok(self.error_expression(span));
1139 }
1140 };
1141
1142 let index_text = index_token.text().replace('_', "");
1143 let index: usize = match index_text.parse() {
1144 Ok(idx) => idx,
1145 Err(_) => {
1146 self.emit_unexpected_str("valid tuple index", index_text, span);
1147 return Ok(self.error_expression(span));
1148 }
1149 };
1150 Ok(leo_ast::TupleAccess { tuple: inner, index: index.into(), span, id }.into())
1151 }
1152
1153 fn field_expr_to_expression(&self, node: &SyntaxNode) -> Result<leo_ast::Expression> {
1155 debug_assert_eq!(node.kind(), FIELD_EXPR);
1156 let span = self.content_span(node);
1157 let id = self.builder.next_id();
1158
1159 let (inner, first_child_kind) = match children(node).find(|n| n.kind().is_expression()) {
1161 Some(n) => {
1162 let kind = n.kind();
1163 let lowered = if matches!(kind, SELF_EXPR | BLOCK_KW_EXPR | NETWORK_KW_EXPR) {
1164 self.error_expression(self.trimmed_span(&n))
1165 } else {
1166 self.to_expression(&n)?
1167 };
1168 (lowered, kind)
1169 }
1170 None => {
1171 self.emit_unexpected_str("expression in field access", node.text(), span);
1172 return Ok(self.error_expression(span));
1173 }
1174 };
1175
1176 let field_token = match find_name_after_dot(node) {
1179 Some(token) => token,
1180 None => {
1181 self.emit_unexpected_str("field name in field access", node.text(), span);
1182 return Ok(self.error_expression(span));
1183 }
1184 };
1185
1186 if field_token.kind() == KW_ALEO
1190 && let leo_ast::Expression::Path(ref path) = inner
1191 && path.user_program().is_none()
1192 && path.qualifier().is_empty()
1193 {
1194 let full_name = format!("{}.aleo", path.identifier().name);
1195 return Ok(leo_ast::Literal::address(full_name, span, id).into());
1196 }
1197
1198 let field_name = Symbol::intern(field_token.text());
1203 let removed_access = match (first_child_kind, field_name) {
1204 (SELF_EXPR, sym::address) => Some(("self.address", "std::ctx::addr()")),
1205 (SELF_EXPR, sym::caller) => Some(("self.caller", "std::ctx::caller()")),
1206 (SELF_EXPR, sym::checksum) => Some(("self.checksum", "std::ctx::checksum()")),
1207 (SELF_EXPR, sym::edition) => Some(("self.edition", "std::ctx::edition()")),
1208 (SELF_EXPR, sym::id) => Some(("self.id", "std::ctx::id()")),
1209 (SELF_EXPR, sym::program_owner) => Some(("self.program_owner", "std::ctx::program_owner()")),
1210 (SELF_EXPR, sym::signer) => Some(("self.signer", "std::ctx::signer()")),
1211 (BLOCK_KW_EXPR, sym::height) => Some(("block.height", "std::ctx::block_height()")),
1212 (BLOCK_KW_EXPR, sym::timestamp) => Some(("block.timestamp", "std::ctx::block_timestamp()")),
1213 (NETWORK_KW_EXPR, sym::id) => Some(("network.id", "std::ctx::network_id()")),
1214 _ => None,
1215 };
1216 if let Some((old, replacement)) = removed_access {
1217 self.handler.emit_err(crate::errors::obsolete_context_access(old, replacement, span));
1218 return Ok(self.error_expression(span));
1219 }
1220 if matches!(first_child_kind, SELF_EXPR | BLOCK_KW_EXPR | NETWORK_KW_EXPR) {
1221 let keyword = match first_child_kind {
1222 SELF_EXPR => "self",
1223 BLOCK_KW_EXPR => "block",
1224 NETWORK_KW_EXPR => "network",
1225 _ => unreachable!(),
1226 };
1227 self.handler.emit_err(crate::errors::obsolete_context_keyword(keyword, span));
1228 return Ok(self.error_expression(span));
1229 }
1230
1231 let field_span = self.token_span(&field_token);
1233 let name = leo_ast::Identifier { name: field_name, span: field_span, id: self.builder.next_id() };
1234 Ok(leo_ast::MemberAccess { inner, name, span, id }.into())
1235 }
1236
1237 fn index_expr_to_expression(&self, node: &SyntaxNode) -> Result<leo_ast::Expression> {
1239 debug_assert_eq!(node.kind(), INDEX_EXPR);
1240 let span = self.content_span(node);
1241 let id = self.builder.next_id();
1242
1243 let mut exprs = children(node).filter(|n| n.kind().is_expression());
1244
1245 let array = match exprs.next() {
1246 Some(n) => self.to_expression(&n)?,
1247 None => {
1248 self.emit_unexpected_str("array in index expression", node.text(), span);
1249 return Ok(self.error_expression(span));
1250 }
1251 };
1252
1253 let index = match exprs.next() {
1254 Some(n) => self.to_expression(&n)?,
1255 None => {
1256 self.emit_unexpected_str("index in index expression", node.text(), span);
1257 return Ok(self.error_expression(span));
1258 }
1259 };
1260
1261 Ok(leo_ast::ArrayAccess { array, index, span, id }.into())
1262 }
1263
1264 fn cast_expr_to_expression(&self, node: &SyntaxNode) -> Result<leo_ast::Expression> {
1266 debug_assert_eq!(node.kind(), CAST_EXPR);
1267 let span = self.content_span(node);
1268 let id = self.builder.next_id();
1269
1270 let Some(expr_node) = children(node).find(|n| n.kind().is_expression()) else {
1272 self.emit_unexpected_str("expression in cast", node.text(), span);
1273 return Ok(self.error_expression(span));
1274 };
1275 let expression = self.to_expression(&expr_node)?;
1276
1277 let Some(type_node) = children(node).find(|n| n.kind().is_type()) else {
1279 self.emit_unexpected_str("type in cast expression", node.text(), span);
1280 return Ok(self.error_expression(span));
1281 };
1282 let type_ = self.to_type_repr(&type_node)?;
1283
1284 Ok(leo_ast::CastExpression { expression, type_, span, id }.into())
1285 }
1286
1287 fn ternary_expr_to_expression(&self, node: &SyntaxNode) -> Result<leo_ast::Expression> {
1289 debug_assert_eq!(node.kind(), TERNARY_EXPR);
1290 let span = self.content_span(node);
1291 let id = self.builder.next_id();
1292
1293 let mut exprs = children(node).filter(|n| n.kind().is_expression());
1294
1295 let condition = match exprs.next() {
1296 Some(n) => self.to_expression(&n)?,
1297 None => {
1298 self.emit_unexpected_str("condition in ternary expression", node.text(), span);
1299 return Ok(self.error_expression(span));
1300 }
1301 };
1302
1303 let if_true = match exprs.next() {
1304 Some(n) => self.to_expression(&n)?,
1305 None => {
1306 self.emit_unexpected_str("true branch in ternary expression", node.text(), span);
1307 return Ok(self.error_expression(span));
1308 }
1309 };
1310
1311 let if_false = match exprs.next() {
1312 Some(n) => self.to_expression(&n)?,
1313 None => {
1314 self.emit_unexpected_str("false branch in ternary expression", node.text(), span);
1315 return Ok(self.error_expression(span));
1316 }
1317 };
1318
1319 Ok(leo_ast::TernaryExpression { condition, if_true, if_false, span, id }.into())
1320 }
1321
1322 fn array_expr_to_expression(&self, node: &SyntaxNode) -> Result<leo_ast::Expression> {
1324 debug_assert_eq!(node.kind(), ARRAY_EXPR);
1325 let span = self.content_span(node);
1326 let id = self.builder.next_id();
1327
1328 let elements = children(node)
1329 .filter(|n| n.kind().is_expression())
1330 .map(|n| self.to_expression(&n))
1331 .collect::<Result<Vec<_>>>()?;
1332
1333 Ok(leo_ast::ArrayExpression { elements, span, id }.into())
1334 }
1335
1336 fn repeat_expr_to_expression(&self, node: &SyntaxNode) -> Result<leo_ast::Expression> {
1338 debug_assert_eq!(node.kind(), REPEAT_EXPR);
1339 let span = self.content_span(node);
1340 let id = self.builder.next_id();
1341
1342 let mut exprs = children(node).filter(|n| n.kind().is_expression());
1343 let expr = match exprs.next() {
1344 Some(n) => self.to_expression(&n)?,
1345 None => {
1346 self.emit_unexpected_str("expression in repeat", node.text(), span);
1347 return Ok(self.error_expression(span));
1348 }
1349 };
1350 let count = match exprs.next() {
1351 Some(n) => self.to_expression(&n)?,
1352 None => {
1353 self.emit_unexpected_str("repeat count", node.text(), span);
1354 return Ok(self.error_expression(span));
1355 }
1356 };
1357
1358 Ok(leo_ast::RepeatExpression { expr, count, span, id }.into())
1359 }
1360
1361 fn tuple_expr_to_expression(&self, node: &SyntaxNode) -> Result<leo_ast::Expression> {
1363 debug_assert_eq!(node.kind(), TUPLE_EXPR);
1364 let span = self.content_span(node);
1365 let id = self.builder.next_id();
1366
1367 let elements: Vec<_> = children(node)
1368 .filter(|n| n.kind().is_expression())
1369 .map(|n| self.to_expression(&n))
1370 .collect::<Result<Vec<_>>>()?;
1371
1372 match elements.len() {
1373 0 => {
1374 self.handler.emit_err(crate::errors::tuple_must_have_at_least_two_elements("expression", span));
1376 Ok(leo_ast::UnitExpression { span, id }.into())
1378 }
1379 1 => {
1380 self.handler.emit_err(crate::errors::tuple_must_have_at_least_two_elements("expression", span));
1382 Ok(elements.into_iter().next().unwrap())
1384 }
1385 _ => Ok(leo_ast::TupleExpression { elements, span, id }.into()),
1386 }
1387 }
1388
1389 fn composite_expression_from_path(
1392 &self,
1393 node: &SyntaxNode,
1394 path: leo_ast::Path,
1395 span: Span,
1396 id: leo_ast::NodeID,
1397 ) -> Result<leo_ast::Expression> {
1398 let members = children(node)
1399 .filter(|n| matches!(n.kind(), STRUCT_FIELD_INIT | STRUCT_FIELD_SHORTHAND))
1400 .map(|n| self.struct_field_init_to_member(&n))
1401 .collect::<Result<Vec<_>>>()?;
1402 let base = children(node)
1403 .find(|n| n.kind() == STRUCT_BASE_UPDATE)
1404 .and_then(|n| children(&n).find(|c| c.kind().is_expression()))
1405 .map(|n| self.to_expression(&n).map(Box::new))
1406 .transpose()?;
1407 let (_type_parameters, const_arguments) = self.extract_const_arg_list(node)?;
1408 Ok(leo_ast::CompositeExpression { path, const_arguments, members, base, span, id }.into())
1409 }
1410
1411 fn struct_expr_to_expression(&self, node: &SyntaxNode) -> Result<leo_ast::Expression> {
1413 debug_assert_eq!(node.kind(), STRUCT_EXPR);
1414 let span = self.content_span(node);
1415 let id = self.builder.next_id();
1416 let path = self.struct_expr_to_path(node)?;
1417 self.composite_expression_from_path(node, path, span, id)
1418 }
1419
1420 fn struct_expr_to_path(&self, node: &SyntaxNode) -> Result<leo_ast::Path> {
1422 let fallback_span = self.content_span(node);
1423
1424 let mut path_components = Vec::new();
1426 for token in tokens(node) {
1427 if token.kind() == L_BRACE {
1428 break;
1429 }
1430 if token.kind() == IDENT {
1431 path_components.push(self.to_identifier(&token));
1432 }
1433 }
1434
1435 let path_span = match (path_components.first(), path_components.last()) {
1436 (Some(first), Some(last)) => Span::new(first.span.lo, last.span.hi),
1437 _ => fallback_span,
1438 };
1439
1440 let name = match path_components.pop() {
1441 Some(name) => name,
1442 None => {
1443 self.emit_unexpected_str("type name in struct expression", node.text(), fallback_span);
1444 self.error_identifier(fallback_span)
1445 }
1446 };
1447 Ok(leo_ast::Path::new(None, path_components, name, path_span, self.builder.next_id()))
1448 }
1449
1450 fn struct_locator_expr_to_expression(&self, node: &SyntaxNode) -> Result<leo_ast::Expression> {
1452 let span = self.content_span(node);
1453 let id = self.builder.next_id();
1454 let path = self.locator_tokens_to_path(node)?;
1455 self.composite_expression_from_path(node, path, span, id)
1456 }
1457
1458 fn path_locator_expr_to_expression(&self, node: &SyntaxNode) -> Result<leo_ast::Expression> {
1460 let path = self.locator_tokens_to_path(node)?;
1461 Ok(leo_ast::Expression::Path(path))
1462 }
1463
1464 fn locator_tokens_to_path(&self, node: &SyntaxNode) -> Result<leo_ast::Path> {
1471 let span = self.to_span(node);
1472 let all_idents: Vec<_> = tokens(node).filter(|t| t.kind() == IDENT).collect();
1473
1474 let program_ident = match all_idents.first() {
1476 Some(t) => self.to_identifier(t),
1477 None => {
1478 self.emit_unexpected_str("program name", node.text(), span);
1479 self.error_identifier(span)
1480 }
1481 };
1482
1483 let network_ident = leo_ast::Identifier {
1485 name: Symbol::intern("aleo"),
1486 span: tokens(node).find(|t| t.kind() == KW_ALEO).map(|t| self.token_span(&t)).unwrap_or(span),
1487 id: self.builder.next_id(),
1488 };
1489
1490 let program = leo_ast::ProgramId { name: program_ident, network: network_ident };
1492
1493 let (qualifier, name) = if all_idents.len() < 2 {
1497 self.emit_unexpected_str("identifier", node.text(), span);
1498 (Vec::new(), self.error_identifier(span))
1499 } else {
1500 let name = self.to_identifier(all_idents.last().unwrap()); let qualifier: Vec<_> = all_idents[1..all_idents.len() - 1].iter().map(|t| self.to_identifier(t)).collect();
1502 (qualifier, name)
1503 };
1504
1505 let path_span = Span::new(program.name.span.lo, name.span.hi);
1506 Ok(leo_ast::Path::new(Some(program), qualifier, name, path_span, self.builder.next_id()))
1507 }
1508
1509 fn struct_field_init_to_member(&self, node: &SyntaxNode) -> Result<leo_ast::CompositeFieldInitializer> {
1511 debug_assert!(matches!(node.kind(), STRUCT_FIELD_INIT | STRUCT_FIELD_SHORTHAND));
1512 let span = self.content_span(node);
1513 let id = self.builder.next_id();
1514
1515 let Some(ident_token) = tokens(node).find(|t| t.kind() == IDENT) else {
1516 self.emit_unexpected_str("identifier in struct field", node.text(), span);
1517 return Ok(leo_ast::CompositeFieldInitializer {
1518 identifier: self.error_identifier(span),
1519 expression: None,
1520 span,
1521 id,
1522 });
1523 };
1524 let identifier = self.to_identifier(&ident_token);
1525
1526 let expression = if node.kind() == STRUCT_FIELD_INIT {
1527 children(node).find(|n| n.kind().is_expression()).map(|n| self.to_expression(&n)).transpose()?
1528 } else {
1529 None
1530 };
1531
1532 Ok(leo_ast::CompositeFieldInitializer { identifier, expression, span, id })
1533 }
1534
1535 fn program_ref_expr_to_expression(&self, node: &SyntaxNode) -> Result<leo_ast::Expression> {
1537 debug_assert_eq!(node.kind(), PROGRAM_REF_EXPR);
1538 let span = self.content_span(node);
1539 let id = self.builder.next_id();
1540 let text: String = tokens(node).map(|t| t.text().to_string()).collect();
1541 Ok(leo_ast::Literal::address(text, span, id).into())
1542 }
1543
1544 fn path_expr_to_expression(&self, node: &SyntaxNode) -> Result<leo_ast::Expression> {
1546 debug_assert_eq!(node.kind(), PATH_EXPR);
1547
1548 let path = self.path_expr_to_path(node)?;
1549 let span = self.trimmed_span(node);
1550 let id = self.builder.next_id();
1551
1552 if path.user_program().is_none()
1554 && path.qualifier().len() == 1
1555 && path.qualifier()[0].name == sym::group
1556 && path.identifier().name == sym::GEN
1557 {
1558 return Ok(self.intrinsic_expression(sym::_group_gen, Vec::new(), span));
1559 }
1560
1561 if path.user_program().is_none() && path.qualifier().is_empty() {
1564 let name_text = path.identifier().name.to_string();
1565 if name_text.starts_with("sign1") && name_text.parse::<Signature<TestnetV0>>().is_ok() {
1566 return Ok(leo_ast::Literal::signature(name_text, span, id).into());
1567 }
1568 if name_text.starts_with('_') {
1571 self.handler.emit_err(crate::errors::identifier_cannot_start_with_underscore(span));
1572 return Ok(self.error_expression(span));
1573 }
1574 }
1575
1576 Ok(leo_ast::Expression::Path(path))
1577 }
1578
1579 fn error_removed_context_keyword(&self, node: &SyntaxNode, name: Symbol) -> leo_ast::Expression {
1583 let span = self.trimmed_span(node);
1584 let keyword = match name {
1585 sym::SelfLower => "self",
1586 sym::block => "block",
1587 sym::network => "network",
1588 _ => unreachable!("error_removed_context_keyword called with non-context keyword"),
1589 };
1590 self.handler.emit_err(crate::errors::obsolete_context_keyword(keyword, span));
1591 self.error_expression(span)
1592 }
1593
1594 fn final_expr_to_expression(&self, node: &SyntaxNode) -> Result<leo_ast::Expression> {
1596 debug_assert_eq!(node.kind(), FINAL_EXPR);
1597 let span = self.content_span(node);
1598 let id = self.builder.next_id();
1599
1600 if let Some(block_node) = children(node).find(|n| n.kind() == BLOCK) {
1602 let block = self.to_block(&block_node)?;
1603 Ok(leo_ast::AsyncExpression { block, span, id }.into())
1604 } else {
1605 self.emit_unexpected_str("block in final expression", node.text(), span);
1607 Ok(self.error_expression(span))
1608 }
1609 }
1610
1611 fn path_expr_to_path(&self, node: &SyntaxNode) -> Result<leo_ast::Path> {
1619 let span = self.trimmed_span(node);
1620
1621 let mut path_components = Vec::new();
1623 for token in tokens(node) {
1624 match token.kind() {
1625 IDENT => {
1626 let text = token.text();
1627 if text.contains("::") {
1631 let token_span = self.token_span(&token);
1632 let mut offset = token_span.lo;
1633 for (i, segment) in text.split("::").enumerate() {
1634 if i > 0 {
1635 offset += 2; }
1637 let seg_span = Span::new(offset, offset + segment.len() as u32);
1638 path_components.push(leo_ast::Identifier {
1639 name: Symbol::intern(segment),
1640 span: seg_span,
1641 id: self.builder.next_id(),
1642 });
1643 offset += segment.len() as u32;
1644 }
1645 } else {
1646 path_components.push(self.to_identifier(&token));
1647 }
1648 }
1649 kind => {
1650 if let Some(name) = keyword_to_path_symbol(kind) {
1651 path_components.push(leo_ast::Identifier {
1652 name,
1653 span: self.token_span(&token),
1654 id: self.builder.next_id(),
1655 });
1656 }
1657 }
1658 }
1659 }
1660
1661 let name = match path_components.pop() {
1662 Some(name) => name,
1663 None => {
1664 self.emit_unexpected_str("identifier in path", node.text(), span);
1665 self.error_identifier(span)
1666 }
1667 };
1668 Ok(leo_ast::Path::new(None, path_components, name, span, self.builder.next_id()))
1669 }
1670
1671 fn to_statement(&self, node: &SyntaxNode) -> Result<leo_ast::Statement> {
1677 let span = self.to_span(node);
1678 let id = self.builder.next_id();
1679
1680 let stmt = match node.kind() {
1681 LET_STMT => self.let_stmt_to_statement(node)?,
1682 CONST_STMT => self.const_stmt_to_statement(node)?,
1683 RETURN_STMT => self.return_stmt_to_statement(node)?,
1684 EXPR_STMT => self.expr_stmt_to_statement(node)?,
1685 ASSIGN_STMT => self.simple_assign_to_statement(node)?,
1686 COMPOUND_ASSIGN_STMT => self.compound_assign_to_statement(node)?,
1687 IF_STMT => self.if_stmt_to_statement(node)?,
1688 FOR_STMT | FOR_INCLUSIVE_STMT => self.for_stmt_to_statement(node)?,
1689 BLOCK => self.to_block(node)?.into(),
1690 ASSERT_STMT => {
1691 let expression = self.require_expression(node, "expression in assert")?;
1692 leo_ast::AssertStatement { variant: leo_ast::AssertVariant::Assert(expression), span, id }.into()
1693 }
1694 ASSERT_EQ_STMT => {
1695 self.assert_binary_to_statement(node, "assert_eq", span, id, leo_ast::AssertVariant::AssertEq)?
1696 }
1697 ASSERT_NEQ_STMT => {
1698 self.assert_binary_to_statement(node, "assert_neq", span, id, leo_ast::AssertVariant::AssertNeq)?
1699 }
1700 ROOT => {
1702 if let Some(inner) = children(node).find(|n| n.kind().is_statement()) {
1703 self.to_statement(&inner)?
1704 } else {
1705 leo_ast::ExpressionStatement { expression: self.error_expression(span), span, id }.into()
1707 }
1708 }
1709 ERROR => leo_ast::ExpressionStatement { expression: self.error_expression(span), span, id }.into(),
1712 kind => panic!("unexpected statement kind: {:?}", kind),
1713 };
1714
1715 Ok(stmt)
1716 }
1717
1718 fn assert_binary_to_statement(
1720 &self,
1721 node: &SyntaxNode,
1722 label: &str,
1723 span: Span,
1724 id: leo_ast::NodeID,
1725 make_variant: fn(leo_ast::Expression, leo_ast::Expression) -> leo_ast::AssertVariant,
1726 ) -> Result<leo_ast::Statement> {
1727 let mut exprs = children(node).filter(|n| n.kind().is_expression());
1728 let e0 = match exprs.next() {
1729 Some(expr) => self.to_expression(&expr)?,
1730 None => {
1731 self.emit_unexpected_str(&format!("first expression in {label}"), node.text(), span);
1732 self.error_expression(span)
1733 }
1734 };
1735 let e1 = match exprs.next() {
1736 Some(expr) => self.to_expression(&expr)?,
1737 None => {
1738 self.emit_unexpected_str(&format!("second expression in {label}"), node.text(), span);
1739 self.error_expression(span)
1740 }
1741 };
1742 Ok(leo_ast::AssertStatement { variant: make_variant(e0, e1), span, id }.into())
1743 }
1744
1745 fn to_block(&self, node: &SyntaxNode) -> Result<leo_ast::Block> {
1747 debug_assert_eq!(node.kind(), BLOCK);
1748 let span = self.to_span(node);
1749 let id = self.builder.next_id();
1750
1751 let statements = children(node)
1752 .filter(|n| n.kind().is_statement())
1753 .map(|n| self.to_statement(&n))
1754 .collect::<Result<Vec<_>>>()?;
1755
1756 Ok(leo_ast::Block { statements, span, id })
1757 }
1758
1759 fn let_stmt_to_statement(&self, node: &SyntaxNode) -> Result<leo_ast::Statement> {
1761 debug_assert_eq!(node.kind(), LET_STMT);
1762 let span = self.to_span(node);
1763 let id = self.builder.next_id();
1764
1765 let place = match children(node).find(|n| matches!(n.kind(), IDENT_PATTERN | TUPLE_PATTERN | WILDCARD_PATTERN))
1767 {
1768 Some(pattern_node) => self.pattern_to_definition_place(&pattern_node)?,
1769 None => {
1770 self.emit_unexpected_str("pattern in let statement", node.text(), span);
1771 leo_ast::DefinitionPlace::Single(self.error_identifier(span))
1772 }
1773 };
1774
1775 let type_ = children(node).find(|n| n.kind().is_type()).map(|n| self.to_type_repr(&n)).transpose()?;
1777
1778 let value = self.require_expression(node, "value in let statement")?;
1779
1780 Ok(leo_ast::DefinitionStatement { place, type_, value, span, id }.into())
1781 }
1782
1783 fn pattern_to_definition_place(&self, node: &SyntaxNode) -> Result<leo_ast::DefinitionPlace> {
1785 let span = self.to_span(node);
1786 match node.kind() {
1787 IDENT_PATTERN => {
1788 let ident = self.require_ident(node, "identifier in pattern");
1789 self.validate_definition_identifier(&ident);
1790 Ok(leo_ast::DefinitionPlace::Single(ident))
1791 }
1792 TUPLE_PATTERN => {
1793 let names = children(node)
1794 .filter(|n| matches!(n.kind(), IDENT_PATTERN | WILDCARD_PATTERN))
1795 .map(|n| {
1796 if n.kind() == WILDCARD_PATTERN {
1797 let span = self.to_span(&n);
1799 leo_ast::Identifier { name: Symbol::intern("_"), span, id: self.builder.next_id() }
1800 } else {
1801 let ident = self.require_ident(&n, "identifier in pattern");
1802 self.validate_definition_identifier(&ident);
1803 ident
1804 }
1805 })
1806 .collect();
1807 Ok(leo_ast::DefinitionPlace::Multiple(names))
1808 }
1809 WILDCARD_PATTERN => {
1810 let ident = leo_ast::Identifier { name: Symbol::intern("_"), span, id: self.builder.next_id() };
1811 Ok(leo_ast::DefinitionPlace::Single(ident))
1812 }
1813 _ => {
1814 self.emit_unexpected_str("valid pattern", node.text(), span);
1815 let ident = self.error_identifier(span);
1816 Ok(leo_ast::DefinitionPlace::Single(ident))
1817 }
1818 }
1819 }
1820
1821 fn const_stmt_to_statement(&self, node: &SyntaxNode) -> Result<leo_ast::Statement> {
1823 debug_assert_eq!(node.kind(), CONST_STMT);
1824 let span = self.to_span(node);
1825 let id = self.builder.next_id();
1826
1827 let place = self.require_ident(node, "name in const declaration");
1828
1829 let type_ = self.require_type_repr(node, "type in const declaration")?;
1830
1831 let value = self.require_expression(node, "value in const declaration")?;
1832
1833 Ok(leo_ast::ConstDeclaration { is_exported: None, place, type_, value, span, id }.into())
1835 }
1836
1837 fn return_stmt_to_statement(&self, node: &SyntaxNode) -> Result<leo_ast::Statement> {
1839 debug_assert_eq!(node.kind(), RETURN_STMT);
1840 let span = self.to_span(node);
1841 let id = self.builder.next_id();
1842
1843 let expression = children(node)
1845 .find(|n| n.kind().is_expression())
1846 .map(|n| self.to_expression(&n))
1847 .transpose()?
1848 .unwrap_or_else(|| leo_ast::UnitExpression { span, id: self.builder.next_id() }.into());
1849
1850 Ok(leo_ast::ReturnStatement { expression, span, id }.into())
1851 }
1852
1853 fn expr_stmt_to_statement(&self, node: &SyntaxNode) -> Result<leo_ast::Statement> {
1855 debug_assert_eq!(node.kind(), EXPR_STMT);
1856 let span = self.to_span(node);
1857 let id = self.builder.next_id();
1858
1859 let expression = self.require_expression(node, "expression in expression statement")?;
1860
1861 Ok(leo_ast::ExpressionStatement { expression, span, id }.into())
1862 }
1863
1864 fn simple_assign_to_statement(&self, node: &SyntaxNode) -> Result<leo_ast::Statement> {
1866 debug_assert_eq!(node.kind(), ASSIGN_STMT);
1867 let span = self.to_span(node);
1868 let id = self.builder.next_id();
1869
1870 let mut exprs = children(node).filter(|n| n.kind().is_expression());
1871
1872 let place = match exprs.next() {
1873 Some(n) => self.to_expression(&n)?,
1874 None => {
1875 self.emit_unexpected_str("left side in assignment", node.text(), span);
1876 return Ok(leo_ast::ExpressionStatement { expression: self.error_expression(span), span, id }.into());
1877 }
1878 };
1879
1880 let value = match exprs.next() {
1881 Some(n) => self.to_expression(&n)?,
1882 None => {
1883 self.emit_unexpected_str("right side in assignment", node.text(), span);
1884 self.error_expression(span)
1885 }
1886 };
1887
1888 Ok(leo_ast::AssignStatement { place, value, span, id }.into())
1889 }
1890
1891 fn compound_assign_to_statement(&self, node: &SyntaxNode) -> Result<leo_ast::Statement> {
1895 debug_assert_eq!(node.kind(), COMPOUND_ASSIGN_STMT);
1896 let span = self.to_span(node);
1897 let id = self.builder.next_id();
1898
1899 let mut exprs = children(node).filter(|n| n.kind().is_expression());
1900
1901 let left = match exprs.next() {
1902 Some(n) => self.to_expression(&n)?,
1903 None => {
1904 self.emit_unexpected_str("left side in compound assignment", node.text(), span);
1905 return Ok(leo_ast::ExpressionStatement { expression: self.error_expression(span), span, id }.into());
1906 }
1907 };
1908
1909 let right = match exprs.next() {
1910 Some(n) => self.to_expression(&n)?,
1911 None => {
1912 self.emit_unexpected_str("right side in compound assignment", node.text(), span);
1913 self.error_expression(span)
1914 }
1915 };
1916
1917 let op_token =
1918 tokens(node).find(|t| is_assign_op(t.kind())).expect("COMPOUND_ASSIGN_STMT should have operator");
1919
1920 let binary_op = match op_token.kind() {
1921 PLUS_EQ => leo_ast::BinaryOperation::Add,
1922 MINUS_EQ => leo_ast::BinaryOperation::Sub,
1923 STAR_EQ => leo_ast::BinaryOperation::Mul,
1924 SLASH_EQ => leo_ast::BinaryOperation::Div,
1925 PERCENT_EQ => leo_ast::BinaryOperation::Rem,
1926 STAR2_EQ => leo_ast::BinaryOperation::Pow,
1927 AMP_EQ => leo_ast::BinaryOperation::BitwiseAnd,
1928 PIPE_EQ => leo_ast::BinaryOperation::BitwiseOr,
1929 CARET_EQ => leo_ast::BinaryOperation::Xor,
1930 SHL_EQ => leo_ast::BinaryOperation::Shl,
1931 SHR_EQ => leo_ast::BinaryOperation::Shr,
1932 AMP2_EQ => leo_ast::BinaryOperation::And,
1933 PIPE2_EQ => leo_ast::BinaryOperation::Or,
1934 k => panic!("unexpected compound assignment operator: {k:?}"),
1935 };
1936
1937 let value =
1938 leo_ast::BinaryExpression { left: left.clone(), right, op: binary_op, span, id: self.builder.next_id() }
1939 .into();
1940
1941 Ok(leo_ast::AssignStatement { place: left, value, span, id }.into())
1942 }
1943
1944 fn if_stmt_to_statement(&self, node: &SyntaxNode) -> Result<leo_ast::Statement> {
1946 debug_assert_eq!(node.kind(), IF_STMT);
1947 let span = self.to_span(node);
1948 let id = self.builder.next_id();
1949
1950 let condition = self.require_expression(node, "condition in if statement")?;
1951
1952 let mut block_or_if = children(node).filter(|n| n.kind() == BLOCK || n.kind() == IF_STMT);
1955
1956 let then = match block_or_if.next() {
1957 Some(n) if n.kind() == BLOCK => self.to_block(&n)?,
1958 _ => {
1959 self.emit_unexpected_str("then block in if statement", node.text(), span);
1960 self.error_block(span)
1961 }
1962 };
1963
1964 let otherwise = block_or_if.next().map(|n| self.to_statement(&n)).transpose()?.map(Box::new);
1965
1966 Ok(leo_ast::ConditionalStatement { condition, then, otherwise, span, id }.into())
1967 }
1968
1969 fn for_stmt_to_statement(&self, node: &SyntaxNode) -> Result<leo_ast::Statement> {
1971 debug_assert!(matches!(node.kind(), FOR_STMT | FOR_INCLUSIVE_STMT));
1972 let span = self.to_span(node);
1973 let id = self.builder.next_id();
1974
1975 let variable = self.require_ident(node, "variable in for statement");
1976
1977 let type_ = children(node).find(|n| n.kind().is_type()).map(|n| self.to_type_repr(&n)).transpose()?;
1979
1980 let mut exprs = children(node).filter(|n| n.kind().is_expression());
1982
1983 let start = match exprs.next() {
1984 Some(n) => self.to_expression(&n)?,
1985 None => {
1986 self.emit_unexpected_str("start expression in for statement", node.text(), span);
1987 self.error_expression(span)
1988 }
1989 };
1990
1991 let stop = match exprs.next() {
1992 Some(n) => self.to_expression(&n)?,
1993 None => {
1994 self.emit_unexpected_str("stop expression in for statement", node.text(), span);
1995 self.error_expression(span)
1996 }
1997 };
1998
1999 let block = match children(node).find(|n| n.kind() == BLOCK) {
2001 Some(block_node) => self.to_block(&block_node)?,
2002 None => {
2003 self.emit_unexpected_str("block in for statement", node.text(), span);
2004 self.error_block(span)
2005 }
2006 };
2007
2008 let inclusive = node.kind() == FOR_INCLUSIVE_STMT;
2009
2010 Ok(leo_ast::IterationStatement { variable, type_, start, stop, inclusive, block, span, id }.into())
2011 }
2012
2013 fn collect_program_item(
2019 &self,
2020 item: &SyntaxNode,
2021 is_in_program_block: bool,
2022 functions: &mut Vec<(Symbol, leo_ast::Function)>,
2023 composites: &mut Vec<(Symbol, leo_ast::Composite)>,
2024 consts: &mut Vec<(Symbol, leo_ast::ConstDeclaration)>,
2025 interfaces: &mut Vec<(Symbol, leo_ast::Interface)>,
2026 ) -> Result<()> {
2027 match item.kind() {
2028 FUNCTION_DEF | FINAL_FN_DEF | VIEW_FN_DEF => {
2029 if item.kind() == VIEW_FN_DEF && !is_in_program_block {
2030 let span = self.to_span(item);
2032 self.handler.emit_err(crate::errors::custom(
2033 "`view fn` is only allowed inside a `program { ... }` block.",
2034 span,
2035 ));
2036 }
2037 let func = self.to_function(item, is_in_program_block)?;
2038 functions.push((func.identifier.name, func));
2039 }
2040 STRUCT_DEF | RECORD_DEF => {
2041 if item.kind() == STRUCT_DEF && is_in_program_block {
2042 let span = self.non_trivia_span(item);
2043 self.handler.emit_err(
2044 crate::errors::custom(
2045 "`struct` definitions are not allowed inside a `program { ... }` block.",
2046 span,
2047 )
2048 .with_help("Move the declaration outside the `program` block, to the top level of the file."),
2049 );
2050 }
2051 let composite = self.to_composite(item, is_in_program_block)?;
2052 composites.push((composite.identifier.name, composite));
2053 }
2054 GLOBAL_CONST => {
2055 if is_in_program_block {
2056 let span = self.non_trivia_span(item);
2057 self.handler.emit_err(
2058 crate::errors::custom(
2059 "`const` declarations are not allowed inside a `program { ... }` block.",
2060 span,
2061 )
2062 .with_help("Move the declaration outside the `program` block, to the top level of the file."),
2063 );
2064 }
2065 let global_const = self.to_global_const(item, is_in_program_block)?;
2066 consts.push((global_const.place.name, global_const));
2067 }
2068 INTERFACE_DEF => {
2069 if is_in_program_block {
2070 let span = self.non_trivia_span(item);
2071 self.handler.emit_err(
2072 crate::errors::custom(
2073 "`interface` definitions are not allowed inside a `program { ... }` block.",
2074 span,
2075 )
2076 .with_help("Move the declaration outside the `program` block, to the top level of the file."),
2077 );
2078 }
2079 let interface = self.to_interface(item, is_in_program_block)?;
2080 interfaces.push((interface.identifier.name, interface));
2081 }
2082 _ => {}
2083 }
2084 Ok(())
2085 }
2086
2087 fn collect_library_item(
2089 &self,
2090 item: &SyntaxNode,
2091 consts: &mut Vec<(Symbol, leo_ast::ConstDeclaration)>,
2092 structs: &mut Vec<(Symbol, leo_ast::Composite)>,
2093 functions: &mut Vec<(Symbol, leo_ast::Function)>,
2094 interfaces: &mut Vec<(Symbol, leo_ast::Interface)>,
2095 ) -> Result<()> {
2096 if is_library_item(item.kind()) {
2097 match item.kind() {
2098 GLOBAL_CONST => {
2099 let global_const = self.to_global_const(item, false)?;
2100 consts.push((global_const.place.name, global_const));
2101 }
2102 STRUCT_DEF => {
2103 let composite = self.to_composite(item, false)?;
2104 structs.push((composite.identifier.name, composite));
2105 }
2106 FUNCTION_DEF => {
2107 let func = self.to_function(item, false)?;
2109 functions.push((func.identifier.name, func));
2110 }
2111 INTERFACE_DEF => {
2112 let interface = self.to_interface(item, false)?;
2113 interfaces.push((interface.identifier.name, interface));
2114 }
2115 _ => {}
2116 }
2117 } else if item.kind() == VIEW_FN_DEF {
2118 let span = self.to_span(item);
2120 self.handler
2121 .emit_err(crate::errors::custom("`view fn` is only allowed inside a `program { ... }` block.", span));
2122 } else if is_program_item(item.kind()) {
2123 let span = self.to_span(item);
2125 self.handler.emit_err(crate::errors::custom(
2126 "Only `const` declarations, `struct` definitions, `fn` functions, and `interface` definitions are allowed in a library.",
2127 span,
2128 ));
2129 }
2130 Ok(())
2133 }
2134
2135 fn to_module(&self, node: &SyntaxNode, program_name: Symbol, path: Vec<Symbol>) -> Result<leo_ast::Module> {
2137 let mut functions = Vec::new();
2139 let mut composites = Vec::new();
2140 let mut consts = Vec::new();
2141 let mut interfaces = Vec::new();
2142
2143 for child in children(node) {
2144 if child.kind() == PROGRAM_DECL {
2145 for item in children(&child) {
2146 self.collect_program_item(
2147 &item,
2148 true,
2149 &mut functions,
2150 &mut composites,
2151 &mut consts,
2152 &mut interfaces,
2153 )?;
2154 }
2155 } else {
2156 self.collect_program_item(
2157 &child,
2158 false,
2159 &mut functions,
2160 &mut composites,
2161 &mut consts,
2162 &mut interfaces,
2163 )?;
2164 }
2165 }
2166
2167 functions.sort_by_key(|func| if func.1.variant.is_entry() { 0u8 } else { 1u8 });
2169
2170 Ok(leo_ast::Module { unit_name: program_name, path, consts, composites, functions, interfaces })
2171 }
2172
2173 fn to_main(&self, node: &SyntaxNode) -> Result<leo_ast::Program> {
2175 let mut imports = indexmap::IndexMap::new();
2177 let mut functions = Vec::new();
2178 let mut composites = Vec::new();
2179 let mut consts = Vec::new();
2180 let mut mappings = Vec::new();
2181 let mut storage_variables = Vec::new();
2182 let mut constructors = Vec::new();
2183 let mut interfaces = Vec::new();
2184 let mut program_name = None;
2185 let mut network = None;
2186 let mut parents = Vec::new();
2187 let mut span = None;
2188
2189 for child in children(node) {
2190 match child.kind() {
2191 IMPORT => {
2192 let program_id = self.import_to_program_id(&child)?;
2193 imports.insert(program_id.as_symbol(), program_id);
2194 }
2195 PROGRAM_DECL => {
2196 if program_name.is_some() {
2197 self.handler
2198 .emit_err(crate::errors::multiple_program_declarations(self.non_trivia_span(&child)));
2199 continue;
2200 }
2201 let (pname, pnetwork, pparents) = self.program_decl_to_name_with_parent(&child)?;
2203 program_name = Some(pname);
2204 network = Some(pnetwork);
2205 parents = pparents;
2206 span = Some(self.to_span(&child));
2207
2208 for item in children(&child) {
2210 self.collect_program_item(
2211 &item,
2212 true,
2213 &mut functions,
2214 &mut composites,
2215 &mut consts,
2216 &mut interfaces,
2217 )?;
2218 match item.kind() {
2219 MAPPING_DEF => {
2220 let mapping = self.to_mapping(&item)?;
2221 mappings.push((mapping.identifier.name, mapping));
2222 }
2223 STORAGE_DEF => {
2224 let storage = self.to_storage(&item)?;
2225 storage_variables.push((storage.identifier.name, storage));
2226 }
2227 CONSTRUCTOR_DEF => {
2228 constructors.push(self.to_constructor(&item)?);
2229 }
2230 _ => {}
2231 }
2232 }
2233 }
2234 _ => {
2235 self.collect_program_item(
2236 &child,
2237 false,
2238 &mut functions,
2239 &mut composites,
2240 &mut consts,
2241 &mut interfaces,
2242 )?;
2243 }
2244 }
2245 }
2246
2247 if let Some(extra) = constructors.get(1) {
2248 return Err(crate::errors::custom("A program can only have one constructor.", extra.span).into());
2249 }
2250
2251 let (Some(program_name), Some(network), Some(span)) = (program_name, network, span) else {
2252 return Err(crate::errors::missing_program_declaration(self.to_span(node)).into());
2253 };
2254
2255 functions.sort_by_key(|func| if func.1.variant.is_entry() { 0u8 } else { 1u8 });
2257
2258 let program_id = leo_ast::ProgramId { name: program_name, network };
2259 let program_id_as_symbol = program_id.as_symbol();
2260 let program_scope = leo_ast::ProgramScope {
2261 program_id,
2262 parents,
2263 consts,
2264 composites,
2265 mappings,
2266 storage_variables,
2267 functions,
2268 interfaces,
2269 constructor: constructors.pop(),
2270 span,
2271 };
2272
2273 Ok(leo_ast::Program {
2274 imports,
2275 modules: indexmap::IndexMap::new(),
2276 stubs: indexmap::IndexMap::new(),
2277 program_scopes: vec![(program_id_as_symbol, program_scope)].into_iter().collect(),
2278 })
2279 }
2280
2281 fn to_library(&self, name: Symbol, node: &SyntaxNode) -> Result<leo_ast::Library> {
2283 let mut consts = Vec::new();
2284 let mut structs = Vec::new();
2285 let mut functions = Vec::new();
2286 let mut interfaces = Vec::new();
2287
2288 for child in children(node) {
2289 self.collect_library_item(&child, &mut consts, &mut structs, &mut functions, &mut interfaces)?;
2290 }
2291
2292 Ok(leo_ast::Library {
2293 name,
2294 modules: indexmap::IndexMap::new(),
2295 consts,
2296 structs,
2297 functions,
2298 interfaces,
2299 stubs: indexmap::IndexMap::new(),
2300 })
2301 }
2302
2303 fn import_to_program_id(&self, node: &SyntaxNode) -> Result<leo_ast::ProgramId> {
2305 debug_assert_eq!(node.kind(), IMPORT);
2306 let span = self.to_span(node);
2307
2308 let program_name_text = match tokens(node).find(|t| t.kind() == IDENT) {
2310 Some(name_token) => name_token.text().to_string(),
2311 None => {
2312 self.emit_unexpected_str("import name", node.text(), span);
2313 "_error".to_string()
2314 }
2315 };
2316
2317 let network_span = tokens(node).find(|t| t.kind() == KW_ALEO).map(|t| self.token_span(&t)).unwrap_or(span); let program_id = leo_ast::ProgramId {
2321 name: leo_ast::Identifier { name: Symbol::intern(&program_name_text), span, id: self.builder.next_id() },
2322 network: leo_ast::Identifier {
2323 name: Symbol::intern("aleo"),
2324 span: network_span,
2325 id: self.builder.next_id(),
2326 },
2327 };
2328
2329 if tokens(node).all(|t| t.kind() != KW_ALEO)
2331 && let Some(net_token) = find_invalid_network(node)
2332 {
2333 self.handler.emit_err(crate::errors::invalid_network(self.token_span(&net_token)));
2334 }
2335
2336 Ok(program_id)
2337 }
2338
2339 fn program_decl_to_name(&self, node: &SyntaxNode) -> Result<(leo_ast::Identifier, leo_ast::Identifier)> {
2341 debug_assert_eq!(node.kind(), PROGRAM_DECL);
2342 let span = self.to_span(node);
2343
2344 let program_name = self.require_ident(node, "program name");
2346
2347 let network = match tokens(node).find(|t| t.kind() == KW_ALEO) {
2348 Some(aleo_token) => leo_ast::Identifier {
2349 name: Symbol::intern("aleo"),
2350 span: self.token_span(&aleo_token),
2351 id: self.builder.next_id(),
2352 },
2353 None => {
2354 if let Some(net_token) = find_invalid_network(node) {
2356 self.handler.emit_err(crate::errors::invalid_network(self.token_span(&net_token)));
2357 } else {
2358 self.emit_unexpected_str(".aleo network", node.text(), span);
2359 }
2360 leo_ast::Identifier { name: Symbol::intern("aleo"), span, id: self.builder.next_id() }
2361 }
2362 };
2363
2364 Ok((program_name, network))
2365 }
2366
2367 fn program_decl_to_name_with_parent(
2369 &self,
2370 node: &SyntaxNode,
2371 ) -> Result<(leo_ast::Identifier, leo_ast::Identifier, Parents)> {
2372 debug_assert_eq!(node.kind(), PROGRAM_DECL);
2373 let (program_name, network) = self.program_decl_to_name(node)?;
2374
2375 let parents = if let Some(parent_list) = children(node).find(|n| n.kind() == PARENT_LIST) {
2376 self.collect_parent_list(&parent_list)?
2377 } else {
2378 vec![]
2379 };
2380
2381 Ok((program_name, network, parents))
2382 }
2383
2384 fn collect_parent_list(&self, node: &SyntaxNode) -> Result<Parents> {
2385 debug_assert_eq!(node.kind(), PARENT_LIST);
2386 children(node)
2387 .filter(|n| n.kind().is_type())
2388 .map(|n| self.to_type(&n).map(|t| (self.to_span(&n), t)))
2389 .collect::<Result<Vec<_>>>()
2390 }
2391
2392 fn collect_annotations(&self, node: &SyntaxNode) -> Result<Vec<leo_ast::Annotation>> {
2394 children(node).filter(|n| n.kind() == ANNOTATION).map(|n| self.to_annotation(&n)).collect()
2395 }
2396
2397 fn require_block(&self, node: &SyntaxNode, span: Span) -> Result<leo_ast::Block> {
2399 Ok(children(node)
2400 .find(|n| n.kind() == BLOCK)
2401 .map(|n| self.to_block(&n))
2402 .transpose()?
2403 .unwrap_or_else(|| self.error_block(span)))
2404 }
2405
2406 fn to_function(&self, node: &SyntaxNode, is_in_program_block: bool) -> Result<leo_ast::Function> {
2408 debug_assert!(matches!(node.kind(), FUNCTION_DEF | FINAL_FN_DEF | VIEW_FN_DEF | CONSTRUCTOR_DEF));
2409 let span = self.span_including_annotations(node, self.non_trivia_span(node));
2410 let id = self.builder.next_id();
2411
2412 let annotations = self.collect_annotations(node)?;
2413
2414 let variant = if is_in_program_block {
2420 match node.kind() {
2421 VIEW_FN_DEF => leo_ast::Variant::View,
2422 FINAL_FN_DEF => leo_ast::Variant::FinalFn,
2423 FUNCTION_DEF | CONSTRUCTOR_DEF => leo_ast::Variant::EntryPoint,
2424 kind => unreachable!("unexpected function node kind in program block: {kind:?}"),
2425 }
2426 } else {
2427 match node.kind() {
2428 FINAL_FN_DEF => leo_ast::Variant::FinalFn,
2429 FUNCTION_DEF | VIEW_FN_DEF => leo_ast::Variant::Fn,
2430 kind => unreachable!("unexpected function node kind outside program block: {kind:?}"),
2431 }
2432 };
2433
2434 let identifier = self.require_ident(node, "function name");
2435 self.validate_identifier(&identifier);
2436
2437 let const_parameters = self.extract_const_parameters(node)?;
2438
2439 let input = children(node)
2441 .find(|n| n.kind() == PARAM_LIST)
2442 .map(|n| self.param_list_to_inputs(&n))
2443 .transpose()?
2444 .unwrap_or_default();
2445
2446 let (output, output_type) = if let Some(return_type_node) = children(node).find(|n| n.kind() == RETURN_TYPE) {
2452 self.return_type_to_outputs(&return_type_node)?
2454 } else if let Some(type_node) = children(node).find(|n| n.kind().is_type()) {
2455 let type_ = self.to_type(&type_node)?;
2457 let (mode, mode_start) = self.return_mode_before(node, &type_node);
2459 let type_span = self.content_span(&type_node);
2460 let output_span = match mode_start {
2461 Some(start) => Span::new(start, type_span.hi),
2462 None => type_span,
2463 };
2464 let output = vec![leo_ast::Output {
2465 mode,
2466 type_: leo_ast::TypeNode::new(self.interner, type_.clone(), type_span),
2467 span: output_span,
2468 id: self.builder.next_id(),
2469 }];
2470 (output, type_)
2471 } else {
2472 (Vec::new(), leo_ast::TypeKind::Unit)
2473 };
2474
2475 let block = self.require_block(node, span)?;
2476
2477 let is_exported = if is_in_program_block { None } else { Some(has_export(node)) };
2478
2479 Ok(leo_ast::Function {
2480 is_exported,
2481 annotations,
2482 variant,
2483 identifier,
2484 const_parameters,
2485 input,
2486 output,
2487 output_type,
2488 block,
2489 span,
2490 id,
2491 })
2492 }
2493
2494 fn return_mode_before(&self, parent: &SyntaxNode, type_node: &SyntaxNode) -> (leo_ast::Mode, Option<u32>) {
2500 let type_start = type_node.text_range().start();
2501 let mut mode = leo_ast::Mode::None;
2502 let mut mode_start = None;
2503 for token in tokens(parent) {
2504 let token_end = token.text_range().end();
2505 if token_end > type_start {
2506 break;
2507 }
2508 if let Some(m) = token_kind_to_mode(token.kind()) {
2509 mode = m;
2510 mode_start = Some(u32::from(token.text_range().start()) + self.start_pos);
2511 }
2512 }
2513 (mode, mode_start)
2514 }
2515
2516 fn return_type_to_outputs(&self, node: &SyntaxNode) -> Result<(Vec<leo_ast::Output>, leo_ast::TypeKind)> {
2518 debug_assert_eq!(node.kind(), RETURN_TYPE);
2519
2520 let mut outputs = Vec::new();
2523 let mut current_mode = leo_ast::Mode::None;
2524 let mut current_mode_start: Option<u32> = None;
2525
2526 for child in node.children_with_tokens() {
2527 match &child {
2528 SyntaxElement::Token(token) if !token.kind().is_trivia() => {
2529 if let Some(m) = token_kind_to_mode(token.kind()) {
2530 current_mode = m;
2531 current_mode_start = Some(u32::from(token.text_range().start()) + self.start_pos);
2532 }
2533 }
2534 SyntaxElement::Node(child_node) if child_node.kind().is_type() => {
2535 let type_ = self.to_type(child_node)?;
2536 let type_span = self.content_span(child_node);
2537 let output_span = match current_mode_start.take() {
2538 Some(start) => Span::new(start, type_span.hi),
2539 None => type_span,
2540 };
2541 outputs.push(leo_ast::Output {
2542 mode: current_mode,
2543 type_: leo_ast::TypeNode::new(self.interner, type_, type_span),
2544 span: output_span,
2545 id: self.builder.next_id(),
2546 });
2547 current_mode = leo_ast::Mode::None;
2548 }
2549 _ => {}
2550 }
2551 }
2552
2553 let output_type = match outputs.len() {
2554 0 => leo_ast::TypeKind::Unit,
2555 1 => outputs[0].type_.kind().clone(),
2556 _ => leo_ast::TupleType::new(outputs.iter().map(|o| o.type_.kind().clone()).collect()).into(),
2557 };
2558
2559 Ok((outputs, output_type))
2560 }
2561
2562 fn to_annotation(&self, node: &SyntaxNode) -> Result<leo_ast::Annotation> {
2564 debug_assert_eq!(node.kind(), ANNOTATION);
2565 let span = self.trimmed_span(node);
2566 let id = self.builder.next_id();
2567
2568 let identifier = match tokens(node).find(|t| t.kind() == IDENT || t.kind().is_keyword()) {
2571 Some(name_token) => {
2572 let name = Symbol::intern(name_token.text());
2573 let name_span = self.token_span(&name_token);
2574 leo_ast::Identifier { name, span: name_span, id: self.builder.next_id() }
2575 }
2576 None => {
2577 self.emit_unexpected_str("annotation name", node.text(), span);
2578 self.error_identifier(span)
2579 }
2580 };
2581
2582 let map = children(node)
2584 .filter(|n| n.kind() == ANNOTATION_PAIR)
2585 .filter_map(|pair| {
2586 let key =
2587 tokens(&pair).find(|t| t.kind() == IDENT || t.kind() == KW_ADDRESS || t.kind() == KW_MAPPING)?;
2588 let val = tokens(&pair).find(|t| t.kind() == STRING)?;
2589 let text = val.text();
2590 Some((Symbol::intern(key.text()), text[1..text.len() - 1].to_string()))
2591 })
2592 .collect();
2593
2594 Ok(leo_ast::Annotation { identifier, map, span, id })
2595 }
2596
2597 fn param_list_to_inputs(&self, node: &SyntaxNode) -> Result<Vec<leo_ast::Input>> {
2599 debug_assert_eq!(node.kind(), PARAM_LIST);
2600
2601 children(node)
2602 .filter(|n| matches!(n.kind(), PARAM | PARAM_PUBLIC | PARAM_PRIVATE | PARAM_CONSTANT))
2603 .map(|n| self.param_to_input(&n))
2604 .collect()
2605 }
2606
2607 fn param_to_input(&self, node: &SyntaxNode) -> Result<leo_ast::Input> {
2609 debug_assert!(matches!(node.kind(), PARAM | PARAM_PUBLIC | PARAM_PRIVATE | PARAM_CONSTANT));
2610 let span = self.non_trivia_span(node);
2611 let id = self.builder.next_id();
2612
2613 let mode = node_kind_to_mode(node.kind());
2614
2615 let identifier = self.require_ident(node, "parameter name");
2616 self.validate_identifier(&identifier);
2617
2618 let type_ = self.require_type_repr(node, "parameter type")?;
2619
2620 Ok(leo_ast::Input { identifier, mode, type_, span, id })
2621 }
2622
2623 fn to_const_parameters(&self, node: &SyntaxNode) -> Result<Vec<leo_ast::ConstParameter>> {
2625 debug_assert_eq!(node.kind(), CONST_PARAM_LIST);
2626
2627 children(node)
2628 .filter(|n| n.kind() == CONST_PARAM)
2629 .map(|n| {
2630 let span = self.non_trivia_span(&n);
2631 let id = self.builder.next_id();
2632
2633 let identifier = self.require_ident(&n, "const parameter name");
2634
2635 let type_ = self.require_type_repr(&n, "const parameter type")?;
2636
2637 Ok(leo_ast::ConstParameter { identifier, type_, span, id })
2638 })
2639 .collect()
2640 }
2641
2642 fn extract_const_parameters(&self, node: &SyntaxNode) -> Result<Vec<leo_ast::ConstParameter>> {
2644 children(node)
2645 .find(|n| n.kind() == CONST_PARAM_LIST)
2646 .map(|n| self.to_const_parameters(&n))
2647 .transpose()
2648 .map(|opt| opt.unwrap_or_default())
2649 }
2650
2651 fn to_composite(&self, node: &SyntaxNode, is_in_program_block: bool) -> Result<leo_ast::Composite> {
2653 debug_assert!(matches!(node.kind(), STRUCT_DEF | RECORD_DEF));
2654 let span = self.non_trivia_span(node);
2655 let id = self.builder.next_id();
2656
2657 let is_record = node.kind() == RECORD_DEF;
2658
2659 let identifier = self.require_ident(node, "struct/record name");
2660 self.validate_identifier(&identifier);
2661
2662 let const_parameters = self.extract_const_parameters(node)?;
2663
2664 let members = children(node)
2666 .filter(|n| {
2667 matches!(
2668 n.kind(),
2669 STRUCT_MEMBER | STRUCT_MEMBER_PUBLIC | STRUCT_MEMBER_PRIVATE | STRUCT_MEMBER_CONSTANT
2670 )
2671 })
2672 .map(|n| self.struct_member_to_member(&n))
2673 .collect::<Result<Vec<_>>>()?;
2674
2675 let is_exported = if is_record || is_in_program_block { None } else { Some(has_export(node)) };
2676
2677 Ok(leo_ast::Composite { is_exported, identifier, const_parameters, members, is_record, span, id })
2678 }
2679
2680 fn struct_member_to_member(&self, node: &SyntaxNode) -> Result<leo_ast::Member> {
2682 debug_assert!(matches!(
2683 node.kind(),
2684 STRUCT_MEMBER | STRUCT_MEMBER_PUBLIC | STRUCT_MEMBER_PRIVATE | STRUCT_MEMBER_CONSTANT
2685 ));
2686 let span = self.non_trivia_span(node);
2687 let id = self.builder.next_id();
2688
2689 let mode = node_kind_to_mode(node.kind());
2690
2691 let identifier = self.require_ident(node, "member name");
2692 self.validate_identifier(&identifier);
2693
2694 let type_ = self.require_type_repr(node, "member type")?;
2695
2696 Ok(leo_ast::Member { mode, identifier, type_, span, id })
2697 }
2698
2699 fn to_global_const(&self, node: &SyntaxNode, is_in_program_block: bool) -> Result<leo_ast::ConstDeclaration> {
2701 debug_assert_eq!(node.kind(), GLOBAL_CONST);
2702 let span = self.non_trivia_span(node);
2703 let id = self.builder.next_id();
2704
2705 let place = self.require_ident(node, "const name");
2706 self.validate_definition_identifier(&place);
2707
2708 let type_ = self.require_type_repr(node, "const type")?;
2709
2710 let value = self.require_expression(node, "const value")?;
2711
2712 let is_exported = if is_in_program_block { None } else { Some(has_export(node)) };
2713
2714 Ok(leo_ast::ConstDeclaration { is_exported, place, type_, value, span, id })
2715 }
2716
2717 fn parse_mapping_def(
2719 &self,
2720 node: &SyntaxNode,
2721 ) -> Result<(leo_ast::Identifier, leo_ast::TypeKind, leo_ast::TypeKind, Span, NodeID)> {
2722 debug_assert_eq!(node.kind(), MAPPING_DEF);
2723 let span = self.non_trivia_span(node);
2724 let id = self.builder.next_id();
2725 let identifier = self.require_ident(node, "name in mapping");
2726 let mut type_nodes = children(node).filter(|n| n.kind().is_type());
2727 let key_type = match type_nodes.next() {
2728 Some(key_node) => self.to_type(&key_node)?,
2729 None => {
2730 self.emit_unexpected_str("key type in mapping", node.text(), span);
2731 leo_ast::TypeKind::Err
2732 }
2733 };
2734 let value_type = match type_nodes.next() {
2735 Some(value_node) => self.to_type(&value_node)?,
2736 None => {
2737 self.emit_unexpected_str("value type in mapping", node.text(), span);
2738 leo_ast::TypeKind::Err
2739 }
2740 };
2741 Ok((identifier, key_type, value_type, span, id))
2742 }
2743
2744 fn to_mapping(&self, node: &SyntaxNode) -> Result<leo_ast::Mapping> {
2746 let (identifier, key_type, value_type, span, id) = self.parse_mapping_def(node)?;
2747 Ok(leo_ast::Mapping { identifier, key_type, value_type, span, id })
2748 }
2749
2750 fn to_mapping_prototype(&self, node: &SyntaxNode) -> Result<leo_ast::MappingPrototype> {
2752 let (identifier, key_type, value_type, span, id) = self.parse_mapping_def(node)?;
2753 Ok(leo_ast::MappingPrototype { identifier, key_type, value_type, span, id })
2754 }
2755
2756 fn parse_storage_def(&self, node: &SyntaxNode) -> Result<(leo_ast::Identifier, leo_ast::TypeNode, Span, NodeID)> {
2758 debug_assert_eq!(node.kind(), STORAGE_DEF);
2759 let span = self.non_trivia_span(node);
2760 let id = self.builder.next_id();
2761 let identifier = self.require_ident(node, "name in storage");
2762 let type_ = self.require_type_repr(node, "type in storage")?;
2763 Ok((identifier, type_, span, id))
2764 }
2765
2766 fn to_storage(&self, node: &SyntaxNode) -> Result<leo_ast::StorageVariable> {
2768 let (identifier, type_, span, id) = self.parse_storage_def(node)?;
2769 Ok(leo_ast::StorageVariable { identifier, type_, span, id })
2770 }
2771
2772 fn to_storage_prototype(&self, node: &SyntaxNode) -> Result<leo_ast::StorageVariablePrototype> {
2774 let (identifier, type_, span, id) = self.parse_storage_def(node)?;
2775 Ok(leo_ast::StorageVariablePrototype { identifier, type_, span, id })
2776 }
2777
2778 fn to_constructor(&self, node: &SyntaxNode) -> Result<leo_ast::Constructor> {
2780 debug_assert_eq!(node.kind(), CONSTRUCTOR_DEF);
2781 let span = self.span_including_annotations(node, self.non_trivia_span(node));
2782 let id = self.builder.next_id();
2783
2784 let annotations = self.collect_annotations(node)?;
2785 let block = self.require_block(node, span)?;
2786
2787 Ok(leo_ast::Constructor { annotations, block, span, id })
2788 }
2789
2790 fn to_interface(&self, node: &SyntaxNode, is_in_program_block: bool) -> Result<leo_ast::Interface> {
2796 debug_assert_eq!(node.kind(), INTERFACE_DEF);
2797 let span = self.to_span(node);
2798
2799 let identifier = self.require_ident(node, "interface name");
2801
2802 let parents = if let Some(parent_list) = children(node).find(|n| n.kind() == PARENT_LIST) {
2805 self.collect_parent_list(&parent_list)?
2806 } else {
2807 vec![]
2808 };
2809
2810 let mut functions = Vec::new();
2811 let mut records = Vec::new();
2812 let mut mappings = Vec::new();
2813 let mut storages = Vec::new();
2814
2815 for child in children(node) {
2816 match child.kind() {
2817 FN_PROTOTYPE_DEF => {
2818 let proto = self.to_function_prototype(&child)?;
2819 functions.push((proto.identifier.name, proto));
2820 }
2821 RECORD_PROTOTYPE_DEF => {
2822 let proto = self.to_record_prototype(&child)?;
2823 records.push((proto.identifier.name, proto));
2824 }
2825 MAPPING_DEF => {
2826 let mapping = self.to_mapping_prototype(&child)?;
2827 mappings.push(mapping);
2828 }
2829 STORAGE_DEF => {
2830 let storage = self.to_storage_prototype(&child)?;
2831 storages.push(storage);
2832 }
2833 _ => {}
2834 }
2835 }
2836
2837 let is_exported = if is_in_program_block { None } else { Some(has_export(node)) };
2838
2839 Ok(leo_ast::Interface {
2840 is_exported,
2841 identifier,
2842 parents,
2843 span,
2844 id: self.builder.next_id(),
2845 functions,
2846 records,
2847 mappings,
2848 storages,
2849 })
2850 }
2851
2852 fn to_function_prototype(&self, node: &SyntaxNode) -> Result<leo_ast::FunctionPrototype> {
2854 debug_assert_eq!(node.kind(), FN_PROTOTYPE_DEF);
2855 let span = self.to_span(node);
2856
2857 let is_view = tokens(node).any(|t| t.kind() == KW_VIEW);
2858 let variant = if is_view { leo_ast::Variant::View } else { leo_ast::Variant::EntryPoint };
2859 let identifier = self.require_ident(node, "function name");
2860
2861 let const_parameters = self.extract_const_parameters(node)?;
2863
2864 let input = children(node)
2866 .find(|n| n.kind() == PARAM_LIST)
2867 .map(|n| self.param_list_to_inputs(&n))
2868 .transpose()?
2869 .unwrap_or_default();
2870
2871 let output = if let Some(return_type_node) = children(node).find(|n| n.kind() == RETURN_TYPE) {
2874 self.return_type_to_outputs(&return_type_node)?.0
2876 } else if let Some(type_node) = children(node).find(|n| n.kind().is_type()) {
2877 let type_ = self.to_type(&type_node)?;
2879 let (mode, mode_start) = self.return_mode_before(node, &type_node);
2881 let type_span = self.content_span(&type_node);
2882 let output_span = match mode_start {
2883 Some(start) => Span::new(start, type_span.hi),
2884 None => type_span,
2885 };
2886 vec![leo_ast::Output {
2887 mode,
2888 type_: leo_ast::TypeNode::new(self.interner, type_, type_span),
2889 span: output_span,
2890 id: self.builder.next_id(),
2891 }]
2892 } else {
2893 Vec::new()
2894 };
2895
2896 Ok(leo_ast::FunctionPrototype::new(
2897 vec![], variant,
2899 identifier,
2900 const_parameters,
2901 input,
2902 output,
2903 span,
2904 self.builder.next_id(),
2905 ))
2906 }
2907
2908 fn to_record_prototype(&self, node: &SyntaxNode) -> Result<leo_ast::RecordPrototype> {
2910 debug_assert_eq!(node.kind(), RECORD_PROTOTYPE_DEF);
2911
2912 let span = self.to_span(node);
2913 let identifier = self.require_ident(node, "record name");
2914 let members = children(node)
2915 .filter(|n| {
2916 matches!(
2917 n.kind(),
2918 STRUCT_MEMBER | STRUCT_MEMBER_PUBLIC | STRUCT_MEMBER_PRIVATE | STRUCT_MEMBER_CONSTANT
2919 )
2920 })
2921 .map(|n| self.struct_member_to_member(&n))
2922 .collect::<Result<Vec<_>>>()?;
2923
2924 let is_redundant = members.is_empty()
2926 || members.iter().all(|m| {
2927 m.identifier.name == sym::owner
2928 && *m.type_.kind() == leo_ast::TypeKind::Address
2929 && m.mode == leo_ast::Mode::None
2930 });
2931 if is_redundant && !members.is_empty() {
2932 self.handler.emit_warning(crate::errors::record_prototype_redundant(identifier.name, span));
2934 return Ok(leo_ast::RecordPrototype { identifier, span, members: Vec::new(), id: self.builder.next_id() });
2935 } else if is_redundant {
2936 let had_braces = node.children_with_tokens().any(|c| c.kind() == L_BRACE);
2939 if had_braces {
2940 self.handler.emit_warning(crate::errors::record_prototype_redundant(identifier.name, span));
2941 }
2942 }
2943
2944 Ok(leo_ast::RecordPrototype { identifier, span, members, id: self.builder.next_id() })
2945 }
2946}
2947
2948fn clamped_span(range: TextRange, start_pos: u32, source_len: u32) -> Span {
2954 let end = start_pos + source_len;
2955 let lo = (u32::from(range.start()) + start_pos).min(end);
2956 let hi = (u32::from(range.end()) + start_pos).min(end).max(lo);
2957 Span::new(lo, hi)
2958}
2959
2960fn emit_lex_errors(handler: &Handler, lex_errors: &[leo_parser_rowan::LexError], start_pos: u32, source_len: u32) {
2962 use leo_parser_rowan::LexErrorKind;
2963 for error in lex_errors {
2964 let span = clamped_span(error.range, start_pos, source_len);
2965
2966 match &error.kind {
2967 LexErrorKind::InvalidDigit { digit, radix, token } => {
2968 handler.emit_err(crate::errors::wrong_digit_for_radix_span(*digit, *radix, token, span));
2969 }
2970 LexErrorKind::CouldNotLex { content } => {
2971 handler.emit_err(crate::errors::could_not_lex_span(content, span));
2972 }
2973 LexErrorKind::BidiOverride => {
2974 handler.emit_err(crate::errors::lexer_bidi_override_span(span));
2975 }
2976 }
2977 }
2978}
2979
2980fn emit_parse_errors(
2983 handler: &Handler,
2984 errors: &[leo_parser_rowan::ParseError],
2985 start_pos: u32,
2986 source_len: u32,
2987 lex_errors: &[leo_parser_rowan::LexError],
2988) {
2989 use std::collections::HashSet;
2990
2991 let has_lex_errors = !lex_errors.is_empty();
2992
2993 let lex_ranges: Vec<(u32, u32)> = lex_errors
2995 .iter()
2996 .map(|e| {
2997 let lo = u32::from(e.range.start()).saturating_add(start_pos);
2998 let hi = u32::from(e.range.end()).saturating_add(start_pos);
2999 (lo, hi)
3000 })
3001 .collect();
3002
3003 let mut emitted_ranges: HashSet<(u32, u32)> = HashSet::new();
3005 let mut count = 0;
3006 let max_errors = 10;
3007
3008 for error in errors {
3009 if count >= max_errors {
3010 break;
3011 }
3012
3013 let span = clamped_span(error.range, start_pos, source_len);
3014 let range_key = (span.lo, span.hi);
3015
3016 if emitted_ranges.contains(&range_key) {
3018 continue;
3019 }
3020
3021 if has_lex_errors && span.lo == span.hi && span.hi == start_pos + source_len {
3024 continue;
3025 }
3026
3027 if lex_ranges.iter().any(|&(lo, hi)| span.lo < hi && span.hi > lo) {
3030 continue;
3031 }
3032
3033 emitted_ranges.insert(range_key);
3034
3035 let is_eof_error = match &error.found {
3038 Some(f) => f.is_empty() || f == "end of file",
3039 None => false,
3040 } || (span.lo == span.hi && span.hi >= start_pos + source_len);
3041
3042 if is_eof_error {
3043 handler.emit_err(crate::errors::unexpected_eof(span));
3044 count += 1;
3045 continue;
3046 }
3047
3048 if let Some(found) = &error.found {
3050 if error.expected.is_empty() {
3051 handler.emit_err(crate::errors::custom(&error.message, span));
3054 } else {
3055 let expected_str = error.expected.join(", ");
3056 handler.emit_err(crate::errors::unexpected(found, expected_str, span));
3057 }
3058 count += 1;
3059 continue;
3060 }
3061
3062 handler.emit_err(crate::errors::custom(&error.message, span));
3064 count += 1;
3065 }
3066}
3067
3068fn conversion_context<'a>(
3070 handler: &'a Handler,
3071 node_builder: &'a NodeBuilder,
3072 interner: &'a TypeInterner,
3073 lex_errors: &[leo_parser_rowan::LexError],
3074 parse_errors: &[leo_parser_rowan::ParseError],
3075 start_pos: u32,
3076 source_len: u32,
3077) -> ConversionContext<'a> {
3078 emit_lex_errors(handler, lex_errors, start_pos, source_len);
3079 emit_parse_errors(handler, parse_errors, start_pos, source_len, lex_errors);
3080 let has_errors = !parse_errors.is_empty() || !lex_errors.is_empty();
3081 ConversionContext::new(handler, node_builder, interner, start_pos, has_errors)
3082}
3083
3084pub fn parse_expression(
3086 handler: Handler,
3087 node_builder: &NodeBuilder,
3088 interner: &TypeInterner,
3089 source: &str,
3090 start_pos: u32,
3091 _network: NetworkName,
3092) -> Result<leo_ast::Expression> {
3093 let parse = leo_parser_rowan::parse_expression_entry(source);
3094 let ctx = conversion_context(
3095 &handler,
3096 node_builder,
3097 interner,
3098 parse.lex_errors(),
3099 parse.errors(),
3100 start_pos,
3101 source.len() as u32,
3102 );
3103 ctx.to_expression(&parse.syntax())
3104}
3105
3106pub fn parse_statement(
3108 handler: Handler,
3109 node_builder: &NodeBuilder,
3110 interner: &TypeInterner,
3111 source: &str,
3112 start_pos: u32,
3113 _network: NetworkName,
3114) -> Result<leo_ast::Statement> {
3115 let parse = leo_parser_rowan::parse_statement_entry(source);
3116 let ctx = conversion_context(
3117 &handler,
3118 node_builder,
3119 interner,
3120 parse.lex_errors(),
3121 parse.errors(),
3122 start_pos,
3123 source.len() as u32,
3124 );
3125 ctx.to_statement(&parse.syntax())
3126}
3127
3128#[allow(clippy::too_many_arguments)]
3130pub fn parse_module(
3131 handler: Handler,
3132 node_builder: &NodeBuilder,
3133 interner: &TypeInterner,
3134 source: &str,
3135 start_pos: u32,
3136 program_name: Symbol,
3137 path: Vec<Symbol>,
3138 _network: NetworkName,
3139) -> Result<leo_ast::Module> {
3140 let parse = leo_parser_rowan::parse_module_entry(source);
3141 let ctx = conversion_context(
3142 &handler,
3143 node_builder,
3144 interner,
3145 parse.lex_errors(),
3146 parse.errors(),
3147 start_pos,
3148 source.len() as u32,
3149 );
3150 ctx.to_module(&parse.syntax(), program_name, path)
3151}
3152
3153pub fn parse_program(
3155 handler: Handler,
3156 node_builder: &NodeBuilder,
3157 interner: &TypeInterner,
3158 source: &SourceFile,
3159 modules: &[std::rc::Rc<SourceFile>],
3160 _network: NetworkName,
3161) -> Result<leo_ast::Program> {
3162 let parse = leo_parser_rowan::parse_file(&source.src);
3164 let main_context = conversion_context(
3165 &handler,
3166 node_builder,
3167 interner,
3168 parse.lex_errors(),
3169 parse.errors(),
3170 source.absolute_start,
3171 source.src.len() as u32,
3172 );
3173 let mut program = main_context.to_main(&parse.syntax())?;
3174 let program_name = *program.program_scopes.first().unwrap().0;
3175
3176 let root_dir = match &source.name {
3178 FileName::Real(path) => path.parent().map(|p| p.to_path_buf()),
3179 _ => None,
3180 };
3181
3182 for module in modules {
3183 let module_parse = leo_parser_rowan::parse_module_entry(&module.src);
3184 let module_context = conversion_context(
3185 &handler,
3186 node_builder,
3187 interner,
3188 module_parse.lex_errors(),
3189 module_parse.errors(),
3190 module.absolute_start,
3191 module.src.len() as u32,
3192 );
3193
3194 if let Some(key) = compute_module_key(&module.name, root_dir.as_deref()) {
3195 for segment in &key {
3196 if leo_parser_rowan::is_keyword(&segment.to_string()) {
3197 return Err(crate::errors::keyword_used_as_module_name(key.iter().format("::"), segment).into());
3198 }
3199 }
3200 let module_ast = module_context.to_module(&module_parse.syntax(), program_name, key.clone())?;
3201 program.modules.insert(key, module_ast);
3202 }
3203 }
3204
3205 Ok(program)
3206}
3207
3208pub fn parse_library(
3210 handler: Handler,
3211 node_builder: &NodeBuilder,
3212 interner: &TypeInterner,
3213 library_name: Symbol,
3214 source: &SourceFile,
3215 modules: &[std::rc::Rc<SourceFile>],
3216 _network: NetworkName,
3217) -> Result<leo_ast::Library> {
3218 let parse = leo_parser_rowan::parse_file(&source.src);
3220 let main_context = conversion_context(
3221 &handler,
3222 node_builder,
3223 interner,
3224 parse.lex_errors(),
3225 parse.errors(),
3226 source.absolute_start,
3227 source.src.len() as u32,
3228 );
3229
3230 let mut library = main_context.to_library(library_name, &parse.syntax())?;
3231
3232 let root_dir = match &source.name {
3234 FileName::Real(path) => path.parent().map(|p| p.to_path_buf()),
3235 _ => None,
3236 };
3237
3238 for module_sf in modules {
3240 let module_parse = leo_parser_rowan::parse_module_entry(&module_sf.src);
3241 let module_context = conversion_context(
3242 &handler,
3243 node_builder,
3244 interner,
3245 module_parse.lex_errors(),
3246 module_parse.errors(),
3247 module_sf.absolute_start,
3248 module_sf.src.len() as u32,
3249 );
3250
3251 if let Some(key) = compute_module_key(&module_sf.name, root_dir.as_deref()) {
3252 for segment in &key {
3253 if leo_parser_rowan::is_keyword(&segment.to_string()) {
3254 return Err(crate::errors::keyword_used_as_module_name(key.iter().format("::"), segment).into());
3255 }
3256 }
3257 let module_ast = module_context.to_module(&module_parse.syntax(), library_name, key.clone())?;
3260 library.modules.insert(key, module_ast);
3261 }
3262 }
3263
3264 Ok(library)
3265}
3266
3267fn children(node: &SyntaxNode) -> impl Iterator<Item = SyntaxNode> + '_ {
3273 node.children().filter(|n| !n.kind().is_trivia())
3274}
3275
3276fn tokens(node: &SyntaxNode) -> impl Iterator<Item = SyntaxToken> + '_ {
3278 node.children_with_tokens().filter_map(|elem| elem.into_token()).filter(|t| !t.kind().is_trivia())
3279}
3280
3281fn has_export(node: &SyntaxNode) -> bool {
3283 tokens(node).any(|t| t.kind() == KW_EXPORT)
3284}
3285
3286fn find_name_after_dot(node: &SyntaxNode) -> Option<SyntaxToken> {
3288 let dot_end = tokens(node).find(|t| t.kind() == DOT)?.text_range().end();
3289 tokens(node).filter(|t| t.text_range().start() >= dot_end).find(|t| t.kind() == IDENT || t.kind().is_keyword())
3290}
3291
3292fn first_non_trivia_token(node: &SyntaxNode) -> Option<SyntaxToken> {
3294 node.children_with_tokens().find_map(|e| e.into_token().filter(|t| !t.kind().is_trivia()))
3295}
3296
3297fn last_non_trivia_token(node: &SyntaxNode) -> Option<SyntaxToken> {
3299 node.children_with_tokens().filter_map(|e| e.into_token().filter(|t| !t.kind().is_trivia())).last()
3300}
3301
3302fn find_invalid_network(node: &SyntaxNode) -> Option<SyntaxToken> {
3304 let mut saw_dot = false;
3305 tokens(node).find(|t| {
3306 if t.kind() == DOT {
3307 saw_dot = true;
3308 return false;
3309 }
3310 saw_dot && t.kind() == IDENT
3311 })
3312}
3313
3314fn token_kind_to_mode(kind: SyntaxKind) -> Option<leo_ast::Mode> {
3316 match kind {
3317 KW_PUBLIC => Some(leo_ast::Mode::Public),
3318 KW_PRIVATE => Some(leo_ast::Mode::Private),
3319 KW_CONSTANT => Some(leo_ast::Mode::Constant),
3320 _ => None,
3321 }
3322}
3323
3324fn node_kind_to_mode(kind: SyntaxKind) -> leo_ast::Mode {
3326 match kind {
3327 PARAM_PUBLIC | STRUCT_MEMBER_PUBLIC => leo_ast::Mode::Public,
3328 PARAM_PRIVATE | STRUCT_MEMBER_PRIVATE => leo_ast::Mode::Private,
3329 PARAM_CONSTANT | STRUCT_MEMBER_CONSTANT => leo_ast::Mode::Constant,
3330 _ => leo_ast::Mode::None,
3331 }
3332}
3333
3334fn keyword_to_path_symbol(kind: SyntaxKind) -> Option<Symbol> {
3336 match kind {
3337 KW_SELF => Some(sym::SelfLower),
3338 KW_BLOCK => Some(sym::block),
3339 KW_NETWORK => Some(sym::network),
3340 KW_FINAL_UPPER => Some(sym::Final),
3341 _ => None,
3342 }
3343}
3344
3345fn is_assign_op(kind: SyntaxKind) -> bool {
3347 matches!(
3348 kind,
3349 EQ | PLUS_EQ
3350 | MINUS_EQ
3351 | STAR_EQ
3352 | SLASH_EQ
3353 | PERCENT_EQ
3354 | STAR2_EQ
3355 | AMP_EQ
3356 | PIPE_EQ
3357 | CARET_EQ
3358 | SHL_EQ
3359 | SHR_EQ
3360 | AMP2_EQ
3361 | PIPE2_EQ
3362 )
3363}
3364fn keyword_to_primitive_type(kind: SyntaxKind) -> Option<leo_ast::TypeKind> {
3366 let ty = match kind {
3367 KW_ADDRESS => leo_ast::TypeKind::Address,
3368 KW_BOOL => leo_ast::TypeKind::Boolean,
3369 KW_FIELD => leo_ast::TypeKind::Field,
3370 KW_GROUP => leo_ast::TypeKind::Group,
3371 KW_SCALAR => leo_ast::TypeKind::Scalar,
3372 KW_SIGNATURE => leo_ast::TypeKind::Signature,
3373 KW_STRING => leo_ast::TypeKind::String,
3374 KW_DYN => leo_ast::TypeKind::DynRecord,
3375 KW_IDENTIFIER => leo_ast::TypeKind::Identifier,
3376 KW_U8 => leo_ast::TypeKind::Integer(leo_ast::IntegerType::U8),
3377 KW_U16 => leo_ast::TypeKind::Integer(leo_ast::IntegerType::U16),
3378 KW_U32 => leo_ast::TypeKind::Integer(leo_ast::IntegerType::U32),
3379 KW_U64 => leo_ast::TypeKind::Integer(leo_ast::IntegerType::U64),
3380 KW_U128 => leo_ast::TypeKind::Integer(leo_ast::IntegerType::U128),
3381 KW_I8 => leo_ast::TypeKind::Integer(leo_ast::IntegerType::I8),
3382 KW_I16 => leo_ast::TypeKind::Integer(leo_ast::IntegerType::I16),
3383 KW_I32 => leo_ast::TypeKind::Integer(leo_ast::IntegerType::I32),
3384 KW_I64 => leo_ast::TypeKind::Integer(leo_ast::IntegerType::I64),
3385 KW_I128 => leo_ast::TypeKind::Integer(leo_ast::IntegerType::I128),
3386 _ => return None,
3387 };
3388 Some(ty)
3389}
3390
3391fn token_to_binary_op(kind: SyntaxKind) -> leo_ast::BinaryOperation {
3393 match kind {
3394 EQ2 => leo_ast::BinaryOperation::Eq,
3395 BANG_EQ => leo_ast::BinaryOperation::Neq,
3396 LT => leo_ast::BinaryOperation::Lt,
3397 LT_EQ => leo_ast::BinaryOperation::Lte,
3398 GT => leo_ast::BinaryOperation::Gt,
3399 GT_EQ => leo_ast::BinaryOperation::Gte,
3400 PLUS => leo_ast::BinaryOperation::Add,
3401 MINUS => leo_ast::BinaryOperation::Sub,
3402 STAR => leo_ast::BinaryOperation::Mul,
3403 SLASH => leo_ast::BinaryOperation::Div,
3404 PERCENT => leo_ast::BinaryOperation::Rem,
3405 PIPE2 => leo_ast::BinaryOperation::Or,
3406 AMP2 => leo_ast::BinaryOperation::And,
3407 PIPE => leo_ast::BinaryOperation::BitwiseOr,
3408 AMP => leo_ast::BinaryOperation::BitwiseAnd,
3409 STAR2 => leo_ast::BinaryOperation::Pow,
3410 SHL => leo_ast::BinaryOperation::Shl,
3411 SHR => leo_ast::BinaryOperation::Shr,
3412 CARET => leo_ast::BinaryOperation::Xor,
3413 _ => panic!("unexpected binary operator: {:?}", kind),
3414 }
3415}
3416
3417fn compute_module_key(name: &FileName, root_dir: Option<&std::path::Path>) -> Option<Vec<Symbol>> {
3419 let path = match name {
3420 FileName::Custom(name) => std::path::Path::new(name).to_path_buf(),
3421 FileName::Real(path) => {
3422 let root = root_dir?;
3423 path.strip_prefix(root).ok()?.to_path_buf()
3424 }
3425 };
3426
3427 let mut key: Vec<Symbol> =
3428 path.components().map(|comp| Symbol::intern(&comp.as_os_str().to_string_lossy())).collect();
3429
3430 if let Some(last) = path.file_name()
3431 && let Some(stem) = std::path::Path::new(last).file_stem()
3432 {
3433 key.pop();
3434 key.push(Symbol::intern(&stem.to_string_lossy()));
3435 }
3436
3437 Some(key)
3438}
3439
3440fn is_library_item(kind: SyntaxKind) -> bool {
3442 matches!(kind, GLOBAL_CONST | STRUCT_DEF | FUNCTION_DEF | INTERFACE_DEF)
3443}
3444
3445fn is_program_item(kind: SyntaxKind) -> bool {
3447 matches!(
3448 kind,
3449 GLOBAL_CONST
3450 | FUNCTION_DEF
3451 | FINAL_FN_DEF
3452 | VIEW_FN_DEF
3453 | STRUCT_DEF
3454 | RECORD_DEF
3455 | INTERFACE_DEF
3456 | MAPPING_DEF
3457 | STORAGE_DEF
3458 | CONSTRUCTOR_DEF
3459 | PROGRAM_DECL
3460 | IMPORT
3461 )
3462}