151 lines
4.0 KiB
Rust
151 lines
4.0 KiB
Rust
use crate::ast::named::Named;
|
|
use crate::ast::CompilationUnit;
|
|
use crate::diagnostic::DmDiagnostic;
|
|
use crate::name_analysis::gather::gather_compilation_unit;
|
|
use crate::name_analysis::resolve::resolve_compilation_unit;
|
|
use crate::name_analysis::symbol_table::SymbolTable;
|
|
|
|
mod fqn_context;
|
|
mod gather;
|
|
mod resolve;
|
|
pub mod symbol;
|
|
pub mod symbol_table;
|
|
|
|
pub(self) struct DiagnosticsContainer {
|
|
diagnostics: Vec<DmDiagnostic>,
|
|
}
|
|
|
|
impl DiagnosticsContainer {
|
|
pub fn new() -> DiagnosticsContainer {
|
|
DiagnosticsContainer {
|
|
diagnostics: vec![],
|
|
}
|
|
}
|
|
|
|
pub fn add(&mut self, diagnostic: DmDiagnostic) {
|
|
self.diagnostics.push(diagnostic);
|
|
}
|
|
}
|
|
|
|
impl Into<Vec<DmDiagnostic>> for DiagnosticsContainer {
|
|
fn into(self) -> Vec<DmDiagnostic> {
|
|
self.diagnostics
|
|
}
|
|
}
|
|
|
|
pub fn analyze_names(
|
|
compilation_units: &mut Vec<CompilationUnit>,
|
|
symbol_table: &mut SymbolTable,
|
|
) -> Vec<DmDiagnostic> {
|
|
let mut diagnostics = DiagnosticsContainer::new();
|
|
|
|
// gather symbols
|
|
for compilation_unit in compilation_units.iter_mut() {
|
|
gather_compilation_unit(compilation_unit, symbol_table, &mut diagnostics);
|
|
}
|
|
|
|
// resolve symbols
|
|
for compilation_unit in compilation_units.iter_mut() {
|
|
resolve_compilation_unit(compilation_unit, 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 indoc::indoc;
|
|
use pest::Parser;
|
|
use std::collections::HashMap;
|
|
|
|
fn assert_no_diagnostics(sources: HashMap<&str, &str>) -> SymbolTable {
|
|
let mut files = SimpleFiles::new();
|
|
let mut compilation_units = vec![];
|
|
|
|
for (file_name, source) in sources {
|
|
let file_id = files.add(file_name, source);
|
|
let parse_result = DeimosParser::parse(Rule::CompilationUnit, source);
|
|
if let Err(err) = &parse_result {
|
|
panic!("{}", err);
|
|
}
|
|
let mut pairs = parse_result.unwrap();
|
|
if pairs.as_str().trim() != source.trim() {
|
|
panic!("Parsing did not consume entire input.");
|
|
}
|
|
|
|
compilation_units.push(build_ast(file_name, file_id, pairs.next().unwrap()))
|
|
}
|
|
|
|
let mut symbol_table = SymbolTable::new();
|
|
|
|
let diagnostics = analyze_names(&mut compilation_units, &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!");
|
|
}
|
|
|
|
for compilation_unit in &compilation_units {
|
|
dbg!(compilation_unit);
|
|
}
|
|
|
|
symbol_table
|
|
}
|
|
|
|
#[test]
|
|
fn params_seen() {
|
|
let sources: HashMap<&str, &str> = HashMap::from([(
|
|
"main.dm",
|
|
indoc! {"
|
|
fn main(args: Array<String>) {
|
|
let x = args;
|
|
}"},
|
|
)]);
|
|
|
|
assert_no_diagnostics(sources);
|
|
}
|
|
|
|
#[test]
|
|
fn two_files() {
|
|
let sources: HashMap<&str, &str> = HashMap::from([
|
|
(
|
|
"main.dm",
|
|
indoc! {"
|
|
use std::core::{Array, String, println};
|
|
|
|
fn main(args: Array<String>) {
|
|
println(\"Hello, World!\");
|
|
}
|
|
"},
|
|
),
|
|
(
|
|
"deps.dm",
|
|
indoc! {"
|
|
ns std::core;
|
|
|
|
pub class String {}
|
|
|
|
pub class Array {}
|
|
|
|
pub platform fn println(msg: String) -> Void;
|
|
"},
|
|
),
|
|
]);
|
|
|
|
assert_no_diagnostics(sources);
|
|
}
|
|
}
|