Move the file list from Preprocessor to its own struct

This commit is contained in:
Tad Hardesty 2018-03-01 19:42:38 -08:00
parent a234223bbc
commit d261bb863d
6 changed files with 78 additions and 39 deletions

View file

@ -36,6 +36,7 @@ fn main() {
#[derive(Default)]
struct Context {
dm_context: dm::Context,
objtree: ObjectTree,
icon_cache: HashMap<PathBuf, IconFile>,
}
@ -44,7 +45,7 @@ impl Context {
fn objtree(&mut self, opt: &Opt) {
println!("parsing {}", opt.environment);
flame!("parse");
match dm::parse_environment(opt.environment.as_ref()) {
match self.dm_context.parse_environment(opt.environment.as_ref()) {
Ok(tree) => self.objtree = tree,
Err(_) => {
// parse_environment has already pretty_printed the error message

View file

@ -1,7 +1,47 @@
//! Error, warning, and other diagnostics handling.
use std::path::{PathBuf, Path};
use super::*;
/// An identifier referring to a loaded file.
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub struct FileId(u32);
const BAD_FILE_ID: FileId = FileId(::std::u32::MAX);
impl Default for FileId {
fn default() -> FileId {
BAD_FILE_ID
}
}
/// A diagnostics context, tracking loaded files and any observed errors.
#[derive(Debug, Default)]
pub struct Context {
/// The list of loaded files.
files: Vec<PathBuf>,
}
impl Context {
/// Add a new file to the context and return its index.
pub fn register_file(&mut self, path: PathBuf) -> FileId {
let len = self.files.len();
self.files.push(path);
FileId(len as u32)
}
/// Look up a file path by its index returned from `register_file`.
pub fn file_path(&self, file: FileId) -> &Path {
let idx = file.0 as usize;
if idx > self.files.len() { // includes BAD_FILE_ID
"(unknown)".as_ref()
} else {
&self.files[idx]
}
}
}
// ----------------------------------------------------------------------------
// Location handling
@ -9,7 +49,7 @@ use super::*;
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Default)]
pub struct Location {
/// The index into the file table.
pub file: u32,
pub file: FileId,
/// The line number, starting at 1.
pub line: u32,
/// The column number, starting at 1.
@ -88,9 +128,9 @@ impl From<io::Error> for DMError {
// Pretty printing
/// Pretty-print a `DMError` to the given output.
pub fn pretty_print_error<W: io::Write>(w: &mut W, pp: &preprocessor::Preprocessor, error: &DMError) -> io::Result<()> {
pub fn pretty_print_error<W: io::Write>(w: &mut W, ctx: &Context, error: &DMError) -> io::Result<()> {
writeln!(w, "\n{}, line {}, column {}:",
pp.file_path(error.location.file).display(),
ctx.file_path(error.location.file).display(),
error.location.line,
error.location.column)?;
writeln!(w, "{}\n", error.desc)

View file

@ -3,7 +3,7 @@ use std::io::{Read, Bytes};
use std::str::FromStr;
use std::fmt;
use super::{DMError, Location, HasLocation};
use super::{DMError, Location, HasLocation, FileId};
macro_rules! table {
($(#[$attr:meta])* table $tabname:ident: $repr:ty => $enum_:ident; $($literal:expr, $name:ident;)*) => {
@ -253,7 +253,7 @@ impl<R: Read> HasLocation for Lexer<R> {
impl<R: Read> Lexer<R> {
/// Create a new lexer from a byte stream.
pub fn new(file_number: u32, source: R) -> Lexer<R> {
pub fn new(file_number: FileId, source: R) -> Lexer<R> {
Lexer {
next: None,
input: source.bytes(),

View file

@ -28,15 +28,20 @@ pub mod objtree;
mod builtins;
pub mod constants;
/// Run the parsing suite on a given `.dme` file, producing an object tree.
///
/// Errors are automatically pretty-printed to stdout before they are returned.
pub fn parse_environment(dme: &Path) -> Result<objtree::ObjectTree, DMError> {
let mut preprocessor = preprocessor::Preprocessor::new(dme.to_owned())?;
parser::parse(indents::IndentProcessor::new(&mut preprocessor)).map_err(|e| {
pretty_print_error(&mut io::stdout(), &preprocessor, &e).unwrap();
e
})
impl Context {
/// Run the parsing suite on a given `.dme` file, producing an object tree.
///
/// Errors are automatically pretty-printed to stdout before they are returned.
pub fn parse_environment(&mut self, dme: &Path) -> Result<objtree::ObjectTree, DMError> {
parser::parse(
indents::IndentProcessor::new(
preprocessor::Preprocessor::new(self, dme.to_owned())?
)
).map_err(|e| {
pretty_print_error(&mut io::stdout(), self, &e).unwrap();
e
})
}
}
// ----------------------------------------------------------------------------

View file

@ -5,7 +5,7 @@ use std::fs::File;
use std::path::{Path, PathBuf};
use super::lexer::*;
use super::{DMError, Location, HasLocation};
use super::{DMError, Location, HasLocation, FileId, Context};
// ----------------------------------------------------------------------------
// Macro representation and predefined macros
@ -120,7 +120,7 @@ fn default_defines(defines: &mut HashMap<String, Define>) {
enum Include {
File {
path: PathBuf,
file: u32,
file: FileId,
lexer: Lexer<BufReader<File>>,
},
Expansion {
@ -131,7 +131,7 @@ enum Include {
}
impl Include {
fn new(path: PathBuf, idx: u32) -> io::Result<Include> {
fn new(path: PathBuf, idx: FileId) -> io::Result<Include> {
Ok(Include::File {
lexer: Lexer::new(idx, BufReader::new(File::open(&path)?)),
file: idx,
@ -178,11 +178,7 @@ impl HasLocation for IncludeStack {
if let Some(include) = self.stack.last() {
include.location()
} else {
Location {
file: 0,
line: 0,
column: 0,
}
Location::default()
}
}
}
@ -230,10 +226,11 @@ impl Ifdef {
}
/// C-like preprocessor for DM. Expands directives and macro invocations.
pub struct Preprocessor {
pub struct Preprocessor<'ctx> {
context: &'ctx mut Context,
env_file: PathBuf,
defines: HashMap<String, Define>,
files: Vec<PathBuf>,
maps: Vec<PathBuf>,
skins: Vec<PathBuf>,
include_stack: IncludeStack,
@ -243,18 +240,18 @@ pub struct Preprocessor {
output: VecDeque<Token>,
}
impl HasLocation for Preprocessor {
impl<'ctx> HasLocation for Preprocessor<'ctx> {
fn location(&self) -> Location {
self.include_stack.location()
}
}
impl Preprocessor {
pub fn new(env_file: PathBuf) -> io::Result<Self> {
impl<'ctx> Preprocessor<'ctx> {
pub fn new(context: &'ctx mut Context, env_file: PathBuf) -> io::Result<Self> {
let env_id = context.register_file(env_file.clone());
let mut pp = Preprocessor {
files: vec![env_file.clone()],
include_stack: IncludeStack {
stack: vec![Include::new(env_file.clone(), 0)?],
stack: vec![Include::new(env_file.clone(), env_id)?],
},
env_file: env_file,
defines: Default::default(),
@ -263,15 +260,12 @@ impl Preprocessor {
ifdef_stack: Default::default(),
last_input_loc: Default::default(),
output: Default::default(),
context: context,
};
default_defines(&mut pp.defines);
Ok(pp)
}
pub fn file_path(&self, file: u32) -> &Path {
&self.files[file as usize]
}
fn is_disabled(&self) -> bool {
self.ifdef_stack.iter().any(|x| !x.active)
}
@ -363,8 +357,7 @@ impl Preprocessor {
].into_iter().rev() {
if !each.exists() { continue }
enum FileType { DMM, DMF, DM }
let len = self.files.len() as u32;
self.files.push(each.clone());
let id = self.context.register_file(each.clone());
match match each.extension().and_then(|s| s.to_str()) {
Some("dmm") => FileType::DMM,
Some("dmf") => FileType::DMF,
@ -373,7 +366,7 @@ impl Preprocessor {
} {
FileType::DMM => self.maps.push(each),
FileType::DMF => self.skins.push(each),
FileType::DM => self.include_stack.stack.push(Include::new(each, len)?),
FileType::DM => self.include_stack.stack.push(Include::new(each, id)?),
}
return Ok(());
}
@ -607,7 +600,7 @@ impl Preprocessor {
}
}
impl Iterator for Preprocessor {
impl<'ctx> Iterator for Preprocessor<'ctx> {
type Item = Result<LocatedToken, DMError>;
fn next(&mut self) -> Option<Result<LocatedToken, DMError>> {

View file

@ -421,7 +421,7 @@ fn parse_constant(input: String) -> Result<Constant, DMError> {
use dm::parser::Parser;
let mut bytes = input.as_bytes();
let expr = match Parser::new(Lexer::new(0, &mut bytes)).expression(true)? {
let expr = match Parser::new(Lexer::new(Default::default(), &mut bytes)).expression(true)? {
Some(expr) => expr,
None => return Err(DMError::new(Location::default(), format!("not an expression: {}", input))),
};