mirror of
https://github.com/fluencelabs/lalrpop
synced 2025-06-08 07:51: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 {
|
fn index(&self, r: usize, c: usize) -> usize {
|
||||||
println!("r={} c={} dims={}x{}", r, c, self.rows, self.columns);
|
|
||||||
assert!(r < self.rows);
|
assert!(r < self.rows);
|
||||||
assert!(c <= self.columns);
|
assert!(c <= self.columns);
|
||||||
r * self.columns + c
|
r * self.columns + c
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
use lr1::LR0Item;
|
use lr1::LR0Item;
|
||||||
|
|
||||||
|
use self::ascii_canvas::AsciiCanvas;
|
||||||
use super::{BacktraceNode, Example, Reduction};
|
use super::{BacktraceNode, Example, Reduction};
|
||||||
|
|
||||||
mod ascii_canvas;
|
mod ascii_canvas;
|
||||||
@ -148,8 +149,6 @@ impl Example {
|
|||||||
/// measured in characters. These are spaced to leave enough room
|
/// measured in characters. These are spaced to leave enough room
|
||||||
/// for the reductions below.
|
/// for the reductions below.
|
||||||
fn positions(&self, lengths: &[usize]) -> Vec<usize> {
|
fn positions(&self, lengths: &[usize]) -> Vec<usize> {
|
||||||
println!("positions({:?}, lengths={:?})", self.symbols, lengths);
|
|
||||||
|
|
||||||
// Initially, position each symbol with one space in between,
|
// Initially, position each symbol with one space in between,
|
||||||
// like:
|
// like:
|
||||||
//
|
//
|
||||||
@ -167,15 +166,6 @@ impl Example {
|
|||||||
})
|
})
|
||||||
.collect();
|
.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
|
// Adjust spacing to account for the nonterminal labels
|
||||||
// we will have to add. It will display
|
// we will have to add. It will display
|
||||||
// like this:
|
// like this:
|
||||||
@ -192,9 +182,6 @@ impl Example {
|
|||||||
// | |
|
// | |
|
||||||
// +-LongLabel22-+
|
// +-LongLabel22-+
|
||||||
for &Reduction { start, end, nonterminal } in &self.reductions {
|
for &Reduction { start, end, nonterminal } in &self.reductions {
|
||||||
println!("positions: nonterminal={:?} start={:?} end={:?}",
|
|
||||||
nonterminal, start, end);
|
|
||||||
|
|
||||||
let nt_len = format!("{}", nonterminal).chars().count();
|
let nt_len = format!("{}", nonterminal).chars().count();
|
||||||
|
|
||||||
// Number of symbols we are reducing. This should always
|
// 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.
|
// rule, we ought to be have a `None` entry in the symbol array.
|
||||||
let num_syms = end - start;
|
let num_syms = end - start;
|
||||||
assert!(num_syms > 0);
|
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.
|
// Let's use the expansion from above as our running example.
|
||||||
// We start out with positions like this:
|
// We start out with positions like this:
|
||||||
@ -225,10 +211,6 @@ impl Example {
|
|||||||
// ^ here
|
// ^ here
|
||||||
let end_position = positions[end - 1] + lengths[end - 1];
|
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
|
// We need space to draw `+-Label-+` between
|
||||||
// start_position and end_position.
|
// start_position and end_position.
|
||||||
let required_len = nt_len + 4; // here, 15
|
let required_len = nt_len + 4; // here, 15
|
||||||
@ -240,11 +222,6 @@ impl Example {
|
|||||||
// Have to add `difference` characters altogether.
|
// Have to add `difference` characters altogether.
|
||||||
let difference = required_len - actual_len; // here, 4
|
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.
|
// Increment over everything that is not part of this nonterminal.
|
||||||
// In the example above, that is E5 and F6.
|
// In the example above, that is E5 and F6.
|
||||||
shift(&mut positions[end..], difference);
|
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 amount = difference / num_gaps; // what to add to each gap. Here, 1.
|
||||||
let extra = difference % num_gaps; // the remainder. 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
|
// For the first `extra` symbols, give them amount + 1
|
||||||
// extra space. After that, just amount. (O(n^2). Sue me.)
|
// extra space. After that, just amount. (O(n^2). Sue me.)
|
||||||
for i in 0 .. extra {
|
for i in 0 .. extra {
|
||||||
@ -295,12 +269,50 @@ impl Example {
|
|||||||
shift(&mut positions[start + 1 + i .. end], amount);
|
shift(&mut positions[start + 1 + i .. end], amount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("positions: current = {:?}", positions);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
fn shift(positions: &mut [usize], amount: usize) {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use intern::intern;
|
use intern::intern;
|
||||||
use grammar::parse_tree::TerminalLiteral;
|
use grammar::parse_tree::TerminalLiteral;
|
||||||
use grammar::repr::*;
|
use grammar::repr::*;
|
||||||
|
use test_util::compare;
|
||||||
|
|
||||||
use super::super::{Example, Reduction};
|
use super::super::{Example, Reduction};
|
||||||
|
|
||||||
@ -23,7 +24,7 @@ macro_rules! syms {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 012345678901234567890
|
// 01234567890123456789012
|
||||||
// A1 B2 C3 D4 E5 F6
|
// A1 B2 C3 D4 E5 F6
|
||||||
// | | |
|
// | | |
|
||||||
// +-LongLabel22-+ |
|
// +-LongLabel22-+ |
|
||||||
@ -43,18 +44,33 @@ fn long_label_1_positions() {
|
|||||||
let example = long_label_1_example();
|
let example = long_label_1_example();
|
||||||
let lengths = example.lengths();
|
let lengths = example.lengths();
|
||||||
let positions = example.positions(&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,
|
#[test]
|
||||||
// but maybe not `paint`.
|
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
|
// A1 B2 C3 D4 E5 F6
|
||||||
// | | | | | | |
|
// | | | | | | |
|
||||||
// +-X-+ | +-Y-+ +-Z-+
|
// +-X-+ | | | | |
|
||||||
|
// | | | | | |
|
||||||
|
// +-MegaLongLabel-+ | | | |
|
||||||
|
// | | | |
|
||||||
|
// +-Y-+ | |
|
||||||
// | |
|
// | |
|
||||||
// +-MegaLongLabel-+
|
// +-Z-+
|
||||||
fn empty_labels_example() -> Example {
|
fn empty_labels_example() -> Example {
|
||||||
Example {
|
Example {
|
||||||
// 0 1 2 3 4 5 6 7
|
// 0 1 2 3 4 5 6 7
|
||||||
@ -73,5 +89,20 @@ fn empty_labels_positions() {
|
|||||||
let lengths = example.lengths();
|
let lengths = example.lengths();
|
||||||
let positions = example.positions(&lengths);
|
let positions = example.positions(&lengths);
|
||||||
// A1 B2 C3 D4 E5 F6
|
// 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