mirror of
https://github.com/SpaceManiac/SpacemanDMM.git
synced 2025-12-23 05:36:47 +00:00
Move the file list from Preprocessor to its own struct
This commit is contained in:
parent
a234223bbc
commit
d261bb863d
6 changed files with 78 additions and 39 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -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>> {
|
||||
|
|
|
|||
|
|
@ -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))),
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue