1extern crate num_bigint_dig as num_bigint;
2extern crate num_traits;
3extern crate serde;
4extern crate serde_derive;
5#[macro_use]
6extern crate lalrpop_util;
7
8lalrpop_mod!(pub lang);
9
10mod include_logic;
11mod parser_logic;
12mod syntax_sugar_remover;
13
14use include_logic::{FileStack, IncludesGraph};
15use program_structure::ast::{produce_compiler_version_report, produce_report, produce_report_with_message, produce_version_warning_report, Expression};
16use program_structure::error_code::ReportCode;
17use program_structure::error_definition::ReportCollection;
18use program_structure::error_definition::Report;
19use program_structure::file_definition::{FileLibrary};
20use program_structure::program_archive::ProgramArchive;
21use std::path::{PathBuf, Path};
22use syntax_sugar_remover::{apply_syntactic_sugar};
23
24use std::str::FromStr;
25
26pub type Version = (usize, usize, usize);
27
28pub fn find_file(
29 crr_file: PathBuf,
30 ext_link_libraries: Vec<PathBuf>,
31) -> (bool, String, String, PathBuf, Vec<Report>) {
32 let mut found = false;
33 let mut path = "".to_string();
34 let mut src = "".to_string();
35 let mut crr_str_file = crr_file.clone();
36 let mut reports = Vec::new();
37 let mut i = 0;
38 while !found && i < ext_link_libraries.len() {
39 let mut p = PathBuf::new();
40 let aux = ext_link_libraries.get(i).unwrap();
41 p.push(aux);
42 p.push(crr_file.clone());
43 crr_str_file = p;
44 match open_file(crr_str_file.clone()) {
45 Ok((new_path, new_src)) => {
46 path = new_path;
47 src = new_src;
48 found = true;
49 }
50 Err(e) => {
51 reports.push(e);
52 i = i + 1;
53 }
54 }
55 }
56 (found, path, src, crr_str_file, reports)
57}
58
59pub fn run_parser(
60 file: String,
61 version: &str,
62 link_libraries: Vec<PathBuf>,
63) -> Result<(ProgramArchive, ReportCollection), (FileLibrary, ReportCollection)> {
64 let mut file_library = FileLibrary::new();
65 let mut definitions = Vec::new();
66 let mut main_components = Vec::new();
67 let mut file_stack = FileStack::new(PathBuf::from(file));
68 let mut includes_graph = IncludesGraph::new();
69 let mut warnings = Vec::new();
70 let mut link_libraries2 = link_libraries.clone();
71 let mut ext_link_libraries = vec![Path::new("").to_path_buf()];
72 ext_link_libraries.append(&mut link_libraries2);
73 while let Some(crr_file) = FileStack::take_next(&mut file_stack) {
74 let (found, path, src, crr_str_file, reports) =
75 find_file(crr_file, ext_link_libraries.clone());
76 if !found {
77 return Result::Err((file_library.clone(), reports));
78 }
79 let file_id = file_library.add_file(path.clone(), src.clone());
80 let program =
81 parser_logic::parse_file(&src, file_id).map_err(|e| (file_library.clone(), e))?;
82 if let Some(main) = program.main_component {
83 main_components.push((file_id, main, program.custom_gates));
84 }
85 includes_graph.add_node(crr_str_file, program.custom_gates, program.custom_gates_declared);
86 let includes = program.includes;
87 definitions.push((file_id, program.definitions));
88 for include in includes {
89 let path_include =
90 FileStack::add_include(&mut file_stack, include.clone(), &link_libraries.clone())
91 .map_err(|e| (file_library.clone(), vec![e]))?;
92 includes_graph.add_edge(path_include).map_err(|e| (file_library.clone(), vec![e]))?;
93 }
94 warnings.append(
95 &mut check_number_version(
96 path.clone(),
97 program.compiler_version,
98 parse_number_version(version),
99 )
100 .map_err(|e| (file_library.clone(), vec![e]))?,
101 );
102 if program.custom_gates {
103 check_custom_gates_version(
104 path,
105 program.compiler_version,
106 parse_number_version(version),
107 )
108 .map_err(|e| (file_library.clone(), vec![e]))?
109 }
110 }
111
112 if main_components.len() == 0 {
113 let report = produce_report(ReportCode::NoMainFoundInProject,0..0, 0);
114 warnings.push(report);
115 Err((file_library, warnings))
116 } else if main_components.len() > 1 {
117 let report = produce_report_with_main_components(main_components);
118 warnings.push(report);
119 Err((file_library, warnings))
120 } else {
121 let mut errors: ReportCollection = includes_graph.get_problematic_paths().iter().map(|path|
122 Report::error(
123 format!(
124 "Missing custom templates pragma in file {} because of the following chain of includes {}",
125 path.last().unwrap().display(),
126 IncludesGraph::display_path(path)
127 ),
128 ReportCode::CustomGatesPragmaError
129 )
130 ).collect();
131 if errors.len() > 0 {
132 warnings.append(& mut errors);
133 Err((file_library, warnings))
134 } else {
135 let (main_id, main_component, custom_gates) = main_components.pop().unwrap();
136 let result_program_archive = ProgramArchive::new(
137 file_library,
138 main_id,
139 main_component,
140 definitions,
141 custom_gates,
142 );
143 match result_program_archive {
144 Err((lib, mut rep)) => {
145 warnings.append(&mut rep);
146 Err((lib, warnings))
147 }
148 Ok(mut program_archive) => {
149 let lib = program_archive.get_file_library().clone();
150 let program_archive_result = apply_syntactic_sugar( &mut program_archive);
151 match program_archive_result {
152 Result::Err(v) => {
153 warnings.push(v);
154 Result::Err((lib,warnings))},
155 Result::Ok(_) => Ok((program_archive, warnings)),
156 }
157 }
158 }
159 }
160 }
161}
162
163fn produce_report_with_main_components(main_components: Vec<(usize, (Vec<String>, Expression), bool)>) -> Report {
164 let mut j = 0;
165 let mut r = produce_report(ReportCode::MultipleMain, 0..0, 0);
166 for (i,exp,_) in main_components{
167 if j > 0 {
168 r.add_secondary(exp.1.get_meta().location.clone(), i, Option::Some("Here it is another main component".to_string()));
169 }
170 else {
171 r.add_primary(exp.1.get_meta().location.clone(), i, "This is a main component".to_string());
172 }
173 j+=1;
174 }
175 r
176}
177
178fn open_file(path: PathBuf) -> Result<(String, String), Report> {
179 use std::fs::read_to_string;
180 let path_str = format!("{:?}", path);
181 read_to_string(path)
182 .map(|contents| (path_str.clone(), contents))
183 .map_err(|_| produce_report_with_message(ReportCode::FileOs, path_str.clone()))
184}
185
186fn parse_number_version(version: &str) -> Version {
187 let version_splitted: Vec<&str> = version.split(".").collect();
188 (
189 usize::from_str(version_splitted[0]).unwrap(),
190 usize::from_str(version_splitted[1]).unwrap(),
191 usize::from_str(version_splitted[2]).unwrap(),
192 )
193}
194
195fn check_number_version(
196 file_path: String,
197 version_file: Option<Version>,
198 version_compiler: Version,
199) -> Result<ReportCollection, Report> {
200 if let Some(required_version) = version_file {
201 if required_version.0 == version_compiler.0
202 && (required_version.1 < version_compiler.1
203 || (required_version.1 == version_compiler.1
204 && required_version.2 <= version_compiler.2))
205 {
206 Ok(vec![])
207 } else {
208 Err(produce_compiler_version_report(file_path, required_version, version_compiler))
209 }
210 } else {
211 let report =
212 produce_version_warning_report(file_path, version_compiler);
213 Ok(vec![report])
214 }
215}
216
217fn check_custom_gates_version(
218 file_path: String,
219 version_file: Option<Version>,
220 version_compiler: Version,
221) -> Result<(), Report> {
222 let custom_gates_version: Version = (2, 0, 6);
223 if let Some(required_version) = version_file {
224 if required_version.0 < custom_gates_version.0
225 || (required_version.0 == custom_gates_version.0
226 && required_version.1 < custom_gates_version.1)
227 || (required_version.0 == custom_gates_version.0
228 && required_version.1 == custom_gates_version.1
229 && required_version.2 < custom_gates_version.2)
230 {
231 let report = Report::error(
232 format!(
233 "File {} requires at least version {:?} to use custom templates (currently {:?})",
234 file_path,
235 custom_gates_version,
236 required_version
237 ),
238 ReportCode::CustomGatesVersionError
239 );
240 return Err(report);
241 }
242 } else {
243 if version_compiler.0 < custom_gates_version.0
244 || (version_compiler.0 == custom_gates_version.0
245 && version_compiler.1 < custom_gates_version.1)
246 || (version_compiler.0 == custom_gates_version.0
247 && version_compiler.1 == custom_gates_version.1
248 && version_compiler.2 < custom_gates_version.2)
249 {
250 let report = Report::error(
251 format!(
252 "File {} does not include pragma version and the compiler version (currently {:?}) should be at least {:?} to use custom templates",
253 file_path,
254 version_compiler,
255 custom_gates_version
256 ),
257 ReportCode::CustomGatesVersionError
258 );
259 return Err(report);
260 }
261 }
262 Ok(())
263}