Skip to content

Commit 8487e8d

Browse files
authored
Merge pull request #19 from theduke/borrowed-ast
Generic AST
2 parents 88ecf9a + 267fa43 commit 8487e8d

15 files changed

+680
-460
lines changed

benches/graphql.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,29 +19,29 @@ fn load_file(name: &str) -> String {
1919
#[bench]
2020
fn bench_minimal(b: &mut test::Bencher) {
2121
let f = load_file("minimal");
22-
b.iter(|| parse_query(&f).unwrap());
22+
b.iter(|| parse_query::<String>(&f).unwrap());
2323
}
2424

2525
#[bench]
2626
fn bench_inline_fragment(b: &mut test::Bencher) {
2727
let f = load_file("inline_fragment");
28-
b.iter(|| parse_query(&f).unwrap());
28+
b.iter(|| parse_query::<String>(&f).unwrap());
2929
}
3030

3131
#[bench]
3232
fn bench_directive_args(b: &mut test::Bencher) {
3333
let f = load_file("directive_args");
34-
b.iter(|| parse_query(&f).unwrap());
34+
b.iter(|| parse_query::<String>(&f).unwrap());
3535
}
3636

3737
#[bench]
3838
fn bench_query_vars(b: &mut test::Bencher) {
3939
let f = load_file("query_vars");
40-
b.iter(|| parse_query(&f).unwrap());
40+
b.iter(|| parse_query::<String>(&f).unwrap());
4141
}
4242

4343
#[bench]
4444
fn bench_kitchen_sink(b: &mut test::Bencher) {
4545
let f = load_file("kitchen-sink");
46-
b.iter(|| parse_query(&f).unwrap());
46+
b.iter(|| parse_query::<String>(&f).unwrap());
4747
}

src/common.rs

Lines changed: 69 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::collections::BTreeMap;
1+
use std::{fmt, collections::BTreeMap};
22

33
use combine::{parser, ParseResult, Parser};
44
use combine::easy::Error;
@@ -9,15 +9,29 @@ use tokenizer::{Kind as T, Token, TokenStream};
99
use helpers::{punct, ident, kind, name};
1010
use position::Pos;
1111

12+
/// Text abstracts over types that hold a string value.
13+
/// It is used to make the AST generic over the string type.
14+
pub trait Text<'a>: 'a {
15+
type Value: 'a + From<&'a str> + AsRef<str> + std::borrow::Borrow<str> + PartialEq + Eq + PartialOrd + Ord + fmt::Debug + Clone;
16+
}
17+
18+
impl<'a> Text<'a> for &'a str {
19+
type Value = Self;
20+
}
1221

13-
/// An alias for string, used where graphql expects a name
14-
pub type Name = String;
22+
impl<'a> Text<'a> for String {
23+
type Value = String;
24+
}
25+
26+
impl<'a> Text<'a> for std::borrow::Cow<'a, str> {
27+
type Value = Self;
28+
}
1529

1630
#[derive(Debug, Clone, PartialEq)]
17-
pub struct Directive {
31+
pub struct Directive<'a, T: Text<'a>> {
1832
pub position: Pos,
19-
pub name: Name,
20-
pub arguments: Vec<(Name, Value)>,
33+
pub name: T::Value,
34+
pub arguments: Vec<(T::Value, Value<'a, T>)>,
2135
}
2236

2337
/// This represents integer number
@@ -32,23 +46,23 @@ pub struct Directive {
3246
pub struct Number(pub(crate) i64);
3347

3448
#[derive(Debug, Clone, PartialEq)]
35-
pub enum Value {
36-
Variable(Name),
49+
pub enum Value<'a, T: Text<'a>> {
50+
Variable(T::Value),
3751
Int(Number),
3852
Float(f64),
3953
String(String),
4054
Boolean(bool),
4155
Null,
42-
Enum(Name),
43-
List(Vec<Value>),
44-
Object(BTreeMap<Name, Value>),
56+
Enum(T::Value),
57+
List(Vec<Value<'a, T>>),
58+
Object(BTreeMap<T::Value, Value<'a, T>>),
4559
}
4660

4761
#[derive(Debug, Clone, PartialEq)]
48-
pub enum Type {
49-
NamedType(Name),
50-
ListType(Box<Type>),
51-
NonNullType(Box<Type>),
62+
pub enum Type<'a, T: Text<'a>> {
63+
NamedType(T::Value),
64+
ListType(Box<Type<'a, T>>),
65+
NonNullType(Box<Type<'a, T>>),
5266
}
5367

5468
impl Number {
@@ -64,25 +78,27 @@ impl From<i32> for Number {
6478
}
6579
}
6680

67-
pub fn directives<'a>(input: &mut TokenStream<'a>)
68-
-> ParseResult<Vec<Directive>, TokenStream<'a>>
81+
pub fn directives<'a, T>(input: &mut TokenStream<'a>)
82+
-> ParseResult<Vec<Directive<'a, T>>, TokenStream<'a>>
83+
where T: Text<'a>,
6984
{
7085
many(position()
7186
.skip(punct("@"))
72-
.and(name())
87+
.and(name::<'a, T>())
7388
.and(parser(arguments))
7489
.map(|((position, name), arguments)| {
7590
Directive { position, name, arguments }
7691
}))
7792
.parse_stream(input)
7893
}
7994

80-
pub fn arguments<'a>(input: &mut TokenStream<'a>)
81-
-> ParseResult<Vec<(String, Value)>, TokenStream<'a>>
95+
pub fn arguments<'a, T>(input: &mut TokenStream<'a>)
96+
-> ParseResult<Vec<(T::Value, Value<'a, T>)>, TokenStream<'a>>
97+
where T: Text<'a>,
8298
{
8399
optional(
84100
punct("(")
85-
.with(many1(name()
101+
.with(many1(name::<'a, T>()
86102
.skip(punct(":"))
87103
.and(parser(value))))
88104
.skip(punct(")")))
@@ -92,23 +108,25 @@ pub fn arguments<'a>(input: &mut TokenStream<'a>)
92108
.parse_stream(input)
93109
}
94110

95-
pub fn int_value<'a>(input: &mut TokenStream<'a>)
96-
-> ParseResult<Value, TokenStream<'a>>
111+
pub fn int_value<'a, S>(input: &mut TokenStream<'a>)
112+
-> ParseResult<Value<'a, S>, TokenStream<'a>>
113+
where S: Text<'a>
97114
{
98115
kind(T::IntValue).and_then(|tok| tok.value.parse())
99116
.map(Number).map(Value::Int)
100117
.parse_stream(input)
101118
}
102119

103-
pub fn float_value<'a>(input: &mut TokenStream<'a>)
104-
-> ParseResult<Value, TokenStream<'a>>
120+
pub fn float_value<'a, S>(input: &mut TokenStream<'a>)
121+
-> ParseResult<Value<'a, S>, TokenStream<'a>>
122+
where S: Text<'a>
105123
{
106124
kind(T::FloatValue).and_then(|tok| tok.value.parse())
107125
.map(Value::Float)
108126
.parse_stream(input)
109127
}
110128

111-
fn unquote_block_string(src: &str) -> Result<String, Error<Token, Token>> {
129+
fn unquote_block_string<'a>(src: &'a str) -> Result<String, Error<Token<'a>, Token<'a>>> {
112130
debug_assert!(src.starts_with("\"\"\"") && src.ends_with("\"\"\""));
113131
let indent = src[3..src.len()-3].lines().skip(1)
114132
.filter_map(|line| {
@@ -144,7 +162,8 @@ fn unquote_block_string(src: &str) -> Result<String, Error<Token, Token>> {
144162
Ok(result)
145163
}
146164

147-
fn unquote_string(s: &str) -> Result<String, Error<Token, Token>> {
165+
fn unquote_string<'a>(s: &'a str) -> Result<String, Error<Token, Token>>
166+
{
148167
let mut res = String::with_capacity(s.len());
149168
debug_assert!(s.starts_with('"') && s.ends_with('"'));
150169
let mut chars = s[1..s.len()-1].chars();
@@ -201,67 +220,73 @@ pub fn string<'a>(input: &mut TokenStream<'a>)
201220
)).parse_stream(input)
202221
}
203222

204-
pub fn string_value<'a>(input: &mut TokenStream<'a>)
205-
-> ParseResult<Value, TokenStream<'a>>
223+
pub fn string_value<'a, S>(input: &mut TokenStream<'a>)
224+
-> ParseResult<Value<'a, S>, TokenStream<'a>>
225+
where S: Text<'a>,
206226
{
207227
kind(T::StringValue).and_then(|tok| unquote_string(tok.value))
208228
.map(Value::String)
209229
.parse_stream(input)
210230
}
211231

212-
pub fn block_string_value<'a>(input: &mut TokenStream<'a>)
213-
-> ParseResult<Value, TokenStream<'a>>
232+
pub fn block_string_value<'a, S>(input: &mut TokenStream<'a>)
233+
-> ParseResult<Value<'a, S>, TokenStream<'a>>
234+
where S: Text<'a>,
214235
{
215236
kind(T::BlockString).and_then(|tok| unquote_block_string(tok.value))
216237
.map(Value::String)
217238
.parse_stream(input)
218239
}
219240

220-
pub fn plain_value<'a>(input: &mut TokenStream<'a>)
221-
-> ParseResult<Value, TokenStream<'a>>
241+
pub fn plain_value<'a, T>(input: &mut TokenStream<'a>)
242+
-> ParseResult<Value<'a, T>, TokenStream<'a>>
243+
where T: Text<'a>,
222244
{
223245
ident("true").map(|_| Value::Boolean(true))
224246
.or(ident("false").map(|_| Value::Boolean(false)))
225247
.or(ident("null").map(|_| Value::Null))
226-
.or(name().map(Value::Enum))
248+
.or(name::<'a, T>().map(Value::Enum))
227249
.or(parser(int_value))
228250
.or(parser(float_value))
229251
.or(parser(string_value))
230252
.or(parser(block_string_value))
231253
.parse_stream(input)
232254
}
233255

234-
pub fn value<'a>(input: &mut TokenStream<'a>)
235-
-> ParseResult<Value, TokenStream<'a>>
256+
pub fn value<'a, T>(input: &mut TokenStream<'a>)
257+
-> ParseResult<Value<'a, T>, TokenStream<'a>>
258+
where T: Text<'a>,
236259
{
237260
parser(plain_value)
238-
.or(punct("$").with(name()).map(Value::Variable))
261+
.or(punct("$").with(name::<'a, T>()).map(Value::Variable))
239262
.or(punct("[").with(many(parser(value))).skip(punct("]"))
240263
.map(Value::List))
241264
.or(punct("{")
242-
.with(many(name().skip(punct(":")).and(parser(value))))
265+
.with(many(name::<'a, T>().skip(punct(":")).and(parser(value))))
243266
.skip(punct("}"))
244267
.map(Value::Object))
245268
.parse_stream(input)
246269
}
247270

248-
pub fn default_value<'a>(input: &mut TokenStream<'a>)
249-
-> ParseResult<Value, TokenStream<'a>>
271+
pub fn default_value<'a, T>(input: &mut TokenStream<'a>)
272+
-> ParseResult<Value<'a, T>, TokenStream<'a>>
273+
where T: Text<'a>,
250274
{
251275
parser(plain_value)
252276
.or(punct("[").with(many(parser(default_value))).skip(punct("]"))
253277
.map(Value::List))
254278
.or(punct("{")
255-
.with(many(name().skip(punct(":")).and(parser(default_value))))
279+
.with(many(name::<'a, T>().skip(punct(":")).and(parser(default_value))))
256280
.skip(punct("}"))
257281
.map(Value::Object))
258282
.parse_stream(input)
259283
}
260284

261-
pub fn parse_type<'a>(input: &mut TokenStream<'a>)
262-
-> ParseResult<Type, TokenStream<'a>>
285+
pub fn parse_type<'a, T>(input: &mut TokenStream<'a>)
286+
-> ParseResult<Type<'a, T>, TokenStream<'a>>
287+
where T: Text<'a>,
263288
{
264-
name().map(Type::NamedType)
289+
name::<'a, T>().map(Type::NamedType)
265290
.or(punct("[")
266291
.with(parser(parse_type))
267292
.skip(punct("]"))

src/format.rs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ impl<'a> Formatter<'a> {
9393
for c in s.chars() {
9494
match c {
9595
'\n' => has_newline = true,
96-
'\r' | '\t' | '\u{0020}'...'\u{FFFF}' => {}
96+
'\r' | '\t' | '\u{0020}'..='\u{FFFF}' => {}
9797
_ => has_nonprintable = true,
9898
}
9999
}
@@ -107,7 +107,7 @@ impl<'a> Formatter<'a> {
107107
'\t' => self.write(r"\t"),
108108
'"' => self.write("\\\""),
109109
'\\' => self.write(r"\\"),
110-
'\u{0020}'...'\u{FFFF}' => self.buf.push(c),
110+
'\u{0020}'..='\u{FFFF}' => self.buf.push(c),
111111
_ => write!(&mut self.buf, "\\u{:04}", c as u32).unwrap(),
112112
}
113113
}
@@ -130,7 +130,9 @@ impl<'a> Formatter<'a> {
130130
}
131131
}
132132

133-
pub(crate) fn format_directives(dirs: &[Directive], f: &mut Formatter) {
133+
pub(crate) fn format_directives<'a, T>(dirs: &[Directive<'a, T>], f: &mut Formatter)
134+
where T: ::common::Text<'a>,
135+
{
134136
for dir in dirs {
135137
f.write(" ");
136138
dir.display(f);
@@ -147,4 +149,16 @@ macro_rules! impl_display {
147149
}
148150
)+
149151
};
152+
153+
('a $($typ: ident, )+) => {
154+
$(
155+
impl<'a, T> fmt::Display for $typ<'a, T>
156+
where T: Text<'a>,
157+
{
158+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
159+
f.write_str(&to_string(self))
160+
}
161+
}
162+
)+
163+
};
150164
}

src/helpers.rs

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ use combine::stream::easy::{Error, Errors, Info};
77
use tokenizer::{TokenStream, Kind, Token};
88
use position::Pos;
99

10+
use super::common::{Text};
11+
1012

1113
#[derive(Debug, Clone)]
1214
pub struct TokenMatch<'a> {
@@ -15,8 +17,10 @@ pub struct TokenMatch<'a> {
1517
}
1618

1719
#[derive(Debug, Clone)]
18-
pub struct NameMatch<'a> {
19-
phantom: PhantomData<&'a u8>,
20+
pub struct NameMatch<'a, T>
21+
where T: Text<'a>
22+
{
23+
phantom: PhantomData<(&'a T)>,
2024
}
2125

2226
#[derive(Debug, Clone)]
@@ -34,7 +38,9 @@ pub fn kind<'x>(kind: Kind) -> TokenMatch<'x> {
3438
}
3539
}
3640

37-
pub fn name<'x>() -> NameMatch<'x> {
41+
pub fn name<'a, T>() -> NameMatch<'a, T>
42+
where T: Text<'a>
43+
{
3844
NameMatch {
3945
phantom: PhantomData,
4046
}
@@ -60,15 +66,15 @@ impl<'a> Parser for TokenMatch<'a> {
6066
}
6167
}
6268

63-
pub fn punct<'x>(value: &'static str) -> Value<'x> {
69+
pub fn punct<'s>(value: &'static str) -> Value<'s> {
6470
Value {
6571
kind: Kind::Punctuator,
6672
value: value,
6773
phantom: PhantomData,
6874
}
6975
}
7076

71-
pub fn ident<'x>(value: &'static str) -> Value<'x> {
77+
pub fn ident<'s>(value: &'static str) -> Value<'s> {
7278
Value {
7379
kind: Kind::Name,
7480
value: value,
@@ -97,17 +103,19 @@ impl<'a> Parser for Value<'a> {
97103
}
98104
}
99105

100-
impl<'a> Parser for NameMatch<'a> {
106+
impl<'a, S> Parser for NameMatch<'a, S>
107+
where S: Text<'a>,
108+
{
101109
type Input = TokenStream<'a>;
102-
type Output = String;
110+
type Output = S::Value;
103111
type PartialState = ();
104112

105113
#[inline]
106114
fn parse_lazy(&mut self, input: &mut Self::Input)
107115
-> ConsumedResult<Self::Output, Self::Input>
108116
{
109117
satisfy(|c: Token<'a>| c.kind == Kind::Name)
110-
.map(|t: Token<'a>| t.value.to_string())
118+
.map(|t: Token<'a>| -> S::Value { S::Value::from(t.value) } )
111119
.parse_lazy(input)
112120
}
113121

0 commit comments

Comments
 (0)