fix unit tests

This commit is contained in:
Niko Matsakis 2015-07-16 06:09:31 -04:00
parent c92619fe15
commit 7b31c3eed6
13 changed files with 96 additions and 99 deletions

View File

@ -39,7 +39,7 @@ pub struct ExternToken {
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct AssociatedType {
pub span: Span,
pub type_span: Span,
pub type_name: InternedString,
pub type_ref: TypeRef,
}

View File

@ -60,7 +60,7 @@ pub struct Production {
// handy to have it
pub nonterminal: NonterminalString,
pub symbols: Vec<Symbol>,
pub action_fn: ActionFn,
pub action: ProductionAction,
pub span: Span,
}
@ -70,6 +70,11 @@ pub enum Symbol {
Terminal(TerminalString),
}
#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub enum ProductionAction {
Call(ActionFn)
}
#[derive(Clone, PartialEq, Eq)]
pub struct ActionFnDefn {
pub arg_patterns: Vec<InternedString>,
@ -231,7 +236,7 @@ impl Debug for Production {
fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
write!(fmt,
"{} = {} => {:?};",
self.nonterminal, Sep(", ", &self.symbols), self.action_fn)
self.nonterminal, Sep(", ", &self.symbols), self.action)
}
}

View File

@ -2,7 +2,7 @@
//!
//! [recursive ascent]: https://en.wikipedia.org/wiki/Recursive_ascent_parser
use grammar::repr::{Grammar, NonterminalString, Symbol, TerminalString, Types};
use grammar::repr::{Grammar, NonterminalString, ProductionAction, Symbol, TerminalString, Types};
use lr1::{Lookahead, State, StateIndex};
use rust::RustWrite;
use std::io::{self, Write};
@ -229,13 +229,16 @@ impl<'ascent,'grammar,W:Write> RecursiveAscent<'ascent,'grammar,W> {
}
// invoke the action code
rust!(self.out, "let {}nt = super::{}actions::{}action{}({}{});",
self.prefix,
self.prefix,
self.prefix,
production.action_fn.index(),
self.grammar.user_parameter_refs(),
Sep(", ", &transfer_syms));
match production.action {
ProductionAction::Call(action_fn) =>
rust!(self.out, "let {}nt = super::{}actions::{}action{}({}{});",
self.prefix,
self.prefix,
self.prefix,
action_fn.index(),
self.grammar.user_parameter_refs(),
Sep(", ", &transfer_syms)),
}
// wrap up the result along with the (unused) lookahead
if !transfer_syms.is_empty() {

View File

@ -26,14 +26,13 @@ fn first(first: &FirstSets, symbols: &[Symbol], lookahead: Lookahead) -> Vec<Loo
#[test]
fn basic() {
let grammar = normalized_grammar(r#"
grammar {
grammar;
extern token { enum Tok { } }
A = B "C";
B: Option<u32> = {
"D" => Some(1);
=> None;
};
}
"#);
let first_sets = FirstSets::new(&grammar);

View File

@ -44,17 +44,16 @@ fn items<'g>(grammar: &'g Grammar, nonterminal: &str, index: usize, la: Lookahea
#[test]
fn start_state() {
let grammar = normalized_grammar(r#"
grammar {
grammar;
extern token { enum Tok { } }
A = B "C";
B: Option<u32> = {
"D" => Some(1);
=> None;
};
}
"#);
let items = items(&grammar, "A", 0, EOF);
expect_debug(items, r#"[
expect_debug(items.vec, r#"[
A = (*) B "C" [EOF],
B = (*) ["C"],
B = (*) "D" ["C"]
@ -64,21 +63,20 @@ grammar {
#[test]
fn start_state_1() {
let grammar = normalized_grammar(r#"
grammar {
extern token { enum Tok { } }
A = B C;
B: Option<u32> = {
"B1" => Some(1);
=> None;
};
C: Option<u32> = {
"C1" => Some(1);
=> None;
};
}
grammar;
extern token { enum Tok { } }
A = B C;
B: Option<u32> = {
"B1" => Some(1);
=> None;
};
C: Option<u32> = {
"C1" => Some(1);
=> None;
};
"#);
expect_debug(items(&grammar, "A", 0, EOF), r#"[
expect_debug(items(&grammar, "A", 0, EOF).vec, r#"[
A = (*) B C [EOF],
B = (*) [EOF],
B = (*) ["C1"],
@ -86,7 +84,7 @@ grammar {
B = (*) "B1" ["C1"]
]"#);
expect_debug(items(&grammar, "A", 1, EOF), r#"[
expect_debug(items(&grammar, "A", 1, EOF).vec, r#"[
A = B (*) C [EOF],
C = (*) [EOF],
C = (*) "C1" [EOF]
@ -96,7 +94,7 @@ grammar {
#[test]
fn expr_grammar1() {
let grammar = normalized_grammar(r#"
grammar {
grammar;
extern token { enum Tok { } }
S: () =
@ -111,7 +109,6 @@ grammar {
"N" => ();
"(" E ")" => ();
};
}
"#);
// for now, just test that process does not result in an error

View File

@ -69,7 +69,7 @@ impl LowerState {
nonterminal: nt.name,
span: alt.span,
symbols: symbols,
action_fn: action_fn,
action: r::ProductionAction::Call(action_fn),
};
self.productions.push(production);
}
@ -129,7 +129,7 @@ impl LowerState {
self.productions.push(r::Production {
nonterminal: fake_name,
symbols: symbols,
action_fn: action_fn,
action: r::ProductionAction::Call(action_fn),
span: nt.span
});
(nt.name, fake_name)

View File

@ -11,7 +11,7 @@ fn flat_productions(grammar: &Grammar) -> Vec<Production> {
// sort by the action fn index just to get a consistent ordering
productions.sort_by(|k1, k2| {
Ord::cmp(&k1.action_fn.index(), &k2.action_fn.index())
Ord::cmp(&k1.action, &k2.action)
});
productions
@ -20,7 +20,7 @@ fn flat_productions(grammar: &Grammar) -> Vec<Production> {
#[test]
fn test_comma() {
let grammar = parser::parse_grammar("
grammar {
grammar;
extern token { enum Tok { } }
Comma<E>: Vec<E> =
@ -28,29 +28,28 @@ grammar {
v.into_iter().chain(e.into_iter()).collect();
Ids = Comma<\"Id\">;
}
").unwrap();
let actual = normalize_without_validating(grammar).unwrap();
expect_debug(flat_productions(&actual),
r#"[
Ids = Comma<"Id"> => ActionFn(0);,
Comma<"Id"> = (<"Id"> ",")*, "Id"? => ActionFn(1);,
"Id"? = "Id" => ActionFn(2);,
"Id"? = => ActionFn(3);,
(<"Id"> ",")* = => ActionFn(4);,
(<"Id"> ",")* = (<"Id"> ",")*, (<"Id"> ",") => ActionFn(5);,
(<"Id"> ",") = "Id", "," => ActionFn(6);
Ids = Comma<"Id"> => Call(ActionFn(0));,
Comma<"Id"> = (<"Id"> ",")*, "Id"? => Call(ActionFn(1));,
"Id"? = "Id" => Call(ActionFn(2));,
"Id"? = => Call(ActionFn(3));,
(<"Id"> ",")* = => Call(ActionFn(4));,
(<"Id"> ",")* = (<"Id"> ",")*, (<"Id"> ",") => Call(ActionFn(5));,
(<"Id"> ",") = "Id", "," => Call(ActionFn(6));
]"#);
expect_debug(&actual.action_fn_defns,
r#"[
fn _(__0: Vec<Tok>) -> Vec<Tok> { (__0) },
fn _(v: std::vec::Vec<Tok>, e: std::option::Option<Tok>) -> Vec<Tok> { v.into_iter().chain(e.into_iter()).collect() },
fn _(__0: Tok) -> std::option::Option<Tok> { Some(__0) },
fn _() -> std::option::Option<Tok> { None },
fn _() -> std::vec::Vec<Tok> { vec![] },
fn _(v: std::vec::Vec<Tok>, e: Tok) -> std::vec::Vec<Tok> { { let mut v = v; v.push(e); v } },
fn _(v: ::std::vec::Vec<Tok>, e: ::std::option::Option<Tok>) -> Vec<Tok> { v.into_iter().chain(e.into_iter()).collect() },
fn _(__0: Tok) -> ::std::option::Option<Tok> { Some(__0) },
fn _() -> ::std::option::Option<Tok> { None },
fn _() -> ::std::vec::Vec<Tok> { vec![] },
fn _(v: ::std::vec::Vec<Tok>, e: Tok) -> ::std::vec::Vec<Tok> { { let mut v = v; v.push(e); v } },
fn _(__0: Tok, _: Tok) -> Tok { (__0) }
]"#);
}

View File

@ -6,37 +6,35 @@ use super::expand_macros;
#[test]
fn test_comma() {
let grammar = parser::parse_grammar(r#"
grammar {
grammar;
Comma<E>: Vec<E> =
<v:(<E> ",")*> <e:E?> =>
v.into_iter().chain(e.into_iter()).collect();
Ids = Comma<"Id">;
}
"#).unwrap();
let actual = expand_macros(grammar).unwrap();
let expected = parser::parse_grammar(r#"
grammar {
grammar;
Ids = `Comma<"Id">`;
`Comma<"Id">`: Vec<`"Id"`> =
<v:`(<"Id"> ",")*`> <e:`"Id"?`> =>
v.into_iter().chain(e.into_iter()).collect();
`"Id"?`: std::option::Option<`"Id"`> = {
`"Id"?`: ::std::option::Option<`"Id"`> = {
"Id" => Some(<>);
=> None;
};
`(<"Id"> ",")*`: std::vec::Vec<``(<"Id"> ",")``> = {
`(<"Id"> ",")*`: ::std::vec::Vec<``(<"Id"> ",")``> = {
=> vec![];
<v:`(<"Id"> ",")*`> <e:`(<"Id"> ",")`> => { let mut v = v; v.push(e); v };
};
`(<"Id"> ",")`: `"Id"` = <"Id"> "," => (<>);
}
"#).unwrap();
compare(actual, expected);
@ -45,7 +43,7 @@ grammar {
#[test]
fn test_if_match() {
let grammar = parser::parse_grammar(r#"
grammar {
grammar;
Expr<E> = {
A if E == "A*C";
B if E ~~ "^A*C$";
@ -56,13 +54,12 @@ grammar {
Expr1 = Expr<"A*C">;
Expr2 = Expr<"AAC">;
Expr3 = Expr<"ABC">;
}
"#).unwrap();
let actual = expand_macros(grammar).unwrap();
let expected = parser::parse_grammar(r#"
grammar {
grammar;
Expr1 = `Expr<"A*C">`;
Expr2 = `Expr<"AAC">`;
Expr3 = `Expr<"ABC">`;
@ -70,7 +67,6 @@ grammar {
`Expr<"ABC">` = { C; D; };
`Expr<"AAC">` = { B; C; };
`Expr<"A*C">` = { A; D; };
}
"#).unwrap();
compare(actual, expected);

View File

@ -28,12 +28,11 @@ fn compare(g1: &str, expected: Vec<(&'static str, &'static str)>) {
#[test]
fn test_pairs_and_tokens() {
compare("
grammar {
grammar;
extern token { enum Tok { } }
X = Y Z;
Y: Foo = \"Hi\";
Z = \"Ho\";
}
", vec![
("X", "(Foo, Tok)"),
("Y", "Foo"),
@ -44,14 +43,13 @@ grammar {
#[test]
fn test_cycle_direct() {
let grammar = parser::parse_grammar("
grammar {
grammar;
extern token { enum Tok { } }
X = {
X Y;
<Y> => vec![<>];
};
Y = \"Hi\";
}
").unwrap();
let actual = expand_macros(grammar).unwrap();
@ -61,13 +59,12 @@ grammar {
#[test]
fn test_cycle_indirect() {
let grammar = parser::parse_grammar("
grammar {
grammar;
extern token { enum Tok { } }
A = B;
B = C;
C = D;
D = A;
}
").unwrap();
let actual = expand_macros(grammar).unwrap();
@ -77,11 +74,10 @@ grammar {
#[test]
fn test_macro_expansion() {
compare("
grammar {
grammar;
extern token { enum Tok { } }
Two<X>: (X, X) = X X;
Ids = Two<\"Id\">;
}
", vec![
("Ids", "(Tok, Tok)"),
(r#"Two<"Id">"#, "(Tok, Tok)"),
@ -91,11 +87,10 @@ grammar {
#[test]
fn test_macro_expansion_infer() {
compare("
grammar {
grammar;
extern token { enum Tok { } }
Two<X> = X X;
Ids = Two<\"Id\">;
}
", vec![
("Ids", "(Tok, Tok)"),
(r#"Two<"Id">"#, "(Tok, Tok)"),
@ -105,13 +100,12 @@ grammar {
#[test]
fn test_type_question() {
compare("
grammar {
grammar;
extern token { enum Tok { } }
X = Y?;
Y = \"Hi\";
}
",vec![
("X", "std::option::Option<Tok>"),
("X", "::std::option::Option<Tok>"),
("Y", "Tok")
])
}
@ -119,25 +113,24 @@ grammar {
#[test]
fn test_star_plus_question() {
compare("
grammar {
grammar;
extern token { enum Tok { } }
A = Z*;
X = \"Hi\"*;
Y = \"Hi\"+;
Z = \"Hi\"?;
}
", vec![
("A", "std::vec::Vec<std::option::Option<Tok>>"),
("X", "std::vec::Vec<Tok>"),
("Y", "std::vec::Vec<Tok>"),
("Z", "std::option::Option<Tok>")
("A", "::std::vec::Vec<::std::option::Option<Tok>>"),
("X", "::std::vec::Vec<Tok>"),
("Y", "::std::vec::Vec<Tok>"),
("Z", "::std::option::Option<Tok>")
])
}
#[test]
fn test_action() {
compare(r#"
grammar {
grammar;
extern token { enum Tok { } }
X = {
@ -146,7 +139,6 @@ grammar {
};
Y: i32 = "foo" => 22;
}
"#,vec![
("X", "i32"),
("Y", "i32"),
@ -156,7 +148,7 @@ grammar {
#[test]
fn test_inconsistent_action() {
let grammar = parser::parse_grammar("
grammar {
grammar;
extern token { enum Tok { } }
X = {
@ -168,7 +160,6 @@ grammar {
Y: i32 = \"foo\" => 22;
Z: u32 = \"bar\" => 22;
}
").unwrap();
let actual = expand_macros(grammar).unwrap();

View File

@ -70,14 +70,14 @@ impl<'grammar> Validator<'grammar> {
for associated_type in &data.associated_types {
if !allowed_names.contains(&associated_type.type_name) {
return_err!(
associated_type.span,
associated_type.type_span,
"associated type `{}` not recognized, \
try one of the following: {}",
associated_type.type_name,
Sep(", ", &allowed_names));
} else if !new_names.insert(associated_type.type_name) {
return_err!(
associated_type.span,
associated_type.type_span,
"associated type `{}` already specified",
associated_type.type_name);
}

View File

@ -1,9 +1,5 @@
use intern::intern;
use parser;
use normalize::macro_expand::expand_macros;
use normalize::tyinfer::infer_types;
use grammar::parse_tree::{NonterminalString, Span};
use grammar::repr::TypeRepr;
use grammar::parse_tree::{Span};
use regex::Regex;
fn check_err(expected_err: &str, grammar: &str) {
@ -36,33 +32,42 @@ fn check_err(expected_err: &str, grammar: &str) {
fn unknown_nonterminal() {
check_err(
"no definition found for nonterminal `Y`",
r#"grammar { X = X >>>Y<<<; }"#);
r#"grammar; X = X >>>Y<<<;"#);
}
#[test]
fn repeated_macro_arg() {
check_err(
"multiple macro arguments declared with the name `Y`",
r#"grammar { >>>X<Y,Y> <<<= "foo"; }"#);
r#"grammar; >>>X<Y,Y> <<<= "foo";"#);
}
#[test]
fn unknown_nonterminal_two() {
check_err(
"no definition found for nonterminal `Expr`",
r#"grammar { Term = { <n:"Num"> => n.as_num(); "A" <>>>Expr<<<> "B"; }; }"#);
r#"grammar; Term = { <n:"Num"> => n.as_num(); "A" <>>>Expr<<<> "B"; };"#);
}
#[test]
fn named_symbols() {
check_err(
r#"named symbols (like `"Num"`) require a custom action"#,
r#"grammar { Term = { <n:>>>"Num"<<<>; }; }"#);
r#"named symbols \(like `"Num"`\) require a custom action"#,
r#"grammar; Term = { <n:>>>"Num"<<<>; };"#);
}
#[test]
fn bad_assoc_type() {
check_err(
r#"named symbols (like `"Num"`) require a custom action"#,
r#"grammar { extern token { type Foo = i32; } }"#);
r#"associated type `Foo` not recognized"#,
r#"grammar; extern token { type >>>Foo <<<= i32; enum Tok { } }"#);
}
#[test]
fn dup_assoc_type() {
check_err(
r#"associated type `Location` already specified"#,
r#"grammar; extern token { type Location = i32;
type >>>Location <<<= u32;
enum Tok { } }"#);
}

View File

@ -265,8 +265,10 @@ rusty_peg! {
};
ASSOCIATED_TYPE: AssociatedType =
(<lo:POSL> "type" <n:ID> "=" <t:TYPE_REF> ";" <hi:POSR>) => {
AssociatedType { span: Span(lo, hi), type_name: n, type_ref: t }
("type" <lo1:POSL> <n:ID> <hi1:POSR> "=" <t:TYPE_REF> ";") => {
AssociatedType { type_span: Span(lo1, hi1),
type_name: n,
type_ref: t }
};
CONVERSION: Conversion =

View File

@ -1,4 +1,4 @@
use grammar::parse_tree::{Symbol, SymbolKind, TypeRef};
use grammar::parse_tree::{SymbolKind, TypeRef};
#[test]
fn type_ref() {