mxmlextrema_as3parser/compilation_unit/
compilation_unit.rsuse std::{any::Any, cell::RefMut};
use std::fmt::{Debug, Formatter};
use crate::ns::*;
use hydroperfox_sourcetext::SourceText;
pub struct CompilationUnit {
pub(crate) file_path: Option<String>,
pub(crate) source_text: SourceText,
pub(crate) compiler_options: RefCell<Option<Rc<dyn Any>>>,
pub(crate) diagnostics: RefCell<Vec<Diagnostic>>,
pub(crate) error_count: Cell<u32>,
pub(crate) warning_count: Cell<u32>,
pub(crate) invalidated: Cell<bool>,
pub(crate) comments: RefCell<Vec<Rc<Comment>>>,
pub(crate) included_from: RefCell<Option<Rc<CompilationUnit>>>,
pub(crate) nested_compilation_units: RefCell<Vec<Rc<CompilationUnit>>>,
}
impl Debug for CompilationUnit {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str("CompilationUnit")
}
}
impl Default for CompilationUnit {
fn default() -> Self {
Self {
file_path: None,
source_text: SourceText::new("".into()),
compiler_options: RefCell::new(None),
diagnostics: RefCell::new(vec![]),
invalidated: Cell::new(false),
error_count: Cell::new(0),
warning_count: Cell::new(0),
comments: RefCell::new(vec![]),
nested_compilation_units: RefCell::new(vec![]),
included_from: RefCell::new(None),
}
}
}
impl CompilationUnit {
pub fn new(file_path: Option<String>, text: String) -> Rc<Self> {
Rc::new(Self {
file_path,
source_text: SourceText::new(text),
compiler_options: RefCell::new(None),
diagnostics: RefCell::new(vec![]),
invalidated: Cell::new(false),
error_count: Cell::new(0),
warning_count: Cell::new(0),
comments: RefCell::new(vec![]),
nested_compilation_units: RefCell::new(vec![]),
included_from: RefCell::new(None),
})
}
pub fn file_path(&self) -> Option<String> {
self.file_path.clone()
}
pub fn text(&self) -> &String {
&self.source_text.contents
}
pub fn compiler_options(&self) -> Option<Rc<dyn Any>> {
self.compiler_options.borrow().clone()
}
pub fn set_compiler_options(&self, options: Option<Rc<dyn Any>>) {
self.compiler_options.replace(options);
}
pub fn invalidated(&self) -> bool {
self.invalidated.get()
}
pub fn comments(&self) -> Vec<Rc<Comment>> {
let mut collection = vec![];
for c in self.comments.borrow().iter() {
collection.push(c.clone());
}
collection
}
pub fn comments_mut(&self) -> RefMut<Vec<Rc<Comment>>> {
self.comments.borrow_mut()
}
pub fn add_comment(&self, comment: Rc<Comment>) {
let mut dup = false;
let i = comment.location.borrow().first_offset();
for c1 in self.comments.borrow().iter() {
if c1.location.borrow().first_offset == i {
dup = true;
break;
}
}
if !dup {
self.comments.borrow_mut().push(comment);
}
}
pub fn diagnostics(&self) -> Vec<Diagnostic> {
self.diagnostics.borrow().clone()
}
pub fn nested_diagnostics(&self) -> Vec<Diagnostic> {
let mut result = self.diagnostics();
for unit in self.nested_compilation_units.borrow().iter() {
result.extend(unit.nested_diagnostics());
}
result
}
pub fn sort_diagnostics(&self) {
self.diagnostics.borrow_mut().sort();
for unit in self.nested_compilation_units.borrow().iter() {
unit.sort_diagnostics();
}
}
pub fn prevent_equal_offset_error(&self, location: &Location) -> bool {
let diag_list = self.diagnostics.borrow();
for diag in diag_list.iter() {
if diag.is_warning() {
continue;
}
if diag.location.first_offset == location.first_offset {
return true;
}
}
false
}
pub fn prevent_equal_offset_warning(&self, location: &Location) -> bool {
let diag_list = self.diagnostics.borrow();
for diag in diag_list.iter() {
if diag.is_error() {
continue;
}
if diag.location.first_offset == location.first_offset {
return true;
}
}
false
}
pub fn included_from(&self) -> Option<Rc<CompilationUnit>> {
self.included_from.borrow().clone()
}
pub(crate) fn set_included_from(&self, included_from: Option<Rc<CompilationUnit>>) {
self.included_from.replace(included_from);
}
pub(crate) fn include_directive_is_circular(&self, file_path: &str) -> bool {
if canonicalize_path(&self.file_path.clone().unwrap_or("".into())) == canonicalize_path(file_path) {
return true;
}
if let Some(included_from) = self.included_from() {
return included_from.include_directive_is_circular(file_path);
}
return false;
}
pub fn nested_compilation_units(&self) -> Vec<Rc<CompilationUnit>> {
let mut result = vec![];
for unit in self.nested_compilation_units.borrow().iter() {
result.push(unit.clone());
}
result
}
pub fn add_nested_compilation_unit(self: &Rc<Self>, unit: Rc<CompilationUnit>) {
self.nested_compilation_units.borrow_mut().push(unit.clone());
unit.set_included_from(Some(self.clone()));
}
pub fn add_diagnostic(&self, diagnostic: Diagnostic) {
if diagnostic.is_warning() {
self.warning_count.set(self.warning_count.get() + 1);
} else {
self.error_count.set(self.error_count.get() + 1);
self.invalidated.set(true);
}
self.diagnostics.borrow_mut().push(diagnostic);
}
pub fn error_count(&self) -> u32 {
self.error_count.get()
}
pub fn warning_count(&self) -> u32 {
self.warning_count.get()
}
pub fn get_line_number(&self, offset: usize) -> usize {
self.source_text.get_line_number(offset)
}
pub fn get_column(&self, offset: usize) -> usize {
self.source_text.get_column(offset)
}
pub fn get_line_offset(&self, line: usize) -> Option<usize> {
self.source_text.get_line_offset(line)
}
pub fn get_line_offset_from_offset(&self, offset: usize) -> usize {
self.source_text.get_line_offset_from_offset(offset)
}
pub fn get_line_indent(&self, line: usize) -> usize {
let line_offset = self.get_line_offset(line).unwrap();
CharacterValidator::indent_count(&self.source_text.contents[line_offset..])
}
}
fn canonicalize_path(path: &str) -> String {
std::path::Path::new(path).canonicalize().unwrap_or(std::path::PathBuf::new()).to_string_lossy().into_owned()
}