summaryrefslogtreecommitdiff
path: root/oryxc/src/main.rs
blob: aa350e8c082a895c662bb02adc6a68244cb5c889 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
#![allow(unsafe_op_in_unsafe_fn)]

mod compiler;
mod errors;
mod lexer;
mod parser;
mod size;
mod unicode;

use std::ffi::OsString;
use std::{
	env,
	process,
	thread,
};

use lexopt;

#[derive(Clone, Copy, Default)]
pub struct Flags {
	pub debug_lexer:  bool,
	pub debug_parser: bool,
	pub help:         bool,
	pub threads:      usize,
    pub error_style:  errors::ErrorStyle,
}

impl Flags {
	fn parse() -> Result<(Flags, Vec<OsString>), lexopt::Error> {
		use lexopt::prelude::*;

		let mut rest = Vec::with_capacity(env::args().len());
		let mut flags = Flags::default();
		let mut parser = lexopt::Parser::from_env();
		parser.set_short_equals(false);

		while let Some(arg) = parser.next()? {
			match arg {
				Short('h') | Long("help") => flags.help = true,
				Short('l') | Long("debug-lexer") => flags.debug_lexer = true,
				Short('p') | Long("debug-parser") => flags.debug_parser = true,
				Short('s') | Long("error-style") => {
					/* TODO: Don’t unwrap */
					flags.error_style = match parser.value()?.to_str().unwrap() {
						"oneline" => errors::ErrorStyle::OneLine,
						"standard" => errors::ErrorStyle::Standard,
						s => Err(format!("{s}: invalid value for -s/--error-style"))?,
					};
				},
				Short('t') | Long("threads") => {
					flags.threads = parser.value()?.parse()?;
					if flags.threads == 0 {
						err!("thread count must be greater than 0");
					}
				},
				Value(v) => rest.push(v),
				_ => return Err(arg.unexpected()),
			}
		}

		if flags.threads == 0 {
			flags.threads = thread::available_parallelism().map_or_else(
				|e| {
					warn!(e, "failed to get thread count");
					1
				},
				|x| x.get(),
			);
		}

		return Ok((flags, rest));
	}
}

fn usage() {
	eprintln!(
		concat!(
			"Usage: {0} [-lp] [-s oneline|standard] [-t threads]\n",
			"       {0} -h",
		),
		errors::progname().display()
	);
}

fn main() {
	let (flags, rest) = match Flags::parse() {
		Ok(v) => v,
		Err(e) => {
			warn!(e);
			usage();
			process::exit(1);
		},
	};

	if flags.help {
		usage();
		process::exit(0);
	}

	let _ = errors::ERROR_STYLE.set(flags.error_style);
	compiler::start(rest, flags);
}