mirror of
https://github.com/fluencelabs/lalrpop
synced 2025-06-05 06:21:22 +00:00
Fix the handling of the right-hand-side
This commit is contained in:
parent
76399fc667
commit
8b51ec251d
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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-+"]);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user