use std::borrow::Cow;
use ast::{Arguments, Definition, Directive, Document, Field, Fragment, FragmentSpread,
InlineFragment, InputValue, Operation, OperationType, Selection, Type,
VariableDefinition, VariableDefinitions};
use parser::{Lexer, OptionParseResult, ParseError, ParseResult, Parser, Spanning, Token,
UnlocatedParseResult};
use parser::value::parse_value_literal;
#[doc(hidden)]
pub fn parse_document_source(s: &str) -> UnlocatedParseResult<Document> {
let mut lexer = Lexer::new(s);
let mut parser = try!(Parser::new(&mut lexer).map_err(|s| s.map(ParseError::LexerError)));
parse_document(&mut parser)
}
fn parse_document<'a>(parser: &mut Parser<'a>) -> UnlocatedParseResult<'a, Document<'a>> {
let mut defs = Vec::new();
loop {
defs.push(try!(parse_definition(parser)));
if parser.peek().item == Token::EndOfFile {
return Ok(defs);
}
}
}
fn parse_definition<'a>(parser: &mut Parser<'a>) -> UnlocatedParseResult<'a, Definition<'a>> {
match parser.peek().item {
Token::CurlyOpen | Token::Name("query") | Token::Name("mutation") => Ok(
Definition::Operation(try!(parse_operation_definition(parser))),
),
Token::Name("fragment") => Ok(Definition::Fragment(
try!(parse_fragment_definition(parser)),
)),
_ => Err(parser.next()?.map(ParseError::UnexpectedToken)),
}
}
fn parse_operation_definition<'a>(parser: &mut Parser<'a>) -> ParseResult<'a, Operation<'a>> {
if parser.peek().item == Token::CurlyOpen {
let selection_set = try!(parse_selection_set(parser));
Ok(Spanning::start_end(
&selection_set.start,
&selection_set.end,
Operation {
operation_type: OperationType::Query,
name: None,
variable_definitions: None,
directives: None,
selection_set: selection_set.item,
},
))
} else {
let start_pos = parser.peek().start.clone();
let operation_type = try!(parse_operation_type(parser));
let name = match parser.peek().item {
Token::Name(_) => Some(try!(parser.expect_name())),
_ => None,
};
let variable_definitions = try!(parse_variable_definitions(parser));
let directives = try!(parse_directives(parser));
let selection_set = try!(parse_selection_set(parser));
Ok(Spanning::start_end(
&start_pos,
&selection_set.end,
Operation {
operation_type: operation_type.item,
name: name,
variable_definitions: variable_definitions,
directives: directives.map(|s| s.item),
selection_set: selection_set.item,
},
))
}
}
fn parse_fragment_definition<'a>(parser: &mut Parser<'a>) -> ParseResult<'a, Fragment<'a>> {
let Spanning {
start: start_pos, ..
} = try!(parser.expect(&Token::Name("fragment")));
let name = match parser.expect_name() {
Ok(n) => if n.item == "on" {
return Err(n.map(|_| ParseError::UnexpectedToken(Token::Name("on"))));
} else {
n
},
Err(e) => return Err(e),
};
try!(parser.expect(&Token::Name("on")));
let type_cond = try!(parser.expect_name());
let directives = try!(parse_directives(parser));
let selection_set = try!(parse_selection_set(parser));
Ok(Spanning::start_end(
&start_pos,
&selection_set.end,
Fragment {
name: name,
type_condition: type_cond,
directives: directives.map(|s| s.item),
selection_set: selection_set.item,
},
))
}
fn parse_optional_selection_set<'a>(
parser: &mut Parser<'a>,
) -> OptionParseResult<'a, Vec<Selection<'a>>> {
if parser.peek().item == Token::CurlyOpen {
Ok(Some(try!(parse_selection_set(parser))))
} else {
Ok(None)
}
}
fn parse_selection_set<'a>(parser: &mut Parser<'a>) -> ParseResult<'a, Vec<Selection<'a>>> {
parser.unlocated_delimited_nonempty_list(&Token::CurlyOpen, parse_selection, &Token::CurlyClose)
}
fn parse_selection<'a>(parser: &mut Parser<'a>) -> UnlocatedParseResult<'a, Selection<'a>> {
match parser.peek().item {
Token::Ellipsis => parse_fragment(parser),
_ => parse_field(parser).map(Selection::Field),
}
}
fn parse_fragment<'a>(parser: &mut Parser<'a>) -> UnlocatedParseResult<'a, Selection<'a>> {
let Spanning {
start: ref start_pos,
..
} = try!(parser.expect(&Token::Ellipsis));
match parser.peek().item {
Token::Name("on") => {
parser.next()?;
let name = try!(parser.expect_name());
let directives = try!(parse_directives(parser));
let selection_set = try!(parse_selection_set(parser));
Ok(Selection::InlineFragment(Spanning::start_end(
&start_pos.clone(),
&selection_set.end,
InlineFragment {
type_condition: Some(name),
directives: directives.map(|s| s.item),
selection_set: selection_set.item,
},
)))
}
Token::CurlyOpen => {
let selection_set = try!(parse_selection_set(parser));
Ok(Selection::InlineFragment(Spanning::start_end(
&start_pos.clone(),
&selection_set.end,
InlineFragment {
type_condition: None,
directives: None,
selection_set: selection_set.item,
},
)))
}
Token::Name(_) => {
let frag_name = try!(parser.expect_name());
let directives = try!(parse_directives(parser));
Ok(Selection::FragmentSpread(Spanning::start_end(
&start_pos.clone(),
&directives
.as_ref()
.map_or(&frag_name.end, |s| &s.end)
.clone(),
FragmentSpread {
name: frag_name,
directives: directives.map(|s| s.item),
},
)))
}
Token::At => {
let directives = try!(parse_directives(parser));
let selection_set = try!(parse_selection_set(parser));
Ok(Selection::InlineFragment(Spanning::start_end(
&start_pos.clone(),
&selection_set.end,
InlineFragment {
type_condition: None,
directives: directives.map(|s| s.item),
selection_set: selection_set.item,
},
)))
}
_ => Err(parser.next()?.map(ParseError::UnexpectedToken)),
}
}
fn parse_field<'a>(parser: &mut Parser<'a>) -> ParseResult<'a, Field<'a>> {
let mut alias = Some(try!(parser.expect_name()));
let name = if try!(parser.skip(&Token::Colon)).is_some() {
try!(parser.expect_name())
} else {
alias.take().unwrap()
};
let arguments = try!(parse_arguments(parser));
let directives = try!(parse_directives(parser));
let selection_set = try!(parse_optional_selection_set(parser));
Ok(Spanning::start_end(
&alias.as_ref().unwrap_or(&name).start.clone(),
&selection_set
.as_ref()
.map(|s| &s.end)
.or_else(|| directives.as_ref().map(|s| &s.end))
.or_else(|| arguments.as_ref().map(|s| &s.end))
.unwrap_or(&name.end)
.clone(),
Field {
alias: alias,
name: name,
arguments: arguments,
directives: directives.map(|s| s.item),
selection_set: selection_set.map(|s| s.item),
},
))
}
fn parse_arguments<'a>(parser: &mut Parser<'a>) -> OptionParseResult<'a, Arguments<'a>> {
if parser.peek().item != Token::ParenOpen {
Ok(None)
} else {
Ok(Some(
try!(
parser
.delimited_nonempty_list(&Token::ParenOpen, parse_argument, &Token::ParenClose)
).map(|args| {
Arguments {
items: args.into_iter().map(|s| s.item).collect(),
}
}),
))
}
}
fn parse_argument<'a>(
parser: &mut Parser<'a>,
) -> ParseResult<'a, (Spanning<&'a str>, Spanning<InputValue>)> {
let name = try!(parser.expect_name());
try!(parser.expect(&Token::Colon));
let value = try!(parse_value_literal(parser, false));
Ok(Spanning::start_end(
&name.start.clone(),
&value.end.clone(),
(name, value),
))
}
fn parse_operation_type<'a>(parser: &mut Parser<'a>) -> ParseResult<'a, OperationType> {
match parser.peek().item {
Token::Name("query") => Ok(parser.next()?.map(|_| OperationType::Query)),
Token::Name("mutation") => Ok(parser.next()?.map(|_| OperationType::Mutation)),
_ => Err(parser.next()?.map(ParseError::UnexpectedToken)),
}
}
fn parse_variable_definitions<'a>(
parser: &mut Parser<'a>,
) -> OptionParseResult<'a, VariableDefinitions<'a>> {
if parser.peek().item != Token::ParenOpen {
Ok(None)
} else {
Ok(Some(
try!(parser.delimited_nonempty_list(
&Token::ParenOpen,
parse_variable_definition,
&Token::ParenClose
)).map(|defs| {
VariableDefinitions {
items: defs.into_iter().map(|s| s.item).collect(),
}
}),
))
}
}
fn parse_variable_definition<'a>(
parser: &mut Parser<'a>,
) -> ParseResult<'a, (Spanning<&'a str>, VariableDefinition<'a>)> {
let Spanning {
start: start_pos, ..
} = try!(parser.expect(&Token::Dollar));
let var_name = try!(parser.expect_name());
try!(parser.expect(&Token::Colon));
let var_type = try!(parse_type(parser));
let default_value = if try!(parser.skip(&Token::Equals)).is_some() {
Some(try!(parse_value_literal(parser, true)))
} else {
None
};
Ok(Spanning::start_end(
&start_pos,
&default_value
.as_ref()
.map_or(&var_type.end, |s| &s.end)
.clone(),
(
Spanning::start_end(&start_pos, &var_name.end, var_name.item),
VariableDefinition {
var_type: var_type,
default_value: default_value,
},
),
))
}
fn parse_directives<'a>(
parser: &mut Parser<'a>,
) -> OptionParseResult<'a, Vec<Spanning<Directive<'a>>>> {
if parser.peek().item != Token::At {
Ok(None)
} else {
let mut items = Vec::new();
while parser.peek().item == Token::At {
items.push(try!(parse_directive(parser)));
}
Ok(Spanning::spanning(items))
}
}
fn parse_directive<'a>(parser: &mut Parser<'a>) -> ParseResult<'a, Directive<'a>> {
let Spanning {
start: start_pos, ..
} = try!(parser.expect(&Token::At));
let name = try!(parser.expect_name());
let arguments = try!(parse_arguments(parser));
Ok(Spanning::start_end(
&start_pos,
&arguments.as_ref().map_or(&name.end, |s| &s.end).clone(),
Directive {
name: name,
arguments: arguments,
},
))
}
pub fn parse_type<'a>(parser: &mut Parser<'a>) -> ParseResult<'a, Type<'a>> {
let parsed_type = if let Some(Spanning {
start: start_pos, ..
}) = try!(parser.skip(&Token::BracketOpen))
{
let inner_type = try!(parse_type(parser));
let Spanning { end: end_pos, .. } = try!(parser.expect(&Token::BracketClose));
Spanning::start_end(&start_pos, &end_pos, Type::List(Box::new(inner_type.item)))
} else {
try!(parser.expect_name()).map(|s| Type::Named(Cow::Borrowed(s)))
};
Ok(match *parser.peek() {
Spanning {
item: Token::ExclamationMark,
..
} => try!(wrap_non_null(parser, parsed_type)),
_ => parsed_type,
})
}
fn wrap_non_null<'a>(
parser: &mut Parser<'a>,
inner: Spanning<Type<'a>>,
) -> ParseResult<'a, Type<'a>> {
let Spanning { end: end_pos, .. } = try!(parser.expect(&Token::ExclamationMark));
let wrapped = match inner.item {
Type::Named(name) => Type::NonNullNamed(name),
Type::List(l) => Type::NonNullList(l),
t => t,
};
Ok(Spanning::start_end(&inner.start, &end_pos, wrapped))
}