Fix the handling of the right-hand-side

This commit is contained in:
Niko Matsakis 2016-02-05 08:18:42 -05:00
parent 76399fc667
commit 8b51ec251d
3 changed files with 81 additions and 39 deletions

View File

@ -18,7 +18,6 @@ impl AsciiCanvas {
}
fn index(&self, r: usize, c: usize) -> usize {
println!("r={} c={} dims={}x{}", r, c, self.rows, self.columns);
assert!(r < self.rows);
assert!(c <= self.columns);
r * self.columns + c

View File

@ -2,6 +2,7 @@
use lr1::LR0Item;
use self::ascii_canvas::AsciiCanvas;
use super::{BacktraceNode, Example, Reduction};
mod ascii_canvas;
@ -148,8 +149,6 @@ impl Example {
/// measured in characters. These are spaced to leave enough room
/// for the reductions below.
fn positions(&self, lengths: &[usize]) -> Vec<usize> {
println!("positions({:?}, lengths={:?})", self.symbols, lengths);
// Initially, position each symbol with one space in between,
// like:
//
@ -167,15 +166,6 @@ impl Example {
})
.collect();
// The final position is a marker. Currently we will leave
// an extra space, so remove it:
//
// X Y Z
// ^ where the marker would be otherwise
*positions.last_mut().unwrap() -= 1;
println!("positions: initial={:?}", positions);
// Adjust spacing to account for the nonterminal labels
// we will have to add. It will display
// like this:
@ -192,9 +182,6 @@ impl Example {
// | |
// +-LongLabel22-+
for &Reduction { start, end, nonterminal } in &self.reductions {
println!("positions: nonterminal={:?} start={:?} end={:?}",
nonterminal, start, end);
let nt_len = format!("{}", nonterminal).chars().count();
// Number of symbols we are reducing. This should always
@ -202,7 +189,6 @@ impl Example {
// rule, we ought to be have a `None` entry in the symbol array.
let num_syms = end - start;
assert!(num_syms > 0);
println!("positions: num_syms={:?} nt_len={:?}", num_syms, nt_len);
// Let's use the expansion from above as our running example.
// We start out with positions like this:
@ -225,10 +211,6 @@ impl Example {
// ^ here
let end_position = positions[end - 1] + lengths[end - 1];
println!("positions: start_position={:?} end_position={:?}",
start_position,
end_position);
// We need space to draw `+-Label-+` between
// start_position and end_position.
let required_len = nt_len + 4; // here, 15
@ -240,11 +222,6 @@ impl Example {
// Have to add `difference` characters altogether.
let difference = required_len - actual_len; // here, 4
println!("positions: nt_len={:?} required_len={:?} \
actual_len={:?} difference={:?}",
nt_len, required_len,
actual_len, difference);
// Increment over everything that is not part of this nonterminal.
// In the example above, that is E5 and F6.
shift(&mut positions[end..], difference);
@ -283,9 +260,6 @@ impl Example {
let amount = difference / num_gaps; // what to add to each gap. Here, 1.
let extra = difference % num_gaps; // the remainder. Here, 1.
println!("positions: num_gaps={:?} amount={:?} extra={:?}",
num_gaps, amount, extra);
// For the first `extra` symbols, give them amount + 1
// extra space. After that, just amount. (O(n^2). Sue me.)
for i in 0 .. extra {
@ -295,12 +269,50 @@ impl Example {
shift(&mut positions[start + 1 + i .. end], amount);
}
}
println!("positions: current = {:?}", positions);
}
positions
}
pub fn paint(&self) -> Vec<String> {
let lengths = self.lengths();
let positions = self.positions(&lengths);
let rows = 1 + self.reductions.len() * 2;
let columns = *positions.last().unwrap();
let mut canvas = AsciiCanvas::new(rows, columns);
// Write the labels:
// A1 B2 C3 D4 E5 F6
for (index, opt_symbol) in self.symbols.iter().enumerate() {
if let &Some(symbol) = opt_symbol {
let column = positions[index];
canvas.write(0, column, format!("{}", symbol).chars());
}
}
// Draw the brackets for each reduction:
for (index, reduction) in self.reductions.iter().enumerate() {
let start_column = positions[reduction.start];
let end_column = positions[reduction.end] - 1;
let row = 2 + index * 2;
println!("reduction: {:?} columns={}..{} row={}",
reduction, start_column, end_column, row);
canvas.draw_vertical_line(1 .. row + 1, start_column);
canvas.draw_vertical_line(1 .. row + 1, end_column - 1);
canvas.draw_horizontal_line(row, start_column .. end_column);
}
// Write the labels for each reduction. Do this after the
// brackets so that ascii canvas can convert `|` to `+`
// without interfering with the text (in case of weird overlap).
for (index, reduction) in self.reductions.iter().enumerate() {
let column = positions[reduction.start] + 2;
let row = 2 + index * 2;
canvas.write(row, column, format!("{}", reduction.nonterminal).chars());
}
canvas.to_strings()
}
}
fn shift(positions: &mut [usize], amount: usize) {

View File

@ -1,6 +1,7 @@
use intern::intern;
use grammar::parse_tree::TerminalLiteral;
use grammar::repr::*;
use test_util::compare;
use super::super::{Example, Reduction};
@ -23,7 +24,7 @@ macro_rules! syms {
}
}
// 012345678901234567890
// 01234567890123456789012
// A1 B2 C3 D4 E5 F6
// | | |
// +-LongLabel22-+ |
@ -43,18 +44,33 @@ fn long_label_1_positions() {
let example = long_label_1_example();
let lengths = example.lengths();
let positions = example.positions(&lengths);
assert_eq!(positions, vec![0, 5, 9, 13, 16, 19, 21]);
assert_eq!(positions, vec![0, 5, 9, 13, 16, 19, 22]);
}
// Note that `positions` can handle this,
// but maybe not `paint`.
#[test]
fn long_label_1_strings() {
let strings = long_label_1_example().paint();
compare(strings,
vec!["A1 B2 C3 D4 E5 F6",
"| | |",
"+-LongLabel22-+ |",
"| |",
"+-Label-------------+"]);
}
// Example with some empty sequences and
// other edge cases.
//
// 01234567890123456789012345678901234
// 012345678901234567890123456789012345
// A1 B2 C3 D4 E5 F6
// | | | | | | |
// +-X-+ | +-Y-+ +-Z-+
// | |
// +-MegaLongLabel-+
// +-X-+ | | | | |
// | | | | | |
// +-MegaLongLabel-+ | | | |
// | | | |
// +-Y-+ | |
// | |
// +-Z-+
fn empty_labels_example() -> Example {
Example {
// 0 1 2 3 4 5 6 7
@ -73,5 +89,20 @@ fn empty_labels_positions() {
let lengths = example.lengths();
let positions = example.positions(&lengths);
// A1 B2 C3 D4 E5 F6
assert_eq!(positions, vec![0, 7, 11, 15, 18, 21, 24, 30, 35]);
assert_eq!(positions, vec![0, 7, 11, 15, 18, 21, 24, 30, 36]);
}
#[test]
fn empty_labels_strings() {
let strings = empty_labels_example().paint();
compare(strings,
vec![" A1 B2 C3 D4 E5 F6",
"| | | | | | |",
"+-X--+ | | | | |",
"| | | | | |",
"+-MegaLongLabel-+ | | | |",
" | | | |",
" +-Y-+ | |",
" | |",
" +-Z-+"]);
}