cl-parser: Forego RAII scopeguard finalization pattern in impl Fold for ModuleInliner
We have an outer function *right there* to do cleanup for us.
This commit is contained in:
parent
0c518b47e6
commit
b74c4cd5bf
@ -3,10 +3,7 @@
|
|||||||
use crate::Parser;
|
use crate::Parser;
|
||||||
use cl_ast::{ast_visitor::Fold, *};
|
use cl_ast::{ast_visitor::Fold, *};
|
||||||
use cl_lexer::Lexer;
|
use cl_lexer::Lexer;
|
||||||
use std::{
|
use std::path::{Path, PathBuf};
|
||||||
ops::{Deref, DerefMut},
|
|
||||||
path::{Path, PathBuf},
|
|
||||||
};
|
|
||||||
|
|
||||||
type IoErrs = Vec<(PathBuf, std::io::Error)>;
|
type IoErrs = Vec<(PathBuf, std::io::Error)>;
|
||||||
type ParseErrs = Vec<(PathBuf, crate::error::Error)>;
|
type ParseErrs = Vec<(PathBuf, crate::error::Error)>;
|
||||||
@ -26,77 +23,76 @@ impl ModuleInliner {
|
|||||||
parse_errs: Default::default(),
|
parse_errs: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true when the [ModuleInliner] has errors to report
|
||||||
|
pub fn has_errors(&self) -> bool {
|
||||||
|
!(self.io_errs.is_empty() && self.parse_errs.is_empty())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the [IO Errors](IoErrs) and [parse Errors](ParseErrs)
|
||||||
|
pub fn into_errs(self) -> Option<(IoErrs, ParseErrs)> {
|
||||||
|
self.has_errors().then_some((self.io_errs, self.parse_errs))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Traverses a [File], attempting to inline all submodules.
|
||||||
|
///
|
||||||
|
/// This is a simple wrapper around [ModuleInliner::fold_file()] and
|
||||||
|
/// [ModuleInliner::into_errs()]
|
||||||
pub fn inline(mut self, file: File) -> Result<File, (File, IoErrs, ParseErrs)> {
|
pub fn inline(mut self, file: File) -> Result<File, (File, IoErrs, ParseErrs)> {
|
||||||
let file = self.fold_file(file);
|
let file = self.fold_file(file);
|
||||||
|
|
||||||
if self.io_errs.is_empty() && self.parse_errs.is_empty() {
|
match self.into_errs() {
|
||||||
Ok(file)
|
Some((io, parse)) => Err((file, io, parse)),
|
||||||
} else {
|
None => Ok(file),
|
||||||
Err((file, self.io_errs, self.parse_errs))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Records an [I/O error](std::io::Error), and rebuilds the outline [Module]
|
|
||||||
fn io_oops(&mut self, name: Identifier, error: std::io::Error) -> Module {
|
/// Records an [I/O error](std::io::Error) for later
|
||||||
|
fn handle_io_error(&mut self, error: std::io::Error) -> ModuleKind {
|
||||||
self.io_errs.push((self.path.clone(), error));
|
self.io_errs.push((self.path.clone(), error));
|
||||||
Module { name, kind: ModuleKind::Outline }
|
ModuleKind::Outline
|
||||||
}
|
}
|
||||||
/// Records a [parse error](crate::error::Error), and rebuilds the outline [Module]
|
|
||||||
fn parse_oops(&mut self, name: Identifier, error: crate::error::Error) -> Module {
|
/// Records a [parse error](crate::error::Error) for later
|
||||||
|
fn handle_parse_error(&mut self, error: crate::error::Error) -> ModuleKind {
|
||||||
self.parse_errs.push((self.path.clone(), error));
|
self.parse_errs.push((self.path.clone(), error));
|
||||||
Module { name, kind: ModuleKind::Outline }
|
ModuleKind::Outline
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Fold for ModuleInliner {
|
impl Fold for ModuleInliner {
|
||||||
fn fold_module(&mut self, m: Module) -> cl_ast::Module {
|
/// Traverses down the module tree, entering ever nested directories
|
||||||
|
fn fold_module(&mut self, m: Module) -> Module {
|
||||||
let Module { name, kind } = m;
|
let Module { name, kind } = m;
|
||||||
let mut inliner = PathMiser::new(self, &name.0);
|
self.path.push(&name.0); // cd ./name
|
||||||
|
|
||||||
let kind = inliner.fold_module_kind(kind);
|
let kind = self.fold_module_kind(kind);
|
||||||
|
|
||||||
let ModuleKind::Outline = kind else {
|
self.path.pop(); // cd ..
|
||||||
return Module { name, kind };
|
Module { name, kind }
|
||||||
};
|
}
|
||||||
|
|
||||||
inliner.path.set_extension("cl");
|
/// Attempts to read and parse a file for every module in the tree
|
||||||
let file = match std::fs::read_to_string(&inliner.path) {
|
fn fold_module_kind(&mut self, m: ModuleKind) -> ModuleKind {
|
||||||
Err(e) => return inliner.io_oops(name, e),
|
if let ModuleKind::Inline(f) = m {
|
||||||
Ok(s) => s,
|
return ModuleKind::Inline(self.fold_file(f));
|
||||||
|
}
|
||||||
|
// cd path/mod.cl
|
||||||
|
self.path.set_extension("cl");
|
||||||
|
|
||||||
|
let file = match std::fs::read_to_string(&self.path) {
|
||||||
|
Err(error) => return self.handle_io_error(error),
|
||||||
|
Ok(file) => file,
|
||||||
};
|
};
|
||||||
|
|
||||||
let kind = match Parser::new(Lexer::new(&file)).file() {
|
let kind = match Parser::new(Lexer::new(&file)).file() {
|
||||||
Err(e) => return inliner.parse_oops(name, e),
|
Err(e) => return self.handle_parse_error(e),
|
||||||
Ok(file) => ModuleKind::Inline(file),
|
Ok(file) => ModuleKind::Inline(file),
|
||||||
};
|
};
|
||||||
|
// cd path/mod
|
||||||
|
self.path.set_extension("");
|
||||||
|
|
||||||
inliner.path.set_extension("");
|
// The newly loaded module may need further inlining
|
||||||
Module { name, kind: inliner.fold_module_kind(kind) }
|
self.fold_module_kind(kind)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// I am the [Path] miser. Whatever I touch turns to [Path] in my clutch.
|
|
||||||
pub struct PathMiser<'mi> {
|
|
||||||
mi: &'mi mut ModuleInliner,
|
|
||||||
}
|
|
||||||
impl<'mi> PathMiser<'mi> {
|
|
||||||
pub fn new(mi: &'mi mut ModuleInliner, name: &str) -> Self {
|
|
||||||
mi.path.push(name);
|
|
||||||
Self { mi }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<'mi> Deref for PathMiser<'mi> {
|
|
||||||
type Target = ModuleInliner;
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
self.mi
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<'mi> DerefMut for PathMiser<'mi> {
|
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
||||||
self.mi
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<'mi> Drop for PathMiser<'mi> {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
self.mi.path.pop();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user