Skip to content

Commit 58ba95b

Browse files
committed
test(item): add closure_0 and 1 and goto tests
1 parent 17d49cb commit 58ba95b

File tree

2 files changed

+174
-11
lines changed

2 files changed

+174
-11
lines changed

src/grammar/grammar.rs

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ use std::collections::{BTreeSet, BTreeMap};
33
use crate::automata::dfa::DFA;
44
use crate::grammar::consts::{EPSILON, STRING_END};
55

6+
use super::item::Item;
7+
68
pub type NonTerminal = usize;
79
pub type Terminal = char;
810

@@ -31,8 +33,20 @@ pub struct Grammar {
3133

3234

3335
impl Grammar {
34-
pub fn first_k(&self, letter: &Vec<Letter>, look_ahead: usize) -> BTreeSet<Terminal> {
35-
unimplemented!();
36+
pub fn new(start_symbol: NonTerminal, productions: Vec<Production>) -> Self {
37+
Grammar {
38+
start_symbol,
39+
productions,
40+
nullable: None,
41+
}
42+
}
43+
44+
pub fn get_start_symbol(&self) -> NonTerminal {
45+
self.start_symbol
46+
}
47+
48+
pub fn get_productions(&self) -> &Vec<Production> {
49+
&self.productions
3650
}
3751

3852
pub fn first(&mut self, letter: &Letter) -> BTreeSet<Terminal> {
@@ -91,10 +105,6 @@ impl Grammar {
91105
first
92106
}
93107

94-
pub fn follow_k(&self, letter: &NonTerminal, look_ahead: usize) -> BTreeSet<Terminal> {
95-
unimplemented!();
96-
}
97-
98108
pub fn follow(&mut self, non_terminal: &NonTerminal) -> BTreeSet<Terminal> {
99109
if let None = self.nullable {
100110
self.nullable = Some(self.get_nullable());
@@ -355,7 +365,7 @@ impl Grammar {
355365
});
356366

357367
// add corresponding productions
358-
let mut adj_list = self.transitions_to_adj_list();
368+
let mut adj_list = self.productions_to_adj_list();
359369
for unitary_couple in unitary_couples.iter() {
360370
if unitary_couple.0 == unitary_couple.1 {
361371
continue;
@@ -384,7 +394,7 @@ impl Grammar {
384394
self.nullable = None;
385395
}
386396

387-
pub fn transitions_to_adj_list(&self) -> BTreeMap<NonTerminal, BTreeSet<Vec<Letter>>> {
397+
pub fn productions_to_adj_list(&self) -> BTreeMap<NonTerminal, BTreeSet<Vec<Letter>>> {
388398
let mut adj_list: BTreeMap<NonTerminal, BTreeSet<Vec<Letter>>> = BTreeMap::new();
389399
for production in self.productions.iter() {
390400
adj_list.entry(production.lhs)
@@ -394,6 +404,16 @@ impl Grammar {
394404

395405
adj_list
396406
}
407+
408+
pub fn add_fake_initial_state(&mut self) -> () {
409+
let new_state = self.get_non_terminal().iter().max().unwrap() + 1;
410+
self.productions.push(Production {
411+
lhs: new_state,
412+
rhs: vec![Letter::NonTerminal(self.start_symbol)]
413+
});
414+
415+
self.start_symbol = new_state;
416+
}
397417
}
398418

399419
impl<T> From<&DFA<T>> for Grammar {

src/grammar/item.rs

Lines changed: 146 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ impl Item {
7373
let mut used_non_term = vec![false; grammar.get_non_terminal().len()];
7474
let mut non_terminals = Self::compute_closure_queue(items, &mut used_non_term);
7575

76-
let dot_production = Self::add_initial_sep(grammar.transitions_to_adj_list());
76+
let dot_production = Self::add_initial_sep(grammar.productions_to_adj_list());
7777

7878
// apply the closure to all the non terminals in non_terminals
7979
while let Some((non_terminal, letter_first)) = non_terminals.pop_front() {
@@ -82,14 +82,14 @@ impl Item {
8282
.iter()
8383
.for_each(|rhs| {
8484
// with dot_production, the dot is always at 0, so the first letter is 1
85-
if rhs.len() >= 1 {
85+
if rhs.len() >= 2 {
8686
let letter = &rhs[1];
8787

8888
if let Letter::NonTerminal(non_term) = letter {
8989
if !used_non_term[*non_term as usize] {
9090
used_non_term[*non_term as usize] = true;
9191

92-
if rhs.len() >= 2 {
92+
if rhs.len() >= 3 {
9393
non_terminals.push_back((*non_term, Some(rhs[2].clone())));
9494
} else {
9595
non_terminals.push_back((*non_term, None));
@@ -232,6 +232,149 @@ mod tests {
232232

233233
#[test]
234234
fn closure_0 () {
235+
// S -> (S)
236+
// S -> A
237+
// A -> a
238+
let mut grammar = Grammar::new(
239+
0,
240+
vec![
241+
Production { lhs: 0, rhs: vec![Letter::Terminal('('), Letter::NonTerminal(0), Letter::Terminal(')')] },
242+
Production { lhs: 0, rhs: vec![Letter::NonTerminal(1)] },
243+
Production { lhs: 1, rhs: vec![Letter::Terminal('a')] },
244+
],
245+
);
246+
grammar.add_fake_initial_state();
247+
248+
let mut start_item = set![Item {
249+
production: Production { lhs: 2, rhs: vec![Letter::Terminal(ITEM_SEP), Letter::NonTerminal(0)] },
250+
look_ahead: None,
251+
}];
252+
let closure = Item::closure(&mut start_item, &mut grammar).into_iter()
253+
.map(|item| item.production)
254+
.collect::<Vec<_>>();
255+
256+
let result = vec![
257+
Production { lhs: 2, rhs: vec![Letter::Terminal(ITEM_SEP), Letter::NonTerminal(0)] },
258+
Production { lhs: 0, rhs: vec![Letter::Terminal(ITEM_SEP), Letter::Terminal('('), Letter::NonTerminal(0), Letter::Terminal(')')] },
259+
Production { lhs: 0, rhs: vec![Letter::Terminal(ITEM_SEP), Letter::NonTerminal(1)] },
260+
Production { lhs: 1, rhs: vec![Letter::Terminal(ITEM_SEP), Letter::Terminal('a')] },
261+
];
262+
263+
assert!(closure.iter().all(|item| result.contains(item)));
264+
assert!(result.iter().all(|item| closure.contains(item)));
265+
}
266+
267+
#[test]
268+
fn closure_1() {
269+
// S -> CC
270+
// C -> cC
271+
// C -> d
272+
273+
let mut grammar = Grammar::new(
274+
0,
275+
vec![
276+
Production { lhs: 0, rhs: vec![Letter::NonTerminal(1), Letter::NonTerminal(1)] },
277+
Production { lhs: 1, rhs: vec![Letter::Terminal('c'), Letter::NonTerminal(1)] },
278+
Production { lhs: 1, rhs: vec![Letter::Terminal('d')] },
279+
],
280+
);
281+
282+
grammar.add_fake_initial_state();
283+
284+
let mut start_item = set![Item {
285+
production: Production { lhs: 2, rhs: vec![Letter::Terminal(ITEM_SEP), Letter::NonTerminal(0)] },
286+
look_ahead: Some(STRING_END),
287+
}];
288+
289+
let closure: Vec<Item> = Item::closure(&mut start_item, &mut grammar).into_iter().collect();
290+
291+
let result = vec![
292+
Item {
293+
production: Production { lhs: 2, rhs: vec![Letter::Terminal(ITEM_SEP), Letter::NonTerminal(0)] },
294+
look_ahead: Some(STRING_END),
295+
},
296+
Item {
297+
production: Production { lhs: 0, rhs: vec![Letter::Terminal(ITEM_SEP), Letter::NonTerminal(1), Letter::NonTerminal(1)] },
298+
look_ahead: Some(STRING_END),
299+
},
300+
Item {
301+
production: Production { lhs: 1, rhs: vec![Letter::Terminal(ITEM_SEP), Letter::Terminal('c'), Letter::NonTerminal(1)] },
302+
look_ahead: Some('c'),
303+
},
304+
Item {
305+
production: Production { lhs: 1, rhs: vec![Letter::Terminal(ITEM_SEP), Letter::Terminal('c'), Letter::NonTerminal(1)] },
306+
look_ahead: Some('d'),
307+
},
308+
Item {
309+
production: Production { lhs: 1, rhs: vec![Letter::Terminal(ITEM_SEP), Letter::Terminal('d')] },
310+
look_ahead: Some('c'),
311+
},
312+
Item {
313+
production: Production { lhs: 1, rhs: vec![Letter::Terminal(ITEM_SEP), Letter::Terminal('d')] },
314+
look_ahead: Some('d'),
315+
},
316+
];
317+
318+
assert!(closure.iter().all(|item| result.contains(item)));
319+
assert!(result.iter().all(|item| closure.contains(item)));
320+
}
321+
322+
#[test]
323+
fn goto() {
324+
// S -> (S)
325+
// S -> ()
326+
let mut grammar = Grammar::new(
327+
0,
328+
vec![
329+
Production { lhs: 0, rhs: vec![Letter::Terminal('('), Letter::NonTerminal(0), Letter::Terminal(')')] },
330+
Production { lhs: 0, rhs: vec![Letter::Terminal('('), Letter::Terminal(')')] },
331+
],
332+
);
333+
grammar.add_fake_initial_state();
334+
335+
let mut start_item = set![Item {
336+
production: Production { lhs: 1, rhs: vec![Letter::Terminal(ITEM_SEP), Letter::NonTerminal(0)] },
337+
look_ahead: None,
338+
}];
339+
340+
let closure = Item::closure(&mut start_item, &mut grammar);
341+
let goto = Item::goto(&closure, &Letter::Terminal('(')).into_iter()
342+
.map(|item| item.production)
343+
.collect::<Vec<_>>();
344+
345+
// result should be
346+
// S -> (.S)
347+
// S -> (.)
348+
let result = vec![
349+
Production { lhs: 0, rhs: vec![Letter::Terminal('('), Letter::Terminal(ITEM_SEP), Letter::NonTerminal(0), Letter::Terminal(')')] },
350+
Production { lhs: 0, rhs: vec![Letter::Terminal('('), Letter::Terminal(ITEM_SEP), Letter::Terminal(')')] },
351+
];
352+
353+
assert!(goto.iter().all(|item| result.contains(item)));
354+
assert!(result.iter().all(|item| goto.contains(item)));
355+
356+
// SECOND PART OF TEST, APPLY CLOSURE TO GOTO'S OUTPUT
357+
let mut goto_items = goto.into_iter()
358+
.map(|item| Item {
359+
production: item,
360+
look_ahead: None,
361+
})
362+
.collect::<BTreeSet<_>>();
363+
364+
let closure = Item::closure(&mut goto_items, &mut grammar)
365+
.into_iter()
366+
.map(|item| item.production)
367+
.collect::<Vec<_>>();
368+
369+
let result = vec![
370+
Production { lhs: 0, rhs: vec![Letter::Terminal('('), Letter::Terminal(ITEM_SEP), Letter::NonTerminal(0), Letter::Terminal(')')] },
371+
Production { lhs: 0, rhs: vec![Letter::Terminal('('), Letter::Terminal(ITEM_SEP), Letter::Terminal(')')] },
372+
Production { lhs: 0, rhs: vec![Letter::Terminal(ITEM_SEP), Letter::Terminal('('), Letter::NonTerminal(0), Letter::Terminal(')')] },
373+
Production { lhs: 0, rhs: vec![Letter::Terminal(ITEM_SEP), Letter::Terminal('('), Letter::Terminal(')')] },
374+
];
375+
376+
assert!(closure.iter().all(|item| result.contains(item)));
377+
assert!(result.iter().all(|item| closure.contains(item)));
235378

236379
}
237380
}

0 commit comments

Comments
 (0)