Added batch processing mode
This commit is contained in:
parent
554a83a63c
commit
c62039dfdf
5 changed files with 155 additions and 42 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -737,6 +737,7 @@ dependencies = [
|
||||||
"tokio",
|
"tokio",
|
||||||
"tower-lsp",
|
"tower-lsp",
|
||||||
"unicode-segmentation",
|
"unicode-segmentation",
|
||||||
|
"walkdir",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
@ -36,3 +36,4 @@ tokio = { version = "1.38.1", features = ["macros", "rt-multi-thread", "io-std"]
|
||||||
|
|
||||||
tower-lsp = "0.20.0"
|
tower-lsp = "0.20.0"
|
||||||
unicode-segmentation = "1.11.0"
|
unicode-segmentation = "1.11.0"
|
||||||
|
walkdir = "2.5.0"
|
||||||
|
|
|
@ -18,6 +18,7 @@ pub enum Target {
|
||||||
pub struct Compiler {
|
pub struct Compiler {
|
||||||
target: Target,
|
target: Target,
|
||||||
cache: Option<RefCell<Connection>>,
|
cache: Option<RefCell<Connection>>,
|
||||||
|
// TODO:
|
||||||
reference_count: RefCell<HashMap<String, HashMap<String, usize>>>,
|
reference_count: RefCell<HashMap<String, HashMap<String, usize>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
192
src/main.rs
192
src/main.rs
|
@ -7,18 +7,20 @@ mod lua;
|
||||||
mod parser;
|
mod parser;
|
||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
|
use std::process::ExitCode;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use compiler::compiler::Compiler;
|
use compiler::compiler::Compiler;
|
||||||
use getopts::Options;
|
use getopts::Options;
|
||||||
use parser::langparser::LangParser;
|
use parser::langparser::LangParser;
|
||||||
use parser::parser::Parser;
|
use parser::parser::Parser;
|
||||||
|
use walkdir::WalkDir;
|
||||||
|
|
||||||
use crate::parser::source::SourceFile;
|
use crate::parser::source::SourceFile;
|
||||||
extern crate getopts;
|
extern crate getopts;
|
||||||
|
|
||||||
fn print_usage(program: &str, opts: Options) {
|
fn print_usage(program: &str, opts: Options) {
|
||||||
let brief = format!("Usage: {} -i FILE [options]", program);
|
let brief = format!("Usage: {} -i PATH -o PATH [options]", program);
|
||||||
print!("{}", opts.usage(&brief));
|
print!("{}", opts.usage(&brief));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,42 +38,15 @@ NML version: 0.4\n"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn process(
|
||||||
let args: Vec<String> = env::args().collect();
|
parser: &LangParser,
|
||||||
let program = args[0].clone();
|
db_path: &Option<String>,
|
||||||
|
input: &String,
|
||||||
let mut opts = Options::new();
|
output: &String,
|
||||||
opts.optopt("i", "", "Input file", "FILE");
|
debug_opts: &Vec<String>,
|
||||||
opts.optopt("d", "database", "Cache database location", "PATH");
|
multi_mode: bool,
|
||||||
opts.optmulti("z", "debug", "Debug options", "OPTS");
|
) -> bool {
|
||||||
opts.optflag("h", "help", "Print this help menu");
|
println!("Processing {input}...");
|
||||||
opts.optflag("v", "version", "Print program version and licenses");
|
|
||||||
|
|
||||||
let matches = match opts.parse(&args[1..]) {
|
|
||||||
Ok(m) => m,
|
|
||||||
Err(f) => {
|
|
||||||
panic!("{}", f.to_string())
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if matches.opt_present("v") {
|
|
||||||
print_version();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if matches.opt_present("h") {
|
|
||||||
print_usage(&program, opts);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if !matches.opt_present("i") {
|
|
||||||
print_usage(&program, opts);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let input = matches.opt_str("i").unwrap();
|
|
||||||
let debug_opts = matches.opt_strs("z");
|
|
||||||
let db_path = matches.opt_str("d");
|
|
||||||
|
|
||||||
let parser = LangParser::default();
|
|
||||||
|
|
||||||
// Parse
|
// Parse
|
||||||
let source = SourceFile::new(input.to_string(), None).unwrap();
|
let source = SourceFile::new(input.to_string(), None).unwrap();
|
||||||
let doc = parser.parse(Rc::new(source), None);
|
let doc = parser.parse(Rc::new(source), None);
|
||||||
|
@ -104,11 +79,146 @@ fn main() {
|
||||||
|
|
||||||
if parser.has_error() {
|
if parser.has_error() {
|
||||||
println!("Compilation aborted due to errors while parsing");
|
println!("Compilation aborted due to errors while parsing");
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let compiler = Compiler::new(compiler::compiler::Target::HTML, db_path);
|
let compiler = Compiler::new(compiler::compiler::Target::HTML, db_path.clone());
|
||||||
|
|
||||||
|
// Get output from file
|
||||||
|
if multi_mode {
|
||||||
|
let out_file = match doc.get_variable("compiler.output") {
|
||||||
|
None => {
|
||||||
|
eprintln!("Missing required variable `compiler.output` for multifile mode");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Some(var) => output.clone() + "/" + var.to_string().as_str(),
|
||||||
|
};
|
||||||
|
|
||||||
let out = compiler.compile(doc.as_ref());
|
let out = compiler.compile(doc.as_ref());
|
||||||
|
std::fs::write(out_file, out).is_ok()
|
||||||
std::fs::write("a.html", out).unwrap();
|
} else {
|
||||||
|
let out = compiler.compile(doc.as_ref());
|
||||||
|
std::fs::write(output, out).is_ok()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> ExitCode {
|
||||||
|
let args: Vec<String> = env::args().collect();
|
||||||
|
let program = args[0].clone();
|
||||||
|
|
||||||
|
let mut opts = Options::new();
|
||||||
|
opts.optopt("i", "input", "Input path", "PATH");
|
||||||
|
opts.optopt("o", "output", "Output path", "PATH");
|
||||||
|
opts.optopt("d", "database", "Cache database location", "PATH");
|
||||||
|
opts.optmulti("z", "debug", "Debug options", "OPTS");
|
||||||
|
opts.optflag("h", "help", "Print this help menu");
|
||||||
|
opts.optflag("v", "version", "Print program version and licenses");
|
||||||
|
|
||||||
|
let matches = match opts.parse(&args[1..]) {
|
||||||
|
Ok(m) => m,
|
||||||
|
Err(f) => {
|
||||||
|
panic!("{}", f.to_string())
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if matches.opt_present("v") {
|
||||||
|
print_version();
|
||||||
|
return ExitCode::SUCCESS;
|
||||||
|
}
|
||||||
|
if matches.opt_present("h") {
|
||||||
|
print_usage(&program, opts);
|
||||||
|
return ExitCode::SUCCESS;
|
||||||
|
}
|
||||||
|
if !matches.opt_present("i") || !matches.opt_present("o") {
|
||||||
|
print_usage(&program, opts);
|
||||||
|
return ExitCode::FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
let input = matches.opt_str("i").unwrap();
|
||||||
|
let input_meta = match std::fs::metadata(&input) {
|
||||||
|
Ok(meta) => meta,
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("Unable to get metadata for input: `{input}`");
|
||||||
|
return ExitCode::FAILURE;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let output = matches.opt_str("o").unwrap();
|
||||||
|
if input_meta.is_dir() {
|
||||||
|
// Create ouput directories
|
||||||
|
if !std::fs::exists(&output).unwrap_or(false) {
|
||||||
|
match std::fs::create_dir_all(&output) {
|
||||||
|
Ok(()) => {}
|
||||||
|
Err(err) => {
|
||||||
|
eprintln!("Unable to create output directory `{output}`: {err}");
|
||||||
|
return ExitCode::FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
match std::fs::metadata(&output) {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("Unable to get metadata for output: `{output}`");
|
||||||
|
return ExitCode::FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let debug_opts = matches.opt_strs("z");
|
||||||
|
let db_path = matches.opt_str("d");
|
||||||
|
let parser = LangParser::default();
|
||||||
|
|
||||||
|
if input_meta.is_dir() {
|
||||||
|
if db_path.is_none() {
|
||||||
|
eprintln!("Please specify a database (-d) for directory mode.");
|
||||||
|
}
|
||||||
|
|
||||||
|
let input_it = match std::fs::read_dir(&input) {
|
||||||
|
Ok(it) => it,
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("Failed to read input directory `{input}`: {e}");
|
||||||
|
return ExitCode::FAILURE;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for entry in WalkDir::new(&input) {
|
||||||
|
if let Err(err) = entry {
|
||||||
|
eprintln!("Failed to recursively walk over input directory: {err}");
|
||||||
|
return ExitCode::FAILURE;
|
||||||
|
}
|
||||||
|
match entry.as_ref().unwrap().metadata() {
|
||||||
|
Ok(meta) => {
|
||||||
|
if !meta.is_file() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("Faield to get metadata for `{entry:#?}`");
|
||||||
|
return ExitCode::FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let path = match entry.as_ref().unwrap().path().to_str() {
|
||||||
|
Some(path) => path.to_string(),
|
||||||
|
None => {
|
||||||
|
eprintln!("Faield to convert input file `{entry:#?}` to UTF-8");
|
||||||
|
return ExitCode::FAILURE;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if !path.ends_with(".nml") {
|
||||||
|
println!("Skipping '{path}'");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !process(&parser, &db_path, &path, &output, &debug_opts, true) {
|
||||||
|
eprintln!("Processing aborted");
|
||||||
|
return ExitCode::FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if !process(&parser, &db_path, &input, &output, &debug_opts, false) {
|
||||||
|
eprintln!("Processing aborted");
|
||||||
|
return ExitCode::FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ExitCode::SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -144,7 +144,7 @@ impl Parser for LangParser {
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
paragraph.push(elem);
|
paragraph.push(elem).unwrap();
|
||||||
} else {
|
} else {
|
||||||
// Process paragraph events
|
// Process paragraph events
|
||||||
if doc.last_element::<Paragraph>().is_some_and(|_| true) {
|
if doc.last_element::<Paragraph>().is_some_and(|_| true) {
|
||||||
|
|
Loading…
Reference in a new issue