Skip to content

Commit

Permalink
Added tests and fixed some issues.
Browse files Browse the repository at this point in the history
  • Loading branch information
dragostis committed Jun 28, 2017
1 parent 65ffafa commit a76b989
Show file tree
Hide file tree
Showing 8 changed files with 408 additions and 45 deletions.
3 changes: 2 additions & 1 deletion pest/src/parser_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,11 @@ pub enum Lookahead {
pub struct ParserState<R: RuleType, I: Input> {
queue: Vec<QueueableToken<R>>,
lookahead: Lookahead,
is_atomic: bool,
pos_attempts: Vec<R>,
neg_attempts: Vec<R>,
attempt_pos: usize,
/// Specifies whether the current state is atomic
pub is_atomic: bool,
/// Stack of `Span`s
pub stack: Vec<Span<I>>
}
Expand Down
2 changes: 1 addition & 1 deletion pest_derive/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ proc-macro = true
[dependencies]
quote = "^0.3"
syn = "^0.10"
pest = { path = "../pest" }
pest = { git = "https:/pest-parser/pest", branch = "procedural" }

[badges]
travis-ci = { repository = "pest-parser/pest" }
72 changes: 44 additions & 28 deletions pest_derive/src/generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ pub fn generate(name: Ident, rules: Vec<Rule>, defaults: Vec<Ident>) -> Tokens {
pos: pest::inputs::Position<I>,
state: &mut pest::ParserState<Rule, I>
) -> Result<pest::inputs::Position<I>, pest::inputs::Position<I>> {
let string = state.stack.pop().expect("pop was called on empty stack").capture();
let span = state.stack.pop().expect("pop was called on empty stack");
let string = span.capture();

pos.match_string(string)
}
Expand Down Expand Up @@ -156,8 +157,8 @@ fn generate_rule(rule: Rule) -> Tokens {
pos: pest::inputs::Position<I>,
state: &mut pest::ParserState<Rule, I>
) -> Result<pest::inputs::Position<I>, pest::inputs::Position<I>> {
state.atomic(true, move |state| {
state.rule(Rule::#name, pos, |state, pos| {
state.rule(Rule::#name, pos, |state, pos| {
state.atomic(true, move |state| {
#expr
})
})
Expand All @@ -169,8 +170,8 @@ fn generate_rule(rule: Rule) -> Tokens {
pos: pest::inputs::Position<I>,
state: &mut pest::ParserState<Rule, I>
) -> Result<pest::inputs::Position<I>, pest::inputs::Position<I>> {
state.atomic(false, move |state| {
state.rule(Rule::#name, pos, |state, pos| {
state.rule(Rule::#name, pos, |state, pos| {
state.atomic(false, move |state| {
#expr
})
})
Expand All @@ -197,42 +198,52 @@ fn generate_skip(rules: &Vec<Rule>) -> Tokens {
pos: pest::inputs::Position<I>,
state: &mut pest::ParserState<Rule, I>
) -> Result<pest::inputs::Position<I>, pest::inputs::Position<I>> {
pos.repeat(|pos| {
whitespace(pos, state)
})
if !state.is_atomic {
pos.repeat(|pos| {
whitespace(pos, state)
})
} else {
Ok(pos)
}
}
},
(false, true) => quote! {
fn skip<I: pest::inputs::Input>(
pos: pest::inputs::Position<I>,
state: &mut pest::ParserState<Rule, I>
) -> Result<pest::inputs::Position<I>, pest::inputs::Position<I>> {
pos.repeat(|pos| {
comment(pos, state)
})
if !state.is_atomic {
pos.repeat(|pos| {
comment(pos, state)
})
} else {
Ok(pos)
}
}
},
(true, true) => quote! {
fn skip<I: pest::inputs::Input>(
pos: pest::inputs::Position<I>,
state: &mut pest::ParserState<Rule, I>
) -> Result<pest::inputs::Position<I>, pest::inputs::Position<I>> {
state.sequence(move |state| {
pos.sequence(|pos| {
pos.repeat(|pos| {
whitespace(pos, state)
}).and_then(|pos| {
if !state.is_atomic {
state.sequence(move |state| {
pos.sequence(|pos| {
pos.repeat(|pos| {
state.sequence(move |state| {
pos.sequence(|pos| {
pos.optional(|pos| {
comment(pos, state)
}).and_then(|pos| {
state.sequence(move |state| {
pos.sequence(|pos| {
whitespace(pos, state).and_then(|pos| {
pos.repeat(|pos| {
whitespace(pos, state)
whitespace(pos, state)
}).and_then(|pos| {
pos.repeat(|pos| {
state.sequence(move |state| {
pos.sequence(|pos| {
pos.optional(|pos| {
comment(pos, state)
}).and_then(|pos| {
state.sequence(move |state| {
pos.sequence(|pos| {
whitespace(pos, state).and_then(|pos| {
pos.repeat(|pos| {
whitespace(pos, state)
})
})
})
})
Expand All @@ -243,7 +254,9 @@ fn generate_skip(rules: &Vec<Rule>) -> Tokens {
})
})
})
})
} else {
Ok(pos)
}
}
}
}
Expand Down Expand Up @@ -477,7 +490,10 @@ fn generate_expr_atomic(expr: Expr) -> Tokens {
let start = pos.clone();

match #expr {
Ok(end) => pos.match_string(start.span(end).capture()),
Ok(end) => {
state.stack.push(start.span(end.clone()));
Ok(end)
}
Err(pos) => Err(pos)
}
}
Expand Down
3 changes: 2 additions & 1 deletion pest_derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ extern crate proc_macro;
extern crate quote;
extern crate syn;

use std::env;
use std::path::Path;
use std::rc::Rc;

Expand All @@ -38,7 +39,7 @@ pub fn derive_parser(input: TokenStream) -> TokenStream {

let (name, path) = parse_derive(source);

let root = std::env::var("CARGO_MANIFEST_DIR").unwrap_or(".".into());
let root = env::var("CARGO_MANIFEST_DIR").unwrap_or(".".into());
let path = Path::new(&root).join("src/").join(&path);
let file_name = match path.file_name() {
Some(file_name) => file_name,
Expand Down
9 changes: 4 additions & 5 deletions pest_derive/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -847,18 +847,17 @@ fn consume_expr<I: Input>(
GrammarRule::insensitive_string => {
let span = pair.into_span();
let string = span.capture();
Expr::Insens(string[1..string.len() - 1].to_owned())
Expr::Insens(string[2..string.len() - 1].to_owned())
}
GrammarRule::range => {
let mut pairs = pair.into_inner();
let span = pairs.next().unwrap().into_span();
let start = span.capture();
pairs.next();
let span = pairs.next().unwrap().into_span();
let end = span.capture();

Expr::Range(
start[1..start.len() - 1].to_owned(),
end[1..end.len() - 1].to_owned()
)
Expr::Range(start.to_owned(), end.to_owned())
}
_ => unreachable!()
};
Expand Down
18 changes: 9 additions & 9 deletions pest_derive/src/validator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,13 @@ pub fn validate_pairs<I: Input>(pairs: Pairs<GrammarRule, I>) -> Vec<Ident> {
pest_keywords.insert("push");
pest_keywords.insert("soi");

let mut predefined = HashSet::new();
predefined.insert("any");
predefined.insert("eoi");
predefined.insert("peek");
predefined.insert("pop");
predefined.insert("soi");

let definitions: Vec<_> = pairs.clone()
.filter(|pair| pair.as_rule() == GrammarRule::grammar_rule)
.map(|pair| {
Expand All @@ -90,13 +97,7 @@ pub fn validate_pairs<I: Input>(pairs: Pairs<GrammarRule, I>) -> Vec<Ident> {
let called_rules: Vec<_> = pairs.clone()
.filter(|pair| pair.as_rule() == GrammarRule::grammar_rule)
.flat_map(|pair| {
let expr = pair.into_inner()
.skip(4)
.next()
.unwrap()
.into_inner();

expr.flatten().filter(|pair| {
pair.into_inner().flatten().skip(1).filter(|pair| {
pair.as_rule() == GrammarRule::identifier
}).map(|pair| {
pair.into_span()
Expand All @@ -108,8 +109,7 @@ pub fn validate_pairs<I: Input>(pairs: Pairs<GrammarRule, I>) -> Vec<Ident> {
errors.extend(validate_rust_keywords(&definitions, &rust_keywords));
errors.extend(validate_pest_keywords(&definitions, &pest_keywords));
errors.extend(validate_already_defined(&definitions));
// TODO: Add the actual set of predefined rules.
errors.extend(validate_undefined(&definitions, &called_rules, &HashSet::new()));
errors.extend(validate_undefined(&definitions, &called_rules, &predefined));

let errors = errors.into_iter().map(|error| {
format!("grammar error\n\n{}", error)
Expand Down
17 changes: 17 additions & 0 deletions pest_derive/tests/grammar.pest
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
string = { "abc" }
insensitive = { ^"abc" }
range = { '0'..'9' }
ident = { string }
pos_pred = { &string }
neg_pred = { !string }
sequence = !@{ string ~ string }
sequence_atomic = @{ string ~ string }
choice = { string | range }
optional = { string? }
repeat = { string* }
repeat_atomic = @{ string* }
repeat_once = { string+ }
repeat_once_atomic = @{ string+ }
peek_ = { push(range) ~ push(range) ~ peek ~ peek }
pop_ = { push(range) ~ push(range) ~ pop ~ pop }
whitespace = _{ " " }
Loading

0 comments on commit a76b989

Please sign in to comment.