1use crate::{Token, tokenizer::*};
23
24use leo_ast::*;
25use leo_errors::{Handler, ParserError, Result};
26use leo_span::{
27 Span,
28 Symbol,
29 source_map::{FileName, SourceFile},
30};
31
32use indexmap::IndexMap;
33use itertools::Itertools;
34
35mod context;
36pub(super) use context::ParserContext;
37
38mod expression;
39mod file;
40mod statement;
41pub(super) mod type_;
42
43pub fn parse(
56 handler: Handler,
57 node_builder: &NodeBuilder,
58 source: &SourceFile,
59 modules: &[std::rc::Rc<SourceFile>],
60 network: NetworkName,
61) -> Result<Program> {
62 let mut tokens = ParserContext::new(
64 &handler,
65 node_builder,
66 crate::tokenize(&source.src, source.absolute_start)?,
67 None, network,
69 );
70
71 let mut program = tokens.parse_program()?;
73 let program_name = tokens.program_name;
74
75 let root_dir = match &source.name {
77 FileName::Real(path) => path.parent().map(|p| p.to_path_buf()),
78 _ => None,
79 };
80
81 for module in modules {
83 let mut module_tokens = ParserContext::new(
84 &handler,
85 node_builder,
86 crate::tokenize(&module.src, module.absolute_start)?,
87 program_name,
88 network,
89 );
90
91 if let Some(key) = compute_module_key(&module.name, root_dir.as_deref()) {
93 for segment in &key {
95 if let Some(keyword) = Token::symbol_to_keyword(*segment) {
96 return Err(
97 ParserError::keyword_used_as_module_name(key.iter().format("::").to_string(), keyword).into()
98 );
99 }
100 }
101
102 let module_ast = module_tokens.parse_module(&key)?;
103 program.modules.insert(key, module_ast);
104 }
105 }
106
107 Ok(program)
108}
109
110fn compute_module_key(name: &FileName, root_dir: Option<&std::path::Path>) -> Option<Vec<Symbol>> {
123 let path = match name {
125 FileName::Custom(name) => std::path::Path::new(name).to_path_buf(),
126 FileName::Real(path) => {
127 let root = root_dir?;
128 path.strip_prefix(root).ok()?.to_path_buf()
129 }
130 };
131
132 let mut key: Vec<Symbol> =
134 path.components().map(|comp| Symbol::intern(&comp.as_os_str().to_string_lossy())).collect();
135
136 if let Some(last) = path.file_name() {
138 if let Some(stem) = std::path::Path::new(last).file_stem() {
139 key.pop(); key.push(Symbol::intern(&stem.to_string_lossy())); }
142 }
143
144 Some(key)
145}
146
147pub fn parse_module(
148 handler: Handler,
149 node_builder: &NodeBuilder,
150 mod_path: &[Symbol],
151 source: &str,
152 start_pos: u32,
153 network: NetworkName,
154) -> Result<Module> {
155 let mut context = ParserContext::new(&handler, node_builder, crate::tokenize(source, start_pos)?, None, network);
156
157 let module = context.parse_module(mod_path)?;
158 if context.token.token == Token::Eof {
159 Ok(module)
160 } else {
161 Err(ParserError::unexpected(context.token.token, Token::Eof, context.token.span).into())
162 }
163}
164
165pub fn parse_expression(
166 handler: Handler,
167 node_builder: &NodeBuilder,
168 source: &str,
169 start_pos: u32,
170 network: NetworkName,
171) -> Result<Expression> {
172 let mut context = ParserContext::new(&handler, node_builder, crate::tokenize(source, start_pos)?, None, network);
173
174 let expression = context.parse_expression()?;
175 if context.token.token == Token::Eof {
176 Ok(expression)
177 } else {
178 Err(ParserError::unexpected(context.token.token, Token::Eof, context.token.span).into())
179 }
180}
181
182pub fn parse_statement(
183 handler: Handler,
184 node_builder: &NodeBuilder,
185 source: &str,
186 start_pos: u32,
187 network: NetworkName,
188) -> Result<Statement> {
189 let mut context = ParserContext::new(&handler, node_builder, crate::tokenize(source, start_pos)?, None, network);
190
191 let statement = context.parse_statement()?;
192 if context.token.token == Token::Eof {
193 Ok(statement)
194 } else {
195 Err(ParserError::unexpected(context.token.token, Token::Eof, context.token.span).into())
196 }
197}