Projektmodule und vollständiges TBC-Kompilat umsetzen und Change archivieren
This commit is contained in:
96
crates/tb-frontend/src/source.rs
Normal file
96
crates/tb-frontend/src/source.rs
Normal file
@@ -0,0 +1,96 @@
|
||||
//! 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)]
|
||||
pub struct SourceSegment {
|
||||
pub file: String,
|
||||
pub first_line: u32,
|
||||
pub text: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
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());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user