use crate::grammar::repr::*;
use crate::lr1::build_states;
use crate::lr1::core::Item;
use crate::lr1::first::FirstSets;
use crate::lr1::interpret::interpret_partial;
use crate::lr1::lookahead::{Token, TokenSet};
use crate::lr1::tls::Lr1Tls;
use crate::test_util::{expect_debug, normalized_grammar};
use crate::tls::Tls;
use string_cache::DefaultAtom as Atom;
use super::super::Tracer;
fn nt(t: &str) -> NonterminalString {
NonterminalString(Atom::from(t))
}
fn term(t: &str) -> TerminalString {
TerminalString::quoted(Atom::from(t))
}
macro_rules! terms {
($($t:expr),*) => {
vec![$(term($t)),*]
}
}
fn test_grammar1() -> Grammar {
normalized_grammar(
r#"
grammar;
pub Start: () = Stmt;
pub Stmt: () = {
Exprs ";",
Exprs
};
Exprs: () = {
Expr,
Exprs "," Expr
};
Expr: () = {
"Int",
Expr "+" "Int",
};
"#,
)
}
#[test]
fn backtrace1() {
let _tls = Tls::test();
let grammar = test_grammar1();
let _lr1_tls = Lr1Tls::install(grammar.terminals.clone());
let first_sets = FirstSets::new(&grammar);
let states = build_states(&grammar, nt("Start")).unwrap();
let tracer = Tracer::new(&first_sets, &states);
let state_stack = interpret_partial(&states, terms!["Int"]).unwrap();
let top_state = *state_stack.last().unwrap();
let semi = Token::Terminal(term(";"));
let semi_item = states[top_state.0]
.items
.vec
.iter()
.find(|item| item.lookahead.contains(&semi))
.unwrap();
let backtrace = tracer.backtrace_reduce(top_state, semi_item.to_lr0());
println!("{backtrace:#?}");
let pictures: Vec<_> = backtrace
.lr0_examples(semi_item.to_lr0())
.map(|e| e.paint_unstyled())
.collect();
expect_debug(
pictures,
r#"
[
[
" Exprs "," "Int" ╷ ";"",
" │ └─Expr─┤ │",
" ├─Exprs──────────┘ │",
" └─Stmt───────────────┘"
],
[
" Exprs "," "Int" ╷ "," Expr",
" │ └─Expr─┤ │",
" ├─Exprs──────────┘ │",
" └─Exprs───────────────────┘"
],
[
" "Int" ╷ ";"",
" ├─Expr──┤ │",
" ├─Exprs─┘ │",
" └─Stmt──────┘"
],
[
" "Int" ╷ "," Expr",
" ├─Expr──┤ │",
" ├─Exprs─┘ │",
" └─Exprs──────────┘"
],
[
" "Int" ╷ "+" "Int"",
" ├─Expr─┘ │",
" └─Expr───────────┘"
]
]
"#
.trim(),
);
}
#[test]
fn backtrace2() {
let _tls = Tls::test();
let grammar = normalized_grammar(
r#"
grammar;
pub Ty: () = {
"int" => (),
"bool" => (),
<t1:Ty> "->" <t2:Ty> => (),
};
"#,
);
let _lr1_tls = Lr1Tls::install(grammar.terminals.clone());
let first_sets = FirstSets::new(&grammar);
let err = build_states(&grammar, nt("Ty")).unwrap_err();
let tracer = Tracer::new(&first_sets, &err.states);
let conflict = err.conflicts[0].clone();
println!("conflict={conflict:?}");
let item = Item {
production: conflict.production,
index: conflict.production.symbols.len(),
lookahead: conflict.lookahead.clone(),
};
println!("item={item:?}");
let backtrace = tracer.backtrace_reduce(conflict.state, item.to_lr0());
println!("{backtrace:#?}");
expect_debug(
&backtrace,
r#"
[
(Nonterminal(Ty) -([Ty, "->"], Some(Ty), [])-> Item(Ty = Ty "->" (*) Ty)),
(Nonterminal(Ty) -([Ty, "->"], Some(Ty), [])-> Nonterminal(Ty)),
(Nonterminal(Ty) -([Ty, "->", Ty], None, [])-> Item(Ty = Ty "->" Ty (*))),
(Item(Ty = (*) Ty "->" Ty) -([], Some(Ty), ["->", Ty])-> Nonterminal(Ty))
]
"#
.trim(),
);
let pictures: Vec<_> = backtrace
.lr1_examples(&first_sets, &item)
.map(|e| e.paint_unstyled())
.collect();
expect_debug(
pictures,
r#"
[
[
" Ty "->" Ty "->" Ty",
" ├─Ty─────┘ │",
" └─Ty─────────────┘"
]
]
"#
.trim(),
);
}
#[test]
fn reduce_backtrace_3_graph() {
let _tls = Tls::test();
let grammar = normalized_grammar(
r#"
grammar;
pub Ty: () = {
"int" => (),
"bool" => (),
<t1:Ty> "->" <t2:Ty> => (),
};
"#,
);
let _lr1_tls = Lr1Tls::install(grammar.terminals.clone());
let first_sets = FirstSets::new(&grammar);
let err = build_states(&grammar, nt("Ty")).unwrap_err();
let conflict = err.conflicts[0].clone();
println!("conflict={conflict:?}");
let item = Item {
production: conflict.production,
index: conflict.production.symbols.len(),
lookahead: conflict.lookahead.clone(),
};
println!("item={item:?}");
let tracer = Tracer::new(&first_sets, &err.states);
let graph = tracer.backtrace_reduce(conflict.state, item.to_lr0());
expect_debug(
&graph,
r#"
[
(Nonterminal(Ty) -([Ty, "->"], Some(Ty), [])-> Item(Ty = Ty "->" (*) Ty)),
(Nonterminal(Ty) -([Ty, "->"], Some(Ty), [])-> Nonterminal(Ty)),
(Nonterminal(Ty) -([Ty, "->", Ty], None, [])-> Item(Ty = Ty "->" Ty (*))),
(Item(Ty = (*) Ty "->" Ty) -([], Some(Ty), ["->", Ty])-> Nonterminal(Ty))
]
"#
.trim(),
);
let list: Vec<_> = graph
.lr1_examples(&first_sets, &item)
.map(|example| example.paint_unstyled())
.collect();
expect_debug(
list,
r#"
[
[
" Ty "->" Ty "->" Ty",
" ├─Ty─────┘ │",
" └─Ty─────────────┘"
]
]
"#
.trim(),
);
}
#[test]
fn backtrace_filter() {
let _tls = Tls::test();
let grammar = normalized_grammar(
r#"
grammar;
pub Start: () = Stmt;
pub Stmt: () = {
Exprs ";"
};
Exprs: () = {
Expr,
Exprs "," Expr
};
Expr: () = {
ExprAtom ExprSuffix
};
ExprSuffix: () = {
(),
"?",
};
ExprAtom: () = {
"Int",
};
"#,
);
let _lr1_tls = Lr1Tls::install(grammar.terminals.clone());
let states = build_states(&grammar, nt("Start")).unwrap();
let first_sets = FirstSets::new(&grammar);
let tracer = Tracer::new(&first_sets, &states);
let state_stack = interpret_partial(&states, terms!["Int"]).unwrap();
let top_state = *state_stack.last().unwrap();
let semi = Token::Terminal(term(";"));
let lr1_item = states[top_state.0]
.items
.vec
.iter()
.find(|item| item.lookahead.contains(&semi))
.unwrap();
let backtrace = tracer.backtrace_reduce(top_state, lr1_item.to_lr0());
println!("{backtrace:#?}");
let pictures: Vec<_> = backtrace
.lr0_examples(lr1_item.to_lr0())
.map(|e| e.paint_unstyled())
.collect();
expect_debug(
pictures,
r#"
[
[
" Exprs "," "Int" ╷ ExprSuffix ";"",
" │ ├─ExprAtom─┘ │ │",
" │ └─Expr────────────────┤ │",
" ├─Exprs─────────────────────────┘ │",
" └─Stmt──────────────────────────────┘"
],
[
" Exprs "," "Int" ╷ ExprSuffix "," Expr",
" │ ├─ExprAtom─┘ │ │",
" │ └─Expr────────────────┤ │",
" ├─Exprs─────────────────────────┘ │",
" └─Exprs──────────────────────────────────┘"
],
[
" "Int" ╷ ExprSuffix ";"",
" ├─ExprAtom─┘ │ │",
" ├─Expr────────────────┤ │",
" ├─Exprs───────────────┘ │",
" └─Stmt────────────────────┘"
],
[
" "Int" ╷ ExprSuffix "," Expr",
" ├─ExprAtom─┘ │ │",
" ├─Expr────────────────┤ │",
" ├─Exprs───────────────┘ │",
" └─Exprs────────────────────────┘"
]
]
"#
.trim(),
);
let semi_item = lr1_item.with_lookahead(TokenSet::from(semi));
let pictures: Vec<_> = backtrace
.lr1_examples(&first_sets, &semi_item)
.map(|e| e.paint_unstyled())
.collect();
expect_debug(
pictures,
r#"
[
[
" Exprs "," "Int" ╷ ExprSuffix ";"",
" │ ├─ExprAtom─┘ │ │",
" │ └─Expr────────────────┤ │",
" ├─Exprs─────────────────────────┘ │",
" └─Stmt──────────────────────────────┘"
],
[
" "Int" ╷ ExprSuffix ";"",
" ├─ExprAtom─┘ │ │",
" ├─Expr────────────────┤ │",
" ├─Exprs───────────────┘ │",
" └─Stmt────────────────────┘"
]
]
"#
.trim(),
);
}