Add pretty-printing of the parsed expression
Adds `--unpretty` unstable flag, which currently accepts two arguments, `dot` and `graphdotviz`, which are synonymous, and which prints the expression we parsed in a graphdotviz-compatible format, i.e. in a form of a directed graph.
This commit is contained in:
parent
ba409b9be0
commit
3d26398ac7
93
src/main.rs
93
src/main.rs
|
@ -1,9 +1,16 @@
|
|||
#![feature(box_syntax)]
|
||||
|
||||
// Try to keep this string updated with the argument parsing, otherwise it will
|
||||
// get confusing for users.
|
||||
static USAGE: &'static str = "usage: pine [options] input
|
||||
|
||||
options:
|
||||
--help print all options";
|
||||
--help print all options
|
||||
|
||||
unstable options:
|
||||
--unpretty val print un-prettified representation of the source code
|
||||
valid options for `val` are:
|
||||
dot, graphdotviz (dot-compatible graph)";
|
||||
|
||||
fn main() {
|
||||
// Throw away the first argument, which usually is the executable name.
|
||||
|
@ -20,6 +27,8 @@ fn main() {
|
|||
}
|
||||
|
||||
let mut path: Option<&str> = None;
|
||||
let mut output_pretty: Option<&str> = None;
|
||||
|
||||
// Handle command-line arguments.
|
||||
let mut i = 0;
|
||||
loop {
|
||||
|
@ -35,6 +44,22 @@ fn main() {
|
|||
println!("{}\n", USAGE);
|
||||
return;
|
||||
},
|
||||
"unpretty" => {
|
||||
if i + 1 == args.len() {
|
||||
eprintln!("pine: \x1b[1;31merror\x1b[0m: expected option to '{}'", arg);
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
output_pretty = match args[i + 1].as_str() {
|
||||
opt @ ("dot" | "graphdotviz") => Some(opt),
|
||||
opt => {
|
||||
eprintln!("pine: \x1b[1;31merror\x1b[0m: invalid option '{}' to '{}'", opt, arg);
|
||||
std::process::exit(1);
|
||||
},
|
||||
};
|
||||
|
||||
i += 1;
|
||||
},
|
||||
_ => {
|
||||
eprintln!("pine: \x1b[1;31merror\x1b[0m: unknown argument '{}'", arg);
|
||||
std::process::exit(1);
|
||||
|
@ -70,6 +95,32 @@ fn main() {
|
|||
let mut tokens = TokenStream::from(source);
|
||||
let expr = parse_expression(&mut tokens);
|
||||
eprintln!("{:?}", expr);
|
||||
|
||||
match output_pretty {
|
||||
Some("dot" | "graphdotviz") => expr.then(|e| {
|
||||
let graph = e.create_graphviz_graph(unsafe { GLOBAL_COUNTER.next() });
|
||||
let graphviz_format = "node [shape = box, style = filled, color = \"#bfd1e5\", fontname = monospace, fontsize = 12]";
|
||||
eprintln!("digraph {{\n{}\n{}\n}}", graphviz_format, graph);
|
||||
}),
|
||||
// This case is validated at the command-line parsing time, and we reject everything
|
||||
// not specified there. This is why this can never happen, unless a solar flare changes
|
||||
// a single bit.
|
||||
Some(_) => unreachable!(),
|
||||
None => {},
|
||||
}
|
||||
}
|
||||
|
||||
trait WithContinuation<T> {
|
||||
fn then<F>(&self, f: F) where F: FnOnce(&T);
|
||||
}
|
||||
|
||||
impl<T> WithContinuation<T> for std::option::Option<T> {
|
||||
fn then<F>(&self, f: F) where F: FnOnce(&T) {
|
||||
match self {
|
||||
None => {},
|
||||
Some(v) => f(v),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -78,6 +129,46 @@ enum Expression {
|
|||
Binary(Token, Box<Expression>, Box<Expression>),
|
||||
}
|
||||
|
||||
struct Counter {
|
||||
state: usize,
|
||||
}
|
||||
|
||||
impl Counter {
|
||||
pub const fn new() -> Self {
|
||||
return Self {
|
||||
state: 0,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn next(&mut self) -> usize {
|
||||
let last_state = self.state;
|
||||
self.state += 1;
|
||||
return last_state;
|
||||
}
|
||||
}
|
||||
|
||||
static mut GLOBAL_COUNTER: Counter = Counter::new();
|
||||
|
||||
impl Expression {
|
||||
pub fn create_graphviz_graph(&self, id: usize) -> String {
|
||||
return match self {
|
||||
Expression::Literal(Token::IntegerLiteral(i)) => {
|
||||
format!("Node{} [label = \"{}\"]", id, i)
|
||||
},
|
||||
Expression::Literal(_) => unreachable!(),
|
||||
Expression::Binary(op, left, right) => {
|
||||
let left_id = unsafe { GLOBAL_COUNTER.next() };
|
||||
let right_id = unsafe { GLOBAL_COUNTER.next() };
|
||||
|
||||
format!("Node{} -> {{ Node{} Node{} }}\nNode{} [label = \"{}\"]\n{}\n{}",
|
||||
id, left_id, right_id,
|
||||
id, op,
|
||||
left.create_graphviz_graph(left_id), right.create_graphviz_graph(right_id))
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_expression<'a>(tokens: &'a mut TokenStream<'a>) -> Option<Expression> {
|
||||
let lhs = match tokens.next()? {
|
||||
token @ Token::IntegerLiteral(_) => Expression::Literal(token),
|
||||
|
|
Loading…
Reference in a new issue