1use itertools::Itertools as _;
28
29use leo_ast::{NetworkName, NodeBuilder};
30use leo_errors::{Handler, ParserError, Result};
31use leo_span::{
32 Symbol,
33 source_map::{FileName, SourceFile},
34 sym,
35};
36
37mod conversions;
38
39#[cfg(test)]
40mod test;
41
42pub fn parse_expression(
43 handler: Handler,
44 node_builder: &NodeBuilder,
45 source: &str,
46 start_pos: u32,
47 _network: NetworkName,
48) -> Result<leo_ast::Expression> {
49 let node = leo_parser_lossless::parse_expression(handler.clone(), source, start_pos)?;
50 conversions::to_expression(&node, node_builder, &handler)
51}
52
53pub fn parse_statement(
54 handler: Handler,
55 node_builder: &NodeBuilder,
56 source: &str,
57 start_pos: u32,
58 _network: NetworkName,
59) -> Result<leo_ast::Statement> {
60 let node = leo_parser_lossless::parse_statement(handler.clone(), source, start_pos)?;
61 conversions::to_statement(&node, node_builder, &handler)
62}
63
64pub fn parse_module(
65 handler: Handler,
66 node_builder: &NodeBuilder,
67 source: &str,
68 start_pos: u32,
69 program_name: Symbol,
70 path: Vec<Symbol>,
71 _network: NetworkName,
72) -> Result<leo_ast::Module> {
73 let node_module = leo_parser_lossless::parse_module(handler.clone(), source, start_pos)?;
74 conversions::to_module(&node_module, node_builder, program_name, path, &handler)
75}
76
77pub fn parse(
78 handler: Handler,
79 node_builder: &NodeBuilder,
80 source: &SourceFile,
81 modules: &[std::rc::Rc<SourceFile>],
82 _network: NetworkName,
83) -> Result<leo_ast::Program> {
84 let program_node = leo_parser_lossless::parse_main(handler.clone(), &source.src, source.absolute_start)?;
85 let mut program = conversions::to_main(&program_node, node_builder, &handler)?;
86 let program_name = *program.program_scopes.first().unwrap().0;
87
88 let root_dir = match &source.name {
90 FileName::Real(path) => path.parent().map(|p| p.to_path_buf()),
91 _ => None,
92 };
93
94 for module in modules {
95 let node_module = leo_parser_lossless::parse_module(handler.clone(), &module.src, module.absolute_start)?;
96 if let Some(key) = compute_module_key(&module.name, root_dir.as_deref()) {
97 for segment in &key {
99 if symbol_is_keyword(*segment) {
100 return Err(ParserError::keyword_used_as_module_name(key.iter().format("::"), segment).into());
101 }
102 }
103
104 let module_ast = conversions::to_module(&node_module, node_builder, program_name, key.clone(), &handler)?;
105 program.modules.insert(key, module_ast);
106 }
107 }
108
109 Ok(program)
110}
111
112pub fn parse_ast(
114 handler: Handler,
115 node_builder: &NodeBuilder,
116 source: &SourceFile,
117 modules: &[std::rc::Rc<SourceFile>],
118 network: NetworkName,
119) -> Result<leo_ast::Ast> {
120 Ok(leo_ast::Ast::new(parse(handler, node_builder, source, modules, network)?))
121}
122
123fn symbol_is_keyword(symbol: Symbol) -> bool {
124 matches!(
125 symbol,
126 sym::address |
127 sym::aleo |
128 sym::As |
129 sym::assert |
130 sym::assert_eq |
131 sym::assert_neq |
132 sym::Async | sym::block |
134 sym::bool |
135 sym::Const |
136 sym::constant |
137 sym::constructor |
138 sym::Else |
139 sym::False |
140 sym::field |
141 sym::Fn |
142 sym::For |
143 sym::function |
144 sym::Future |
145 sym::group |
146 sym::i8 |
147 sym::i16 |
148 sym::i32 |
149 sym::i64 |
150 sym::i128 |
151 sym::If |
152 sym::import |
153 sym::In |
154 sym::inline |
155 sym::Let |
156 sym::leo |
157 sym::mapping |
158 sym::storage |
159 sym::network |
160 sym::private |
161 sym::program |
162 sym::public |
163 sym::record |
164 sym::Return |
165 sym::scalar |
166 sym::script |
167 sym::SelfLower |
168 sym::signature |
169 sym::string |
170 sym::Struct |
171 sym::transition |
172 sym::True |
173 sym::u8 |
174 sym::u16 |
175 sym::u32 |
176 sym::u64 |
177 sym::u128
178 )
179}
180
181fn compute_module_key(name: &FileName, root_dir: Option<&std::path::Path>) -> Option<Vec<Symbol>> {
194 let path = match name {
196 FileName::Custom(name) => std::path::Path::new(name).to_path_buf(),
197 FileName::Real(path) => {
198 let root = root_dir?;
199 path.strip_prefix(root).ok()?.to_path_buf()
200 }
201 };
202
203 let mut key: Vec<Symbol> =
205 path.components().map(|comp| Symbol::intern(&comp.as_os_str().to_string_lossy())).collect();
206
207 if let Some(last) = path.file_name()
209 && let Some(stem) = std::path::Path::new(last).file_stem()
210 {
211 key.pop(); key.push(Symbol::intern(&stem.to_string_lossy())); }
214
215 Some(key)
216}