97 lines
2.8 KiB
Rust
97 lines
2.8 KiB
Rust
//! Quellen bleiben auch nach Include-Expansion einem Modul und einer Datei zugeordnet.
|
|
use crate::{ast, lexer, parser, Diagnostic, SourcePos};
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
pub struct SourceFile {
|
|
pub module: u16,
|
|
pub path: String,
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub struct SourceSegment {
|
|
pub file: String,
|
|
pub first_line: u32,
|
|
pub text: String,
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub struct SourceUnit {
|
|
pub name: String,
|
|
pub segments: Vec<SourceSegment>,
|
|
}
|
|
|
|
impl SourceUnit {
|
|
pub fn new(name: &str, file: &str, text: &str) -> Self {
|
|
Self {
|
|
name: name.into(),
|
|
segments: vec![SourceSegment {
|
|
file: file.into(),
|
|
first_line: 1,
|
|
text: text.into(),
|
|
}],
|
|
}
|
|
}
|
|
|
|
pub fn parse(
|
|
&self,
|
|
module: u16,
|
|
sources: &mut Vec<SourceFile>,
|
|
) -> (ast::Module, Vec<Diagnostic>) {
|
|
let mut text = String::new();
|
|
let mut origins = Vec::new();
|
|
for segment in &self.segments {
|
|
let file = SourceFile {
|
|
module,
|
|
path: segment.file.clone(),
|
|
};
|
|
let source = sources.iter().position(|s| s == &file).unwrap_or_else(|| {
|
|
sources.push(file);
|
|
sources.len() - 1
|
|
}) as u32;
|
|
for (line, part) in segment.text.split_inclusive('\n').enumerate() {
|
|
origins.push(SourcePos {
|
|
source,
|
|
line: segment.first_line + line as u32,
|
|
column: 1,
|
|
});
|
|
text.push_str(part);
|
|
if !part.ends_with('\n') {
|
|
text.push('\n');
|
|
}
|
|
}
|
|
}
|
|
let map = |pos: &mut SourcePos| {
|
|
let origin = origins
|
|
.get(pos.line.saturating_sub(1) as usize)
|
|
.copied()
|
|
.or_else(|| {
|
|
origins.last().map(|p| SourcePos {
|
|
line: p.line + 1,
|
|
..*p
|
|
})
|
|
})
|
|
.unwrap_or_default();
|
|
pos.source = origin.source;
|
|
pos.line = origin.line;
|
|
};
|
|
let mut lexed = lexer::lex(&text);
|
|
for token in &mut lexed.tokens {
|
|
map(&mut token.pos);
|
|
}
|
|
for diagnostic in &mut lexed.diagnostics {
|
|
map(&mut diagnostic.pos);
|
|
}
|
|
let parsed = parser::parse(&self.name, &lexed.tokens);
|
|
lexed.diagnostics.extend(parsed.diagnostics);
|
|
(parsed.module, lexed.diagnostics)
|
|
}
|
|
}
|
|
|
|
pub fn locate_diagnostics(diagnostics: &mut [Diagnostic], sources: &[SourceFile]) {
|
|
for diagnostic in diagnostics {
|
|
diagnostic.file = sources
|
|
.get(diagnostic.pos.source as usize)
|
|
.map(|s| s.path.clone());
|
|
}
|
|
}
|