127 lines
3.6 KiB
Rust
127 lines
3.6 KiB
Rust
use crate::ast::named::Named;
|
|
use crate::ast::{CompilationUnit, Identifier};
|
|
use crate::diagnostic::DmDiagnostic;
|
|
use crate::name_analysis::fqn_context::FqnContext;
|
|
use crate::name_analysis::gather::gather_module_level_declaration;
|
|
use crate::name_analysis::resolve::resolve_module_level_declaration;
|
|
use crate::name_analysis::symbol_table::SymbolTable;
|
|
use codespan_reporting::diagnostic::{Diagnostic, Label};
|
|
|
|
mod fqn_context;
|
|
mod gather;
|
|
mod resolve;
|
|
pub mod symbol;
|
|
pub mod symbol_table;
|
|
|
|
pub(self) struct DiagnosticsContainer {
|
|
file_id: usize,
|
|
diagnostics: Vec<DmDiagnostic>,
|
|
}
|
|
|
|
impl DiagnosticsContainer {
|
|
pub fn new(file_id: usize) -> DiagnosticsContainer {
|
|
DiagnosticsContainer {
|
|
file_id,
|
|
diagnostics: vec![],
|
|
}
|
|
}
|
|
|
|
pub fn add(&mut self, f: impl FnOnce(usize) -> DmDiagnostic) {
|
|
self.diagnostics.push(f(self.file_id));
|
|
}
|
|
|
|
pub fn add_error_at_identifier(&mut self, msg: &str, identifier: &Identifier) {
|
|
self.diagnostics.push(
|
|
Diagnostic::error()
|
|
.with_message(msg)
|
|
.with_label(Label::primary(self.file_id, identifier.range)),
|
|
);
|
|
}
|
|
}
|
|
|
|
impl Into<Vec<DmDiagnostic>> for DiagnosticsContainer {
|
|
fn into(self) -> Vec<DmDiagnostic> {
|
|
self.diagnostics
|
|
}
|
|
}
|
|
|
|
pub fn analyze_names(
|
|
file_id: usize,
|
|
compilation_unit: &mut CompilationUnit,
|
|
symbol_table: &mut SymbolTable,
|
|
) -> Vec<DmDiagnostic> {
|
|
let mut diagnostics = DiagnosticsContainer::new(file_id);
|
|
|
|
let mut fqn_context = FqnContext::new();
|
|
if let Some(namespace) = &compilation_unit.namespace {
|
|
fqn_context.push(namespace.name().to_string());
|
|
}
|
|
|
|
for declaration in &mut compilation_unit.declarations {
|
|
gather_module_level_declaration(
|
|
declaration,
|
|
symbol_table,
|
|
&mut fqn_context,
|
|
&mut diagnostics,
|
|
);
|
|
}
|
|
|
|
assert_eq!(symbol_table.current_scope_id(), 0);
|
|
|
|
for declaration in &mut compilation_unit.declarations {
|
|
resolve_module_level_declaration(declaration, symbol_table, &mut diagnostics);
|
|
}
|
|
|
|
diagnostics.into()
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
use crate::ast::build::build_ast;
|
|
use crate::parser::{DeimosParser, Rule};
|
|
use codespan_reporting::files::SimpleFiles;
|
|
use codespan_reporting::term;
|
|
use codespan_reporting::term::termcolor::{ColorChoice, StandardStream};
|
|
use pest::Parser;
|
|
|
|
fn assert_no_diagnostics(src: &str) {
|
|
let parse_result = DeimosParser::parse(Rule::CompilationUnit, src);
|
|
if let Err(err) = &parse_result {
|
|
panic!("{:?}", err);
|
|
}
|
|
let compilation_unit_pair = parse_result.unwrap().next().unwrap();
|
|
let mut ast = build_ast(compilation_unit_pair);
|
|
|
|
let mut files = SimpleFiles::new();
|
|
let test_file_id = files.add("test.dm", src);
|
|
|
|
let mut symbol_table = SymbolTable::new();
|
|
|
|
let diagnostics = analyze_names(test_file_id, &mut ast, &mut symbol_table);
|
|
|
|
if !diagnostics.is_empty() {
|
|
let writer = StandardStream::stderr(ColorChoice::Always);
|
|
let config = term::Config::default();
|
|
|
|
for diagnostic in &diagnostics {
|
|
term::emit(&mut writer.lock(), &config, &files, &diagnostic).unwrap();
|
|
}
|
|
|
|
eprintln!("{}", symbol_table);
|
|
panic!("Diagnostics was not empty!");
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn params_seen() {
|
|
assert_no_diagnostics(
|
|
r#"
|
|
fn main(args: Array<String>) {
|
|
let x = args;
|
|
}
|
|
"#,
|
|
)
|
|
}
|
|
}
|