summaryrefslogtreecommitdiff
path: root/src/main.rs
blob: 1ac5a54008b1bb00675d5ce5e860c433dbbaa70e (plain)
use std::collections::HashMap;

use bpaf::{Bpaf, Parser};
use bumpalo::Bump;
use kuht::{analyze::symbol_table, compile::compile, parse::parse_document, tokenize::tokenize};

#[derive(Debug, Clone, Bpaf)]
struct Options {
	/// Show any errors without compiling
	#[bpaf(switch)]
	dry: bool,

	// The location to place the resulting HTML file
	#[bpaf(short)]
	out: String,

	/// The files to compile to an HTML
	#[bpaf(positional("FILES"))]
	files: Vec<String>,
}

fn main() {
	let options = options().run();
	let sources = options
		.files
		.into_iter()
		.map(|filename| {
			let source = match std::fs::read_to_string(&filename) {
				Ok(source) => source,
				Err(error) => {
					eprintln!("{error}");
					std::process::exit(1);
				}
			};
			(filename, source)
		})
		.collect::<HashMap<_, _>>();

	let arena = Bump::new();
	let tokens = sources
		.into_iter()
		.map(|(filename, source)| (filename, tokenize(&source, &arena)))
		.collect::<HashMap<_, _>>();

	let asts = tokens
		.into_iter()
		.map(|(filename, tokens)| (filename, parse_document(tokens, &arena)))
		.collect::<HashMap<_, _>>();

	let symbol_tables = asts
		.into_iter()
		.map(|(filename, document)| (filename, symbol_table(&arena, document)))
		.collect::<HashMap<_, _>>();

	if !options.dry {
		let output = compile(&symbol_tables.into_values().collect::<Box<_>>());
		if let Err(e) = std::fs::write(options.out, output.as_bytes()) {
			eprintln!("{e}");
			std::process::exit(1);
		}
	}
}