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
Changes from all commits
Commits
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
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
@@ -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" }

@@ -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
@@ -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 {
2 changes: 2 additions & 0 deletions benches/json.rs
Original file line number Diff line number Diff line change
@@ -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 {
3 changes: 3 additions & 0 deletions peg-macros/Cargo.toml
Original file line number Diff line number Diff line change
@@ -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
4 changes: 4 additions & 0 deletions peg-macros/bin.rs
Original file line number Diff line number Diff line change
@@ -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;
6 changes: 3 additions & 3 deletions peg-macros/grammar.rs
Original file line number Diff line number Diff line change
@@ -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(),
}
}
@@ -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();
2 changes: 2 additions & 0 deletions peg-macros/lib.rs
Original file line number Diff line number Diff line change
@@ -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.
77 changes: 66 additions & 11 deletions peg-macros/translate.rs
Original file line number Diff line number Diff line change
@@ -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);)
}
@@ -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()),*
}
}
}
}
}
@@ -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));
5 changes: 4 additions & 1 deletion peg-runtime/Cargo.toml
Original file line number Diff line number Diff line change
@@ -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 {
@@ -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 {}",
@@ -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"
@@ -88,7 +92,7 @@ impl ErrorState {
suppress_fail: 0,
reparsing_on_error: false,
expected: ExpectedSet {
expected: HashSet::new(),
expected: BTreeSet::new(),
},
}
}
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;
@@ -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
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)]
@@ -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)
}
}
Loading