Skip to content

Commit

Permalink
Implemented feature: member variables. Fixes github issue kevinmehall…
Browse files Browse the repository at this point in the history
  • Loading branch information
sandeep-datta committed Apr 5, 2020
1 parent 8898f64 commit 7404fec
Show file tree
Hide file tree
Showing 7 changed files with 161 additions and 17 deletions.
3 changes: 2 additions & 1 deletion peg-macros/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ impl Grammar {
#[derive(Debug)]
pub enum Item {
Use(TokenStream),
MemberVariable(Ident, TokenStream),
Rule(Rule),
}

Expand Down Expand Up @@ -100,4 +101,4 @@ pub enum BoundedRepeat {
Plus,
Exact(TokenStream),
Both(Option<TokenStream>, Option<TokenStream>),
}
}
97 changes: 92 additions & 5 deletions peg-macros/grammar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -805,12 +805,28 @@ pub mod peg {
::peg::RuleResult::Matched(__pos, __value)
}
::peg::RuleResult::Failed => {
let __seq_res = __parse_peg_rule(__input, __state, __err_state, __pos);
match __seq_res {
::peg::RuleResult::Matched(__pos, r) => {
::peg::RuleResult::Matched(__pos, { Item::Rule(r) })
let __choice_res = {
let __seq_res = __parse_rust_var(__input, __state, __err_state, __pos);
match __seq_res {
::peg::RuleResult::Matched(__pos, v) => {
::peg::RuleResult::Matched(__pos, { v })
}
::peg::RuleResult::Failed => ::peg::RuleResult::Failed,
}
};
match __choice_res {
::peg::RuleResult::Matched(__pos, __value) => {
::peg::RuleResult::Matched(__pos, __value)
}
::peg::RuleResult::Failed => {
let __seq_res = __parse_peg_rule(__input, __state, __err_state, __pos);
match __seq_res {
::peg::RuleResult::Matched(__pos, r) => {
::peg::RuleResult::Matched(__pos, { Item::Rule(r) })
}
::peg::RuleResult::Failed => ::peg::RuleResult::Failed,
}
}
::peg::RuleResult::Failed => ::peg::RuleResult::Failed,
}
}
}
Expand Down Expand Up @@ -1206,6 +1222,77 @@ pub mod peg {
}
}
}
fn __parse_rust_var<'input>(
__input: &'input Input,
__state: &mut ParseState<'input>,
__err_state: &mut ::peg::error::ErrorState,
__pos: usize,
) -> ::peg::RuleResult<Item> {
#![allow(non_snake_case, unused)]
{
let __seq_res = __parse_IDENT(__input, __state, __err_state, __pos);
match __seq_res {
::peg::RuleResult::Matched(__pos, name) => {
let __seq_res =
match ::peg::ParseLiteral::parse_string_literal(__input, __pos, ":") {
::peg::RuleResult::Matched(__pos, __val) => {
::peg::RuleResult::Matched(__pos, __val)
}
::peg::RuleResult::Failed => __err_state.mark_failure(__pos, "\":\""),
};
match __seq_res {
::peg::RuleResult::Matched(__pos, _) => {
let __seq_res = {
let str_start = __pos;
match match __parse_rust_type(__input, __state, __err_state, __pos)
{
::peg::RuleResult::Matched(pos, _) => {
::peg::RuleResult::Matched(pos, ())
}
::peg::RuleResult::Failed => ::peg::RuleResult::Failed,
} {
::peg::RuleResult::Matched(__newpos, _) => {
::peg::RuleResult::Matched(
__newpos,
::peg::ParseSlice::parse_slice(
__input, str_start, __newpos,
),
)
}
::peg::RuleResult::Failed => ::peg::RuleResult::Failed,
}
};
match __seq_res {
::peg::RuleResult::Matched(__pos, rt) => {
let __seq_res = match ::peg::ParseLiteral::parse_string_literal(
__input, __pos, ";",
) {
::peg::RuleResult::Matched(__pos, __val) => {
::peg::RuleResult::Matched(__pos, __val)
}
::peg::RuleResult::Failed => {
__err_state.mark_failure(__pos, "\";\"")
}
};
match __seq_res {
::peg::RuleResult::Matched(__pos, _) => {
::peg::RuleResult::Matched(__pos, {
Item::MemberVariable(name, rt.to_owned())
})
}
::peg::RuleResult::Failed => ::peg::RuleResult::Failed,
}
}
::peg::RuleResult::Failed => ::peg::RuleResult::Failed,
}
}
::peg::RuleResult::Failed => ::peg::RuleResult::Failed,
}
}
::peg::RuleResult::Failed => ::peg::RuleResult::Failed,
}
}
}
fn __parse_rust_path<'input>(
__input: &'input Input,
__state: &mut ParseState<'input>,
Expand Down
4 changes: 4 additions & 0 deletions peg-macros/grammar.rustpeg
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ rule peg_rule() -> Rule

rule item() -> Item
= u:rust_use() { Item::Use(u) }
/ v:rust_var() { v }
/ r:peg_rule() { Item::Rule(r) }

rule rust_doc_comment() -> Option<TokenStream> = $("#" "[" "doc" "=" LITERAL() "]")?
Expand All @@ -43,6 +44,9 @@ rule rust_use() -> TokenStream
/ ("as" IDENT())?
) ";") { v.to_owned() }

rule rust_var() -> Item
= name: IDENT() ":" rt:$(rust_type()) ";" { Item::MemberVariable(name, rt.to_owned()) }

rule rust_path()
= ("crate" "::")? IDENT() ++ "::"

Expand Down
29 changes: 23 additions & 6 deletions peg-macros/translate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ pub(crate) fn compile_grammar(grammar: &Grammar) -> TokenStream {
for item in &grammar.items {
match item {
Item::Use(tt) => items.push(tt.clone()),
Item::MemberVariable(_, _) => { /* do nothing */ }
Item::Rule(rule) => {
if seen_rule_names.insert(rule.name.to_string()) {
if rule.cached && !(rule.params.is_empty() && rule.ty_params.is_none()) {
Expand Down Expand Up @@ -111,25 +112,41 @@ pub(crate) fn compile_grammar(grammar: &Grammar) -> TokenStream {
fn make_parse_state(grammar: &Grammar) -> TokenStream {
let mut cache_fields_def: Vec<TokenStream> = Vec::new();
let mut cache_fields: Vec<Ident> = Vec::new();
for rule in grammar.iter_rules() {
if rule.cached {
let name = format_ident!("{}_cache", rule.name);
let ret_ty = rule.ret_type.clone().unwrap_or_else(|| quote!(()));
cache_fields_def.push(quote!{ #name: ::std::collections::HashMap<usize, ::peg::RuleResult<#ret_ty>> });
cache_fields.push(name);
let mut user_var_defs: Vec<TokenStream> = Vec::new();
let mut user_var_inits: Vec<TokenStream> = Vec::new();

for item in &grammar.items {
match item {
Item::Rule(rule) => {
if rule.cached {
let name = format_ident!("{}_cache", rule.name);
let ret_ty = rule.ret_type.clone().unwrap_or_else(|| quote!(()));
cache_fields_def.push(quote!{ #name: ::std::collections::HashMap<usize, ::peg::RuleResult<#ret_ty>> });
cache_fields.push(name);
}
}
Item::MemberVariable(name, ty) => {
user_var_defs.push(quote!{ #name: #ty });
user_var_inits.push(quote!{ #name: Default::default() });
}
Item::Use(_) => {
// Do nothing
}
}
}

quote! {
struct ParseState<'input> {
_phantom: ::std::marker::PhantomData<&'input ()>,
#(#user_var_defs),*
#(#cache_fields_def),*
}

impl<'input> ParseState<'input> {
fn new() -> ParseState<'input> {
ParseState {
_phantom: ::std::marker::PhantomData,
#(#user_var_inits),*
#(#cache_fields: ::std::collections::HashMap::new()),*
}
}
Expand Down
2 changes: 1 addition & 1 deletion tests/compile-fail/syntax_error.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
extern crate peg;

peg::parser!(grammar foo() for str {
fn asdf() {} //~ ERROR expected one of "#", "crate", "pub", "rule", "use", "}"
fn asdf() {} //~ ERROR expected ":"
});

fn main() {}
8 changes: 4 additions & 4 deletions tests/compile-fail/syntax_error.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error: expected one of "#", "crate", "pub", "rule", "use", "}"
--> $DIR/syntax_error.rs:4:5
error: expected ":"
--> $DIR/syntax_error.rs:4:8
|
4 | fn asdf() {} //~ ERROR expected one of "#", "crate", "pub", "rule", "use", "}"
| ^^
4 | fn asdf() {} //~ ERROR expected ":"
| ^^^^
35 changes: 35 additions & 0 deletions tests/run-pass/member_variables.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
use crate::line_counter::lines;

peg::parser!( grammar line_counter() for str {
line_count: u32;

pub rule lines() -> u32
= line()* { __state.line_count }

rule line()
= (terminated_line() / unterminated_line()) { __state.line_count += 1; }

rule terminated_line()
= (not_eol() one_char())* eol()

rule unterminated_line()
= (not_eol() one_char())+

rule one_char() = [_]
rule not_eol() = !eol()
rule eol() = "\r\n" / "\n"
rule eof() = ![_]
});

fn main() {
assert_eq!(lines(""), Ok(0));

assert_eq!(lines("\n"), Ok(1));
assert_eq!(lines("abc\n"), Ok(1));
assert_eq!(lines("abc"), Ok(1));

assert_eq!(lines("\n\n"), Ok(2));
assert_eq!(lines("abc\ndef\n"), Ok(2));
assert_eq!(lines("abc\ndef"), Ok(2));
assert_eq!(lines("\ndef"), Ok(2));
}

0 comments on commit 7404fec

Please sign in to comment.