Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extract the parser and validator from the pest_derive crate into pest_meta #159

Merged
merged 30 commits into from
Feb 18, 2018
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
c1e30aa
Extract ast, parser and validator into pest_meta
Victor-Savu Oct 7, 2017
5525216
Separate defaults generation from consume_rules
Victor-Savu Oct 7, 2017
1319bde
Rename Grammar{Parser,Rule} -> Pest{Parser/Rule}
Victor-Savu Oct 7, 2017
02d445d
Use the `maplit` crate for defining keyword sets
Victor-Savu Oct 7, 2017
47cfdbd
Remove unused rules `soi` and `eoi`
Victor-Savu Oct 7, 2017
927ac86
Use functional style for validation
Victor-Savu Oct 8, 2017
d718e67
Make validator return Result instead of panicking
Victor-Savu Oct 8, 2017
f0337c3
Add macro for PestParser rules
Victor-Savu Oct 9, 2017
b934c5a
Use `match` in the state parsing macro syntax
Victor-Savu Oct 12, 2017
4b1101d
Remove `pest_meta` dependency on `quote`
Victor-Savu Oct 15, 2017
7387dde
Add use-case for `pest_meta` as a syntax colorizer
Victor-Savu Oct 22, 2017
49e39e0
Remove redundant example section in Cargo.toml
Victor-Savu Oct 29, 2017
7c44ad9
Put spaces inside braces in all the unsafe places
Victor-Savu Oct 29, 2017
076898c
Merge branch 'master' into feature/meta
Victor-Savu Jan 27, 2018
8729712
Merge branch 'master' into feature/meta
Victor-Savu Jan 27, 2018
1f471b2
Qualify grammar errors
Victor-Savu Jan 27, 2018
a390796
Fix expected value of `missing_rhs` test
Victor-Savu Jan 27, 2018
f87b084
Bootstrap the parser using an older `pest_derive`
Victor-Savu Jan 27, 2018
4a07821
Bootstrap pest parser using pest_derive v1.0.3
Victor-Savu Feb 3, 2018
dae7e88
Reference strings, idents and ranges in the AST nodes
Victor-Savu Feb 3, 2018
4d7fe48
Change pest_meta licence to MIT/Appache-2.0
Victor-Savu Feb 3, 2018
4d0448b
Format according to review
Victor-Savu Feb 3, 2018
33195d7
Fix failing tests
Victor-Savu Feb 3, 2018
03515ab
Merge branch 'master' into feature/meta
Victor-Savu Feb 10, 2018
55f0098
Revert "Reference strings, idents and ranges in the AST nodes"
Victor-Savu Feb 12, 2018
2057588
Merge branch 'master' into feature/meta
dragostis Feb 18, 2018
95c5e5f
Removed meta example, for now.
dragostis Feb 18, 2018
333c9d8
Improved formatting.
dragostis Feb 18, 2018
9b044a5
Renames grammar file.
dragostis Feb 18, 2018
c5e533a
Added pest_meta to projects.
dragostis Feb 18, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
members = [
"pest",
"pest_derive",
"pest_grammars"
"pest_grammars",
"pest_meta"
]
1 change: 1 addition & 0 deletions pest_derive/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ proc-macro = true
quote = "^0.3"
syn = "^0.10"
pest = { path = "../pest", version = "^1.0.0-beta" }
pest_meta = { path = "../pest_meta", version = "^1.0.0-beta" }

[badges]
travis-ci = { repository = "pest-parser/pest" }
38 changes: 20 additions & 18 deletions pest_derive/src/generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ use std::collections::HashMap;

use quote::{Ident, Tokens};

use super::ast::*;
use super::ast::{Rule, RuleType, Expr};

pub fn generate(name: Ident, rules: Vec<Rule>, defaults: Vec<Ident>) -> Tokens {
pub fn generate(name: Ident, rules: Vec<Rule>, defaults: Vec<String>) -> Tokens {
let mut predefined = HashMap::new();
predefined.insert("any", quote! {
fn any<I: ::pest::inputs::Input>(
Expand Down Expand Up @@ -70,7 +70,7 @@ pub fn generate(name: Ident, rules: Vec<Rule>, defaults: Vec<Ident>) -> Tokens {
let skip = generate_skip(&rules);

let mut rules: Vec<_> = rules.into_iter().map(|rule| generate_rule(rule)).collect();
rules.extend(defaults.into_iter().map(|name| predefined.get(name.as_ref()).unwrap().clone()));
rules.extend(defaults.iter().map(|name| predefined.get(name.as_str()).unwrap().clone()));


let parser_impl = quote! {
Expand Down Expand Up @@ -102,7 +102,7 @@ pub fn generate(name: Ident, rules: Vec<Rule>, defaults: Vec<Ident>) -> Tokens {
}

fn generate_enum(rules: &Vec<Rule>) -> Tokens {
let rules = rules.iter().map(|rule| &rule.name);
let rules = rules.iter().map(|rule| Ident::new(rule.name.as_str()));

quote! {
#[allow(dead_code, non_camel_case_types)]
Expand All @@ -117,7 +117,7 @@ fn generate_patterns(rules: &Vec<Rule>) -> Tokens {
let mut tokens = Tokens::new();

let rules = rules.iter().map(|rule| {
let rule = &rule.name;
let rule = Ident::new(rule.name.as_str());
quote! {
Rule::#rule => rules::#rule(pos, &mut state)
}
Expand All @@ -129,7 +129,7 @@ fn generate_patterns(rules: &Vec<Rule>) -> Tokens {
}

fn generate_rule(rule: Rule) -> Tokens {
let name = rule.name;
let name = Ident::new(rule.name.as_str());
let expr = if {
rule.ty == RuleType::Atomic ||
rule.ty == RuleType::CompoundAtomic ||
Expand Down Expand Up @@ -205,8 +205,8 @@ fn generate_rule(rule: Rule) -> Tokens {
}

fn generate_skip(rules: &Vec<Rule>) -> Tokens {
let whitespace = rules.iter().any(|rule| rule.name.as_ref() == "whitespace");
let comment = rules.iter().any(|rule| rule.name.as_ref() == "comment");
let whitespace = rules.iter().any(|rule| rule.name.as_str() == "whitespace");
let comment = rules.iter().any(|rule| rule.name.as_str() == "comment");

match (whitespace, comment) {
(false, false) => quote! {
Expand Down Expand Up @@ -327,8 +327,9 @@ fn generate_expr(expr: Expr) -> Tokens {

tokens
},
Expr::Ident(ident) => quote! {
self::#ident(pos, state)
Expr::Ident(ident) => {
let ident = Ident::new(ident.as_str());
quote! { self::#ident(pos, state) }
},
Expr::PosPred(expr) => {
let expr = generate_expr(*expr);
Expand Down Expand Up @@ -502,8 +503,9 @@ fn generate_expr_atomic(expr: Expr) -> Tokens {

tokens
},
Expr::Ident(ident) => quote! {
self::#ident(pos, state)
Expr::Ident(ident) => {
let ident = Ident::new(ident.as_str());
quote! { self::#ident(pos, state) }
},
Expr::PosPred(expr) => {
let expr = generate_expr_atomic(*expr);
Expand Down Expand Up @@ -632,9 +634,9 @@ mod tests {
fn rule_enum_simple() {
let rules = vec![
Rule {
name: Ident::new("f"),
name: "f".to_owned(),
ty: RuleType::Normal,
expr: Expr::Ident(Ident::new("g"))
expr: Expr::Ident("g".to_owned())
}
];

Expand Down Expand Up @@ -759,7 +761,7 @@ mod tests {
#[test]
fn expr_complex() {
let expr = Expr::Choice(
Box::new(Expr::Ident(Ident::new("a"))),
Box::new(Expr::Ident("a".to_owned())),
Box::new(Expr::Seq(
Box::new(Expr::Range("'a'".to_owned(), "'b'".to_owned())),
Box::new(Expr::Seq(
Expand Down Expand Up @@ -854,7 +856,7 @@ mod tests {
#[test]
fn expr_complex_atomic() {
let expr = Expr::Choice(
Box::new(Expr::Ident(Ident::new("a"))),
Box::new(Expr::Ident("a".to_owned())),
Box::new(Expr::Seq(
Box::new(Expr::Range("'a'".to_owned(), "'b'".to_owned())),
Box::new(Expr::Seq(
Expand Down Expand Up @@ -912,11 +914,11 @@ mod tests {
fn generate_complete() {
let name = Ident::new("MyParser");
let rules = vec![Rule {
name: Ident::new("a"),
name: "a".to_owned(),
ty: RuleType::Silent,
expr: Expr::Str("b".to_owned())
}];
let defaults = vec![Ident::new("any")];
let defaults = vec!["any".to_owned()];

assert_eq!(generate(name, rules, defaults), quote! {
#[allow(dead_code, non_camel_case_types)]
Expand Down
66 changes: 36 additions & 30 deletions pest_derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,14 +226,15 @@
#![doc(html_root_url = "https://docs.rs/pest_derive")]
#![recursion_limit="256"]

#[macro_use]
extern crate pest;
extern crate pest_meta;
extern crate proc_macro;
#[macro_use]
extern crate quote;
extern crate syn;

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

Expand All @@ -243,13 +244,11 @@ use proc_macro::TokenStream;
use quote::Ident;
use syn::{Attribute, Lit, MetaItem};

mod ast;
mod generator;
mod optimizer;
mod parser;
mod validator;

use parser::{GrammarParser, GrammarRule};
use pest_meta::parser::{self, PestParser, PestRule};
use pest_meta::{ast, validator};

#[proc_macro_derive(Parser, attributes(grammar))]
pub fn derive_parser(input: TokenStream) -> TokenStream {
Expand All @@ -268,39 +267,46 @@ pub fn derive_parser(input: TokenStream) -> TokenStream {
Ok(input) => Rc::new(input),
Err(error) => panic!("error opening {:?}: {}", file_name, error)
};
let pairs = match GrammarParser::parse(GrammarRule::grammar_rules, input) {
let pairs = match PestParser::parse(PestRule::grammar_rules, input) {
Ok(pairs) => pairs,
Err(error) => panic!("error parsing {:?}\n\n{}", file_name, error.renamed_rules(|rule| {
match *rule {
GrammarRule::grammar_rule => "rule".to_owned(),
GrammarRule::eoi => "end-of-input".to_owned(),
GrammarRule::assignment_operator => "`=`".to_owned(),
GrammarRule::silent_modifier => "`_`".to_owned(),
GrammarRule::atomic_modifier => "`@`".to_owned(),
GrammarRule::compound_atomic_modifier => "`$`".to_owned(),
GrammarRule::non_atomic_modifier => "`!`".to_owned(),
GrammarRule::opening_brace => "`{`".to_owned(),
GrammarRule::closing_brace => "`}`".to_owned(),
GrammarRule::opening_paren => "`(`".to_owned(),
GrammarRule::positive_predicate_operator => "`&`".to_owned(),
GrammarRule::negative_predicate_operator => "`!`".to_owned(),
GrammarRule::sequence_operator => "`&`".to_owned(),
GrammarRule::choice_operator => "`|`".to_owned(),
GrammarRule::optional_operator => "`?`".to_owned(),
GrammarRule::repeat_operator => "`*`".to_owned(),
GrammarRule::repeat_once_operator => "`+`".to_owned(),
GrammarRule::comma => "`,`".to_owned(),
GrammarRule::closing_paren => "`)`".to_owned(),
GrammarRule::quote => "`\"`".to_owned(),
GrammarRule::insensitive_string => "`^`".to_owned(),
GrammarRule::range_operator => "`..`".to_owned(),
GrammarRule::single_quote => "`'`".to_owned(),
PestRule::grammar_rule => "rule".to_owned(),
PestRule::assignment_operator => "`=`".to_owned(),
PestRule::silent_modifier => "`_`".to_owned(),
PestRule::atomic_modifier => "`@`".to_owned(),
PestRule::compound_atomic_modifier => "`$`".to_owned(),
PestRule::non_atomic_modifier => "`!`".to_owned(),
PestRule::opening_brace => "`{`".to_owned(),
PestRule::closing_brace => "`}`".to_owned(),
PestRule::opening_paren => "`(`".to_owned(),
PestRule::positive_predicate_operator => "`&`".to_owned(),
PestRule::negative_predicate_operator => "`!`".to_owned(),
PestRule::sequence_operator => "`&`".to_owned(),
PestRule::choice_operator => "`|`".to_owned(),
PestRule::optional_operator => "`?`".to_owned(),
PestRule::repeat_operator => "`*`".to_owned(),
PestRule::repeat_once_operator => "`+`".to_owned(),
PestRule::comma => "`,`".to_owned(),
PestRule::closing_paren => "`)`".to_owned(),
PestRule::quote => "`\"`".to_owned(),
PestRule::insensitive_string => "`^`".to_owned(),
PestRule::range_operator => "`..`".to_owned(),
PestRule::single_quote => "`'`".to_owned(),
other_rule => format!("{:?}", other_rule)
}
}))
};

let (ast, defaults) = parser::consume_rules(pairs);
fn format_errors<Errors: IntoIterator>(errors: Errors) -> String where Errors::Item: Display {
errors.into_iter()
.map(|error| { format!("{}", error) })
.collect::<Vec<_>>()
.join("\n\n")
}

let defaults = validator::validate_pairs(pairs.clone()).unwrap_or_else(|e| panic!(format_errors(e)));
let ast = parser::consume_rules(pairs).unwrap_or_else(|e| panic!(format_errors(e)));
let optimized = optimizer::optimize(ast);
let generated = generator::generate(name, optimized, defaults);

Expand Down
34 changes: 16 additions & 18 deletions pest_derive/src/optimizer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,13 +139,11 @@ pub fn optimize(rules: Vec<Rule>) -> Vec<Rule> {
mod tests {
use super::*;

use quote::Ident;

#[test]
fn concat_strings() {
let rules = vec![
Rule {
name: Ident::new("rule"),
name: "rule".to_owned(),
ty: RuleType::Atomic,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Space here is not needed per rustfmt.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I run rustfmt on this file, I get a bunch of changes (many not related to the changes I made) Should I just go ahead and use rustfmt, or should I just remove these spaces? I am using rustfmt 0.8.0

expr: Expr::Seq(
Box::new(Expr::Seq(
Expand All @@ -161,7 +159,7 @@ mod tests {
];
let concatenated = vec![
Rule {
name: Ident::new("rule"),
name: "rule".to_owned(),
ty: RuleType::Atomic,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here.

expr: Expr::Str("abcd".to_owned())
}
Expand All @@ -174,7 +172,7 @@ mod tests {
fn concat_insensitive_strings() {
let rules = vec![
Rule {
name: Ident::new("rule"),
name: "rule".to_owned(),
ty: RuleType::Atomic,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Space.

expr: Expr::Seq(
Box::new(Expr::Seq(
Expand All @@ -190,7 +188,7 @@ mod tests {
];
let concatenated = vec![
Rule {
name: Ident::new("rule"),
name: "rule".to_owned(),
ty: RuleType::Atomic,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Space.

expr: Expr::Insens("abcd".to_owned())
}
Expand All @@ -203,37 +201,37 @@ mod tests {
fn long_common_sequence() {
let rules = vec![
Rule {
name: Ident::new("rule"),
name: "rule".to_owned(),
ty: RuleType::Silent,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Space.

expr: Expr::Choice(
Box::new(Expr::Seq(
Box::new(Expr::Ident(Ident::new("a"))),
Box::new(Expr::Ident("a".to_owned())),
Box::new(Expr::Seq(
Box::new(Expr::Ident(Ident::new("b"))),
Box::new(Expr::Ident(Ident::new("c")))
Box::new(Expr::Ident("b".to_owned())),
Box::new(Expr::Ident("c".to_owned()))
))
)),
Box::new(Expr::Seq(
Box::new(Expr::Seq(
Box::new(Expr::Ident(Ident::new("a"))),
Box::new(Expr::Ident(Ident::new("b")))
Box::new(Expr::Ident("a".to_owned())),
Box::new(Expr::Ident("b".to_owned()))
)),
Box::new(Expr::Ident(Ident::new("d")))
Box::new(Expr::Ident("d".to_owned()))
))
)
}
];
let optimized = vec![
Rule {
name: Ident::new("rule"),
name: "rule".to_owned(),
ty: RuleType::Silent,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Space.

expr: Expr::Seq(
Box::new(Expr::Ident(Ident::new("a"))),
Box::new(Expr::Ident("a".to_owned())),
Box::new(Expr::Seq(
Box::new(Expr::Ident(Ident::new("b"))),
Box::new(Expr::Ident("b".to_owned())),
Box::new(Expr::Choice(
Box::new(Expr::Ident(Ident::new("c"))),
Box::new(Expr::Ident(Ident::new("d")))
Box::new(Expr::Ident("c".to_owned())),
Box::new(Expr::Ident("d".to_owned()))
))
))
)
Expand Down
Loading