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

Add no_std support #294

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
63 changes: 63 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ readme = "README.md"
edition = "2018"

[dependencies]
hashbrown = { version = "0.12.0", optional = true }
peg-macros = { path = "./peg-macros", version = "= 0.8.1" }
peg-runtime = { path = "./peg-runtime", version = "= 0.8.1" }

Expand All @@ -26,4 +27,6 @@ path = "tests/trybuild.rs"
harness = false

[features]
default = ["std"]
trace = ["peg-macros/trace"]
std = ["peg-macros/std", "peg-runtime/std"]
2 changes: 2 additions & 0 deletions benches/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ extern crate peg;

extern crate test;

#[cfg(not(feature = "std"))] #[macro_use] extern crate alloc;

use test::Bencher;

peg::parser!(grammar parser() for str {
Expand Down
2 changes: 2 additions & 0 deletions benches/json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ extern crate peg;

extern crate test;

#[cfg(not(feature = "std"))] #[macro_use] extern crate alloc;

use test::Bencher;

peg::parser!(grammar parser() for str {
Expand Down
3 changes: 3 additions & 0 deletions peg-macros/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,12 @@ edition = "2018"
quote = "1.0"
proc-macro2 = "1.0.24"
peg-runtime = { version = "= 0.8.1", path = "../peg-runtime" }
cfg-if = "1.0.0"

[features]
std = ["peg-runtime/std"]
trace = []
hashbrown = []

[lib]
proc-macro = true
Expand Down
4 changes: 4 additions & 0 deletions peg-macros/bin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ use std::process;
// requires `::peg` paths.
extern crate peg_runtime as peg;

#[cfg(not(feature = "std"))]
#[macro_use]
extern crate alloc;

mod analysis;
mod ast;
mod grammar;
Expand Down
6 changes: 3 additions & 3 deletions peg-macros/grammar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ pub mod peg {
type PositionRepr = <Input as ::peg::Parse>::PositionRepr;
#[allow(unused_parens)]
struct ParseState<'input> {
_phantom: ::std::marker::PhantomData<(&'input ())>,
_phantom: ::core::marker::PhantomData<(&'input ())>,
primary_cache: ::std::collections::HashMap<usize, ::peg::RuleResult<SpannedExpr>>,
}
impl<'input> ParseState<'input> {
fn new() -> ParseState<'input> {
ParseState {
_phantom: ::std::marker::PhantomData,
_phantom: ::core::marker::PhantomData,
primary_cache: ::std::collections::HashMap::new(),
}
}
Expand All @@ -23,7 +23,7 @@ pub mod peg {
use proc_macro2::{Delimiter, Group, Ident, Literal, Span, TokenStream};
pub fn peg_grammar<'input>(
__input: &'input Input,
) -> ::std::result::Result<Grammar, ::peg::error::ParseError<PositionRepr>> {
) -> ::core::result::Result<Grammar, ::peg::error::ParseError<PositionRepr>> {
#![allow(non_snake_case, unused)]
let mut __err_state = ::peg::error::ErrorState::new(::peg::Parse::start(__input));
let mut __state = ParseState::new();
Expand Down
2 changes: 2 additions & 0 deletions peg-macros/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ mod grammar;
mod tokens;
mod translate;

#[cfg(not(feature = "std"))] extern crate alloc;

/// The main macro for creating a PEG parser.
///
/// For the grammar syntax, see the `peg` crate documentation.
Expand Down
77 changes: 66 additions & 11 deletions peg-macros/translate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ pub use self::Expr::*;
use crate::analysis;
use crate::ast::*;

use cfg_if::cfg_if;

pub fn report_error(span: Span, msg: String) -> TokenStream {
quote_spanned!(span=>compile_error!(#msg);)
}
Expand Down Expand Up @@ -161,25 +163,78 @@ fn make_parse_state(grammar: &Grammar) -> TokenStream {
if rule.cache.is_some() && rule.params.is_empty() && rule.ty_params.is_none() {
let name = format_ident!("{}_cache", rule.name);
let ret_ty = rule.ret_type.clone().unwrap_or_else(|| quote!(()));
cache_fields_def.push(
quote_spanned! { span => #name: ::std::collections::HashMap<usize, ::peg::RuleResult<#ret_ty>> },
);

let span = {
cfg_if! {
if #[cfg(not(feature = "std"))] {
cfg_if! {
if #[cfg(feature = "hashbrown")] {
quote_spanned! { span => #name: ::hashbrown::HashMap<usize, ::peg::RuleResult<#ret_ty>> }
} else {
quote_spanned! { span => #name: ::alloc::collections::btree_map::BTreeMap<usize, ::peg::RuleResult<#ret_ty>> }
}
}
} else {
quote_spanned! { span => #name: ::std::collections::HashMap<usize, ::peg::RuleResult<#ret_ty>> }
}
}
};

cache_fields_def.push(span);
cache_fields.push(name);
}
}

quote_spanned! { span =>
let parse_state_struct = quote_spanned! { span =>
#[allow(unused_parens)]
struct ParseState<'input #(, #grammar_lifetime_params)*> {
_phantom: ::std::marker::PhantomData<(&'input () #(, &#grammar_lifetime_params ())*)>,
_phantom: ::core::marker::PhantomData<(&'input () #(, &#grammar_lifetime_params ())*)>,
#(#cache_fields_def),*
}
};

cfg_if! {
if #[cfg(not(feature = "std"))] {
cfg_if! {
if #[cfg(feature = "hashbrown")] {
quote_spanned! { span =>
#parse_state_struct

impl<'input #(, #grammar_lifetime_params)*> ParseState<'input #(, #grammar_lifetime_params)*> {
fn new() -> ParseState<'input #(, #grammar_lifetime_params)*> {
ParseState {
_phantom: ::std::marker::PhantomData,
#(#cache_fields: ::std::collections::HashMap::new()),*
impl<'input #(, #grammar_lifetime_params)*> ParseState<'input #(, #grammar_lifetime_params)*> {
fn new() -> ParseState<'input #(, #grammar_lifetime_params)*> {
ParseState {
_phantom: ::core::marker::PhantomData,
#(#cache_fields: ::hashbrown::HashMap::new()),*
}
}
}
}
} else {
quote_spanned! { span =>
#parse_state_struct

impl<'input #(, #grammar_lifetime_params)*> ParseState<'input #(, #grammar_lifetime_params)*> {
fn new() -> ParseState<'input #(, #grammar_lifetime_params)*> {
ParseState {
_phantom: ::core::marker::PhantomData,
#(#cache_fields: ::alloc::collections::btree_map::BTreeMap::new()),*
}
}
}
}
}
}
} else {
quote_spanned! { span =>
#parse_state_struct

impl<'input #(, #grammar_lifetime_params)*> ParseState<'input #(, #grammar_lifetime_params)*> {
fn new() -> ParseState<'input #(, #grammar_lifetime_params)*> {
ParseState {
_phantom: ::core::marker::PhantomData,
#(#cache_fields: ::std::collections::HashMap::new()),*
}
}
}
}
}
Expand Down Expand Up @@ -369,7 +424,7 @@ fn compile_rule_export(context: &Context, rule: &Rule) -> TokenStream {

quote_spanned! { span =>
#doc
#visibility fn #name<'input #(, #grammar_lifetime_params)* #(, #ty_params)*>(__input: #input_ty #extra_args_def #(, #rule_params)*) -> ::std::result::Result<#ret_ty, ::peg::error::ParseError<PositionRepr<#(#grammar_lifetime_params),*>>> {
#visibility fn #name<'input #(, #grammar_lifetime_params)* #(, #ty_params)*>(__input: #input_ty #extra_args_def #(, #rule_params)*) -> ::core::result::Result<#ret_ty, ::peg::error::ParseError<PositionRepr<#(#grammar_lifetime_params),*>>> {
#![allow(non_snake_case, unused)]

let mut __err_state = ::peg::error::ErrorState::new(::peg::Parse::start(__input));
Expand Down
5 changes: 4 additions & 1 deletion peg-runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,7 @@ description = "Runtime support for rust-peg grammars. To use rust-peg, see the `
edition = "2018"

[lib]
path = "lib.rs"
path = "lib.rs"

[features]
std = []
14 changes: 9 additions & 5 deletions peg-runtime/error.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
//! Parse error reporting

use crate::{Parse, RuleResult};
use std::collections::HashSet;
use std::fmt::{self, Debug, Display};
use core::fmt::{self, Debug, Display};

#[cfg(not(feature = "std"))] use alloc::{collections::btree_set::BTreeSet, vec::Vec};
#[cfg(feature = "std")] use std::collections::BTreeSet;

/// A set of literals or names that failed to match
#[derive(PartialEq, Eq, Debug, Clone)]
pub struct ExpectedSet {
expected: HashSet<&'static str>,
expected: BTreeSet<&'static str>,
}

impl ExpectedSet {
Expand Down Expand Up @@ -49,7 +51,7 @@ pub struct ParseError<L> {
}

impl<L: Display> Display for ParseError<L> {
fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::result::Result<(), ::std::fmt::Error> {
fn fmt(&self, fmt: &mut ::core::fmt::Formatter) -> ::core::result::Result<(), ::core::fmt::Error> {
write!(
fmt,
"error at {}: expected {}",
Expand All @@ -58,6 +60,8 @@ impl<L: Display> Display for ParseError<L> {
}
}

// Unfortuantely, std::error::Error never made it into core::error
#[cfg(feature = "std")]
impl<L: Display + Debug> ::std::error::Error for ParseError<L> {
fn description(&self) -> &str {
"parse error"
Expand Down Expand Up @@ -88,7 +92,7 @@ impl ErrorState {
suppress_fail: 0,
reparsing_on_error: false,
expected: ExpectedSet {
expected: HashSet::new(),
expected: BTreeSet::new(),
},
}
}
Expand Down
8 changes: 6 additions & 2 deletions peg-runtime/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
use std::fmt::Display;
#![cfg_attr(not(feature = "std"), no_std)]

#[cfg(not(feature = "std"))] extern crate alloc;

use core::fmt::Display;

pub mod error;
mod slice;
Expand All @@ -7,7 +11,7 @@ pub mod str;
/// The result type used internally in the parser.
///
/// You'll only need this if implementing the `Parse*` traits for a custom input
/// type. The public API of a parser adapts errors to `std::result::Result`.
/// type. The public API of a parser adapts errors to `core::result::Result`.
#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
pub enum RuleResult<T> {
/// Success, with final location
Expand Down
4 changes: 2 additions & 2 deletions peg-runtime/str.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Utilities for `str` input

use super::{Parse, ParseElem, ParseLiteral, ParseSlice, RuleResult};
use std::fmt::Display;
use core::fmt::Display;

/// Line and column within a string
#[derive(PartialEq, Eq, Debug, Clone, Copy)]
Expand All @@ -17,7 +17,7 @@ pub struct LineCol {
}

impl Display for LineCol {
fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::result::Result<(), ::std::fmt::Error> {
fn fmt(&self, fmt: &mut ::core::fmt::Formatter) -> ::core::result::Result<(), ::core::fmt::Error> {
write!(fmt, "{}:{}", self.line, self.column)
}
}
Expand Down