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