use grammar::repr::Grammar;
use tls::Tls;
use std::fmt;
use std::io::{self, Write};
macro_rules! rust {
($w:expr, $($args:tt)*) => {
try!(($w).writeln(&::std::fmt::format(format_args!($($args)*))))
}
}
pub struct RustWrite<W: Write> {
write: W,
indent: usize,
}
const TAB: usize = 4;
impl<W:Write> RustWrite<W> {
pub fn new(w: W) -> RustWrite<W> {
RustWrite { write: w, indent: 0 }
}
pub fn into_inner(self) -> W {
self.write
}
fn write_indentation(&mut self) -> io::Result<()> {
write!(self.write, "{0:1$}", "", self.indent)
}
fn write_indented(&mut self, out: &str) -> io::Result<()> {
writeln!(self.write, "{0:1$}{2}", "", self.indent, out)
}
pub fn write_table_row<I, C>(&mut self, iterable: I) -> io::Result<()>
where I: IntoIterator<Item=(i32, C)>,
C: fmt::Display,
{
if Tls::session().emit_comments {
for (i, comment) in iterable {
try!(self.write_indentation());
try!(writeln!(self.write, "{}, {}", i, comment));
}
} else {
try!(self.write_indentation());
let mut first = true;
for (i, _comment) in iterable {
if !first {
try!(write!(self.write, " "));
}
try!(write!(self.write, "{},", i));
first = false;
}
}
writeln!(self.write, "")
}
pub fn writeln(&mut self, out: &str) -> io::Result<()> {
let buf = out.as_bytes();
if buf.is_empty() {
return self.write.write_all("\n".as_bytes());
}
let n = buf.len() - 1;
if buf[0] == ('}' as u8) || buf[0] == (']' as u8) || buf[0] == (')' as u8) {
self.indent -= TAB;
}
try!(self.write_indented(out));
if buf[n] == ('{' as u8) || buf[n] == ('[' as u8) || buf[n] == ('(' as u8) {
self.indent += TAB;
}
Ok(())
}
pub fn write_pub_fn_header(&mut self,
grammar: &Grammar,
name: String,
type_parameters: Vec<String>,
parameters: Vec<String>,
return_type: String,
where_clauses: Vec<String>)
-> io::Result<()>
{
self.write_fn_header_helper(grammar, "pub ", name, type_parameters,
parameters, return_type, where_clauses)
}
fn write_fn_header_helper(&mut self,
grammar: &Grammar,
qualifiers: &str,
name: String,
type_parameters: Vec<String>,
parameters: Vec<String>,
return_type: String,
where_clauses: Vec<String>)
-> io::Result<()>
{
rust!(self, "{}fn {}<", qualifiers, name);
for type_parameter in &grammar.type_parameters {
rust!(self, "{0:1$}{2},", "", TAB, type_parameter);
}
for type_parameter in type_parameters {
rust!(self, "{0:1$}{2},", "", TAB, type_parameter);
}
rust!(self, ">(");
for parameter in &grammar.parameters {
rust!(self, "{}: {},", parameter.name, parameter.ty);
}
for parameter in ¶meters {
rust!(self, "{},", parameter);
}
if !grammar.where_clauses.is_empty() || !where_clauses.is_empty() {
rust!(self, ") -> {} where", return_type);
for where_clause in &grammar.where_clauses {
rust!(self, " {},", where_clause);
}
for where_clause in &where_clauses {
rust!(self, " {},", where_clause);
}
} else {
rust!(self,") -> {}", return_type);
}
Ok(())
}
pub fn write_uses(&mut self,
super_prefix: &str,
grammar: &Grammar)
-> io::Result<()>
{
for u in &grammar.uses {
if u.starts_with("super::") {
rust!(self, "use {}{};", super_prefix, u);
} else {
rust!(self, "use {};", u);
}
}
self.write_standard_uses(&grammar.prefix)
}
pub fn write_standard_uses(&mut self, prefix: &str) -> io::Result<()> {
rust!(self, "extern crate lalrpop_util as {}lalrpop_util;",
prefix);
Ok(())
}
}