mxmlextrema_as3parser/compilation_unit/
compilation_unit.rs1use std::{any::Any, cell::RefMut};
2use std::fmt::{Debug, Formatter};
3use crate::ns::*;
4use realhydroper_sourcetext::SourceText;
5
6pub struct CompilationUnit {
9 pub(crate) file_path: Option<String>,
10 pub(crate) source_text: SourceText,
11 pub(crate) compiler_options: RefCell<Option<Rc<dyn Any>>>,
12 pub(crate) diagnostics: RefCell<Vec<Diagnostic>>,
13 pub(crate) error_count: Cell<u32>,
14 pub(crate) warning_count: Cell<u32>,
15 pub(crate) invalidated: Cell<bool>,
16 pub(crate) comments: RefCell<Vec<Rc<Comment>>>,
17 pub(crate) included_from: RefCell<Option<Rc<CompilationUnit>>>,
18 pub(crate) nested_compilation_units: RefCell<Vec<Rc<CompilationUnit>>>,
19}
20
21impl Debug for CompilationUnit {
22 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
23 f.write_str("CompilationUnit")
24 }
25}
26
27impl Default for CompilationUnit {
28 fn default() -> Self {
29 Self {
30 file_path: None,
31 source_text: SourceText::new("".into()),
32 compiler_options: RefCell::new(None),
33 diagnostics: RefCell::new(vec![]),
34 invalidated: Cell::new(false),
35 error_count: Cell::new(0),
36 warning_count: Cell::new(0),
37 comments: RefCell::new(vec![]),
38 nested_compilation_units: RefCell::new(vec![]),
39 included_from: RefCell::new(None),
40 }
41 }
42}
43
44impl CompilationUnit {
45 pub fn new(file_path: Option<String>, text: String) -> Rc<Self> {
47 Rc::new(Self {
48 file_path,
49 source_text: SourceText::new(text),
50 compiler_options: RefCell::new(None),
51 diagnostics: RefCell::new(vec![]),
52 invalidated: Cell::new(false),
53 error_count: Cell::new(0),
54 warning_count: Cell::new(0),
55 comments: RefCell::new(vec![]),
56 nested_compilation_units: RefCell::new(vec![]),
57 included_from: RefCell::new(None),
58 })
59 }
60
61 pub fn file_path(&self) -> Option<String> {
63 self.file_path.clone()
64 }
65
66 pub fn text(&self) -> &String {
68 &self.source_text.contents
69 }
70
71 pub fn compiler_options(&self) -> Option<Rc<dyn Any>> {
73 self.compiler_options.borrow().clone()
74 }
75
76 pub fn set_compiler_options(&self, options: Option<Rc<dyn Any>>) {
78 self.compiler_options.replace(options);
79 }
80
81 pub fn invalidated(&self) -> bool {
84 self.invalidated.get()
85 }
86
87 pub fn comments(&self) -> Vec<Rc<Comment>> {
90 let mut collection = vec![];
91 for c in self.comments.borrow().iter() {
92 collection.push(c.clone());
93 }
94 collection
95 }
96
97 pub fn comments_mut(&self) -> RefMut<Vec<Rc<Comment>>> {
99 self.comments.borrow_mut()
100 }
101
102 pub fn add_comment(&self, comment: Rc<Comment>) {
105 let mut dup = false;
106 let i = comment.location.borrow().first_offset();
107 for c1 in self.comments.borrow().iter() {
108 if c1.location.borrow().first_offset == i {
109 dup = true;
110 break;
111 }
112 }
113 if !dup {
114 self.comments.borrow_mut().push(comment);
115 }
116 }
117
118 pub fn diagnostics(&self) -> Vec<Diagnostic> {
121 self.diagnostics.borrow().clone()
122 }
123
124 pub fn nested_diagnostics(&self) -> Vec<Diagnostic> {
127 let mut result = self.diagnostics();
128 for unit in self.nested_compilation_units.borrow().iter() {
129 result.extend(unit.nested_diagnostics());
130 }
131 result
132 }
133
134 pub fn sort_diagnostics(&self) {
137 self.diagnostics.borrow_mut().sort();
138 for unit in self.nested_compilation_units.borrow().iter() {
139 unit.sort_diagnostics();
140 }
141 }
142
143 pub fn prevent_equal_offset_error(&self, location: &Location) -> bool {
146 let diag_list = self.diagnostics.borrow();
147 for diag in diag_list.iter() {
148 if diag.is_warning() {
149 continue;
150 }
151 if diag.location.first_offset == location.first_offset {
152 return true;
153 }
154 }
155 false
156 }
157
158 pub fn prevent_equal_offset_warning(&self, location: &Location) -> bool {
161 let diag_list = self.diagnostics.borrow();
162 for diag in diag_list.iter() {
163 if diag.is_error() {
164 continue;
165 }
166 if diag.location.first_offset == location.first_offset {
167 return true;
168 }
169 }
170 false
171 }
172
173 pub fn included_from(&self) -> Option<Rc<CompilationUnit>> {
176 self.included_from.borrow().clone()
177 }
178
179 pub(crate) fn set_included_from(&self, included_from: Option<Rc<CompilationUnit>>) {
180 self.included_from.replace(included_from);
181 }
182
183 pub(crate) fn include_directive_is_circular(&self, file_path: &str) -> bool {
184 if normalize_path(&self.file_path.clone().unwrap_or("".into())) == normalize_path(file_path) {
185 return true;
186 }
187 if let Some(included_from) = self.included_from() {
188 return included_from.include_directive_is_circular(file_path);
189 }
190 return false;
191 }
192
193 pub fn nested_compilation_units(&self) -> Vec<Rc<CompilationUnit>> {
194 let mut result = vec![];
195 for unit in self.nested_compilation_units.borrow().iter() {
196 result.push(unit.clone());
197 }
198 result
199 }
200
201 pub fn add_nested_compilation_unit(self: &Rc<Self>, unit: Rc<CompilationUnit>) {
202 self.nested_compilation_units.borrow_mut().push(unit.clone());
203 unit.set_included_from(Some(self.clone()));
204 }
205
206 pub fn add_diagnostic(&self, diagnostic: Diagnostic) {
207 if diagnostic.is_warning() {
208 self.warning_count.set(self.warning_count.get() + 1);
209 } else {
210 self.error_count.set(self.error_count.get() + 1);
211 self.invalidated.set(true);
212 }
213 self.diagnostics.borrow_mut().push(diagnostic);
214 }
215
216 pub fn error_count(&self) -> u32 {
217 self.error_count.get()
218 }
219
220 pub fn warning_count(&self) -> u32 {
221 self.warning_count.get()
222 }
223
224 pub fn get_line_number(&self, offset: usize) -> usize {
227 self.source_text.get_line_number(offset)
228 }
229
230 pub fn get_column(&self, offset: usize) -> usize {
232 self.source_text.get_column(offset)
233 }
234
235 pub fn get_line_offset(&self, line: usize) -> Option<usize> {
237 self.source_text.get_line_offset(line)
238 }
239
240 pub fn get_line_offset_from_offset(&self, offset: usize) -> usize {
242 self.source_text.get_line_offset_from_offset(offset)
243 }
244
245 pub fn get_line_indent(&self, line: usize) -> usize {
246 let line_offset = self.get_line_offset(line).unwrap();
247 CharacterValidator::indent_count(&self.source_text.contents[line_offset..])
248 }
249}
250
251fn normalize_path(path: &str) -> String {
252 realhydroper_path::normalize_path(std::path::Path::new(path)).to_string_lossy().into_owned()
253}