platform/graphql_parser/lib/src/language/parser.dart

616 lines
16 KiB
Dart
Raw Normal View History

2017-02-05 23:08:03 +00:00
library graphql_parser.language.parser;
2017-01-22 23:15:53 +00:00
import 'ast/ast.dart';
2017-01-25 04:28:09 +00:00
import 'syntax_error.dart';
2017-01-22 23:15:53 +00:00
import 'token.dart';
2017-01-25 04:28:09 +00:00
import 'token_type.dart';
2017-01-22 23:15:53 +00:00
2017-07-03 15:37:35 +00:00
class Parser {
Token _current;
int _index = -1;
2017-01-22 23:15:53 +00:00
2017-07-03 15:37:35 +00:00
final List<Token> tokens;
2018-08-04 19:18:53 +00:00
final List<SyntaxError> errors = <SyntaxError>[];
2017-01-25 04:28:09 +00:00
2017-07-03 15:37:35 +00:00
Parser(this.tokens);
2017-01-25 04:28:09 +00:00
2017-07-03 15:37:35 +00:00
Token get current => _current;
2017-01-25 04:28:09 +00:00
bool next(TokenType type, {Iterable<String> exclude}) {
var tok = peek();
if (tok?.type == type && exclude?.contains(tok.span.text) != true) {
2017-07-03 15:37:35 +00:00
_current = tokens[++_index];
return true;
}
2017-01-25 04:28:09 +00:00
2017-07-03 15:37:35 +00:00
return false;
2017-01-22 23:15:53 +00:00
}
bool nextName(String name) {
var tok = peek();
if (tok?.type == TokenType.NAME && tok.span.text == name) {
return next(TokenType.NAME);
}
return false;
}
2017-07-03 15:37:35 +00:00
Token peek() {
if (_index < tokens.length - 1) {
return tokens[_index + 1];
}
return null;
2017-01-25 04:28:09 +00:00
}
2017-07-04 15:58:22 +00:00
Token maybe(TokenType type) => next(type) ? current : null;
2018-08-04 19:18:53 +00:00
void eatCommas() {
while (next(TokenType.COMMA)) {
continue;
}
}
2017-07-04 17:32:52 +00:00
DocumentContext parseDocument() {
List<DefinitionContext> defs = [];
DefinitionContext def = parseDefinition();
while (def != null) {
defs.add(def);
def = parseDefinition();
}
2019-08-08 02:24:19 +00:00
return DocumentContext()..definitions.addAll(defs);
2017-07-04 17:32:52 +00:00
}
DefinitionContext parseDefinition() =>
parseOperationDefinition() ?? parseFragmentDefinition();
2017-07-04 19:27:47 +00:00
OperationDefinitionContext parseOperationDefinition() {
var selectionSet = parseSelectionSet();
2019-08-08 02:28:20 +00:00
if (selectionSet != null) {
2019-08-08 02:24:19 +00:00
return OperationDefinitionContext(null, null, null, selectionSet);
2019-08-08 02:28:20 +00:00
} else {
if (nextName('mutation') ||
nextName('query') ||
nextName('subscription')) {
2017-07-04 19:27:47 +00:00
var TYPE = current;
Token NAME = next(TokenType.NAME) ? current : null;
var variables = parseVariableDefinitions();
var dirs = parseDirectives();
var selectionSet = parseSelectionSet();
2019-08-08 02:28:20 +00:00
if (selectionSet != null) {
return OperationDefinitionContext(TYPE, NAME, variables, selectionSet)
..directives.addAll(dirs);
2019-08-08 02:28:20 +00:00
} else {
2019-08-08 02:24:19 +00:00
errors.add(SyntaxError(
2018-08-04 19:18:53 +00:00
'Missing selection set in fragment definition.',
NAME?.span ?? TYPE.span));
return null;
}
2019-08-08 02:28:20 +00:00
} else {
2017-07-04 19:27:47 +00:00
return null;
2019-08-08 02:28:20 +00:00
}
2017-07-04 19:27:47 +00:00
}
}
2017-01-25 04:28:09 +00:00
2017-07-04 19:27:47 +00:00
FragmentDefinitionContext parseFragmentDefinition() {
if (nextName('fragment')) {
2017-07-04 19:27:47 +00:00
var FRAGMENT = current;
if (next(TokenType.NAME)) {
var NAME = current;
if (nextName('on')) {
2017-07-04 19:27:47 +00:00
var ON = current;
var typeCondition = parseTypeCondition();
if (typeCondition != null) {
var dirs = parseDirectives();
var selectionSet = parseSelectionSet();
2019-08-08 02:28:20 +00:00
if (selectionSet != null) {
2019-08-08 02:24:19 +00:00
return FragmentDefinitionContext(
2017-07-04 19:27:47 +00:00
FRAGMENT, NAME, ON, typeCondition, selectionSet)
..directives.addAll(dirs);
2019-08-08 02:28:20 +00:00
} else {
2019-08-08 02:24:19 +00:00
errors.add(SyntaxError(
2017-07-04 19:27:47 +00:00
'Expected selection set in fragment definition.',
2018-08-04 19:18:53 +00:00
typeCondition.span));
return null;
}
} else {
2019-08-08 02:24:19 +00:00
errors.add(SyntaxError(
2017-07-04 19:27:47 +00:00
'Expected type condition after "on" in fragment definition.',
2018-08-04 19:18:53 +00:00
ON.span));
return null;
}
} else {
2019-08-08 02:24:19 +00:00
errors.add(SyntaxError(
2017-07-04 19:27:47 +00:00
'Expected "on" after name "${NAME.text}" in fragment definition.',
2018-08-04 19:18:53 +00:00
NAME.span));
return null;
}
} else {
2019-08-08 02:24:19 +00:00
errors.add(SyntaxError(
2017-07-04 19:27:47 +00:00
'Expected name after "fragment" in fragment definition.',
2018-08-04 19:18:53 +00:00
FRAGMENT.span));
return null;
}
2019-08-08 02:28:20 +00:00
} else {
2017-07-04 19:27:47 +00:00
return null;
2019-08-08 02:28:20 +00:00
}
2017-07-04 19:27:47 +00:00
}
2017-01-25 04:28:09 +00:00
2017-07-04 16:46:01 +00:00
FragmentSpreadContext parseFragmentSpread() {
if (next(TokenType.ELLIPSIS)) {
var ELLIPSIS = current;
if (next(TokenType.NAME, exclude: ['on'])) {
2017-07-04 16:46:01 +00:00
var NAME = current;
2019-08-08 02:24:19 +00:00
return FragmentSpreadContext(ELLIPSIS, NAME)
2017-07-04 16:46:01 +00:00
..directives.addAll(parseDirectives());
2017-07-04 17:32:52 +00:00
} else {
_index--;
return null;
}
2019-08-08 02:28:20 +00:00
} else {
2017-07-04 17:32:52 +00:00
return null;
2019-08-08 02:28:20 +00:00
}
2017-07-04 17:32:52 +00:00
}
InlineFragmentContext parseInlineFragment() {
if (next(TokenType.ELLIPSIS)) {
var ELLIPSIS = current;
if (nextName('on')) {
2017-07-04 17:32:52 +00:00
var ON = current;
var typeCondition = parseTypeCondition();
if (typeCondition != null) {
var directives = parseDirectives();
var selectionSet = parseSelectionSet();
if (selectionSet != null) {
2019-08-08 02:24:19 +00:00
return InlineFragmentContext(
2017-07-04 17:32:52 +00:00
ELLIPSIS, ON, typeCondition, selectionSet)
..directives.addAll(directives);
2018-08-04 19:18:53 +00:00
} else {
2019-08-08 02:24:19 +00:00
errors.add(SyntaxError(
2018-08-04 19:18:53 +00:00
'Missing selection set in inline fragment.',
directives.isEmpty
? typeCondition.span
: directives.last.span));
return null;
}
} else {
2019-08-08 02:24:19 +00:00
errors.add(SyntaxError(
2018-08-04 19:18:53 +00:00
'Missing type condition after "on" in inline fragment.',
ON.span));
return null;
}
} else {
2019-08-08 02:24:19 +00:00
errors.add(SyntaxError(
2018-08-04 19:18:53 +00:00
'Missing "on" after "..." in inline fragment.', ELLIPSIS.span));
return null;
}
2019-08-08 02:28:20 +00:00
} else {
2017-07-04 16:46:01 +00:00
return null;
2019-08-08 02:28:20 +00:00
}
2017-07-04 16:46:01 +00:00
}
2017-01-25 04:28:09 +00:00
2017-07-04 16:46:01 +00:00
SelectionSetContext parseSelectionSet() {
if (next(TokenType.LBRACE)) {
var LBRACE = current;
List<SelectionContext> selections = [];
SelectionContext selection = parseSelection();
while (selection != null) {
selections.add(selection);
2018-08-04 19:18:53 +00:00
eatCommas();
2017-07-04 16:46:01 +00:00
selection = parseSelection();
}
2018-08-04 19:18:53 +00:00
eatCommas();
2019-08-08 02:28:20 +00:00
if (next(TokenType.RBRACE)) {
2019-08-08 02:24:19 +00:00
return SelectionSetContext(LBRACE, current)
2017-07-04 16:46:01 +00:00
..selections.addAll(selections);
2019-08-08 02:28:20 +00:00
} else {
2019-08-08 02:24:19 +00:00
errors.add(SyntaxError('Missing "}" after selection set.',
2018-08-04 19:18:53 +00:00
selections.isEmpty ? LBRACE.span : selections.last.span));
return null;
}
2019-08-08 02:28:20 +00:00
} else {
2017-07-04 16:46:01 +00:00
return null;
2019-08-08 02:28:20 +00:00
}
2017-07-04 16:46:01 +00:00
}
2017-01-25 04:28:09 +00:00
2017-07-04 16:46:01 +00:00
SelectionContext parseSelection() {
var field = parseField();
2019-08-08 02:24:19 +00:00
if (field != null) return SelectionContext(field);
2017-07-04 16:46:01 +00:00
var fragmentSpread = parseFragmentSpread();
2019-08-08 02:28:20 +00:00
if (fragmentSpread != null) return SelectionContext(null, fragmentSpread);
2017-07-04 16:46:01 +00:00
var inlineFragment = parseInlineFragment();
2019-08-08 02:28:20 +00:00
if (inlineFragment != null) {
2019-08-08 02:24:19 +00:00
return SelectionContext(null, null, inlineFragment);
2019-08-08 02:28:20 +00:00
} else {
2017-07-04 16:46:01 +00:00
return null;
2019-08-08 02:28:20 +00:00
}
2017-07-04 16:46:01 +00:00
}
2017-01-25 04:28:09 +00:00
2017-07-04 15:58:22 +00:00
FieldContext parseField() {
var fieldName = parseFieldName();
if (fieldName != null) {
var args = parseArguments();
var directives = parseDirectives();
var selectionSet = parseSelectionSet();
2019-08-08 02:24:19 +00:00
return FieldContext(fieldName, selectionSet)
2018-08-04 19:18:53 +00:00
..arguments.addAll(args ?? <ArgumentContext>[])
2017-07-04 15:58:22 +00:00
..directives.addAll(directives);
2019-08-08 02:28:20 +00:00
} else {
2017-07-04 15:58:22 +00:00
return null;
2019-08-08 02:28:20 +00:00
}
2017-07-04 15:58:22 +00:00
}
2017-02-05 23:08:03 +00:00
2017-07-04 15:58:22 +00:00
FieldNameContext parseFieldName() {
if (next(TokenType.NAME)) {
var NAME1 = current;
if (next(TokenType.COLON)) {
var COLON = current;
2019-08-08 02:28:20 +00:00
if (next(TokenType.NAME)) {
return FieldNameContext(null, AliasContext(NAME1, COLON, current));
} else {
errors.add(
SyntaxError('Missing name after colon in alias.', COLON.span));
2018-08-04 19:18:53 +00:00
return null;
}
2019-08-08 02:28:20 +00:00
} else {
2019-08-08 02:24:19 +00:00
return FieldNameContext(NAME1);
2019-08-08 02:28:20 +00:00
}
} else {
2017-07-04 15:58:22 +00:00
return null;
2019-08-08 02:28:20 +00:00
}
2017-07-04 15:58:22 +00:00
}
2017-02-05 23:08:03 +00:00
2017-07-04 19:27:47 +00:00
VariableDefinitionsContext parseVariableDefinitions() {
if (next(TokenType.LPAREN)) {
var LPAREN = current;
List<VariableDefinitionContext> defs = [];
VariableDefinitionContext def = parseVariableDefinition();
while (def != null) {
defs.add(def);
2018-08-04 19:18:53 +00:00
eatCommas();
2017-07-04 19:27:47 +00:00
def = parseVariableDefinition();
}
2019-08-08 02:28:20 +00:00
if (next(TokenType.RPAREN)) {
2019-08-08 02:24:19 +00:00
return VariableDefinitionsContext(LPAREN, current)
2017-07-04 19:27:47 +00:00
..variableDefinitions.addAll(defs);
2019-08-08 02:28:20 +00:00
} else {
2019-08-08 02:24:19 +00:00
errors.add(SyntaxError(
2018-08-04 19:18:53 +00:00
'Missing ")" after variable definitions.', LPAREN.span));
return null;
}
2019-08-08 02:28:20 +00:00
} else {
2017-07-04 19:27:47 +00:00
return null;
2019-08-08 02:28:20 +00:00
}
2017-07-04 19:27:47 +00:00
}
2017-02-05 23:08:03 +00:00
2017-07-04 15:58:22 +00:00
VariableDefinitionContext parseVariableDefinition() {
var variable = parseVariable();
if (variable != null) {
if (next(TokenType.COLON)) {
var COLON = current;
var type = parseType();
if (type != null) {
var defaultValue = parseDefaultValue();
2019-08-08 02:28:20 +00:00
return VariableDefinitionContext(variable, COLON, type, defaultValue);
2018-08-04 19:18:53 +00:00
} else {
2019-08-08 02:28:20 +00:00
errors.add(
SyntaxError('Missing type in variable definition.', COLON.span));
2018-08-04 19:18:53 +00:00
return null;
}
} else {
2019-08-08 02:28:20 +00:00
errors.add(
SyntaxError('Missing ":" in variable definition.', variable.span));
2018-08-04 19:18:53 +00:00
return null;
}
2019-08-08 02:28:20 +00:00
} else {
2017-07-04 15:58:22 +00:00
return null;
2019-08-08 02:28:20 +00:00
}
2017-07-04 15:58:22 +00:00
}
2017-02-05 23:08:03 +00:00
2017-07-04 15:58:22 +00:00
TypeContext parseType() {
var name = parseTypeName();
if (name != null) {
2019-08-08 02:24:19 +00:00
return TypeContext(name, null, maybe(TokenType.EXCLAMATION));
2017-07-04 15:58:22 +00:00
} else {
var listType = parseListType();
if (listType != null) {
2019-08-08 02:24:19 +00:00
return TypeContext(null, listType, maybe(TokenType.EXCLAMATION));
2019-08-08 02:28:20 +00:00
} else {
2017-07-04 15:58:22 +00:00
return null;
2019-08-08 02:28:20 +00:00
}
2017-07-04 15:58:22 +00:00
}
}
ListTypeContext parseListType() {
if (next(TokenType.LBRACKET)) {
var LBRACKET = current;
var type = parseType();
if (type != null) {
if (next(TokenType.RBRACKET)) {
2019-08-08 02:24:19 +00:00
return ListTypeContext(LBRACKET, type, current);
2018-08-04 19:18:53 +00:00
} else {
2019-08-08 02:24:19 +00:00
errors.add(SyntaxError('Missing "]" in list type.', type.span));
2018-08-04 19:18:53 +00:00
return null;
}
} else {
2019-08-08 02:24:19 +00:00
errors.add(SyntaxError('Missing type after "[".', LBRACKET.span));
2018-08-04 19:18:53 +00:00
return null;
}
2019-08-08 02:28:20 +00:00
} else {
2017-07-04 15:58:22 +00:00
return null;
2019-08-08 02:28:20 +00:00
}
2017-07-04 15:58:22 +00:00
}
List<DirectiveContext> parseDirectives() {
List<DirectiveContext> out = [];
DirectiveContext d = parseDirective();
while (d != null) {
out.add(d);
d = parseDirective();
}
return out;
}
2017-02-05 23:08:03 +00:00
2017-07-03 15:37:35 +00:00
DirectiveContext parseDirective() {
if (next(TokenType.ARROBA)) {
var ARROBA = current;
if (next(TokenType.NAME)) {
var NAME = current;
2017-02-05 23:08:03 +00:00
2017-07-03 15:37:35 +00:00
if (next(TokenType.COLON)) {
var COLON = current;
2019-08-08 01:57:36 +00:00
var val = parseInputValue();
2019-08-08 02:28:20 +00:00
if (val != null) {
return DirectiveContext(ARROBA, NAME, COLON, null, null, null, val);
} else {
2019-08-08 02:24:19 +00:00
errors.add(SyntaxError(
2018-08-04 19:18:53 +00:00
'Missing value or variable in directive after colon.',
COLON.span));
return null;
}
2017-07-03 15:37:35 +00:00
} else if (next(TokenType.LPAREN)) {
var LPAREN = current;
var arg = parseArgument();
if (arg != null) {
if (next(TokenType.RPAREN)) {
2019-08-08 02:24:19 +00:00
return DirectiveContext(
2017-07-03 15:37:35 +00:00
ARROBA, NAME, null, LPAREN, current, arg, null);
2018-08-04 19:18:53 +00:00
} else {
2019-08-08 02:24:19 +00:00
errors.add(SyntaxError('Missing \')\'', arg.value.span));
2018-08-04 19:18:53 +00:00
return null;
}
} else {
errors.add(
2019-08-08 02:24:19 +00:00
SyntaxError('Missing argument in directive.', LPAREN.span));
2018-08-04 19:18:53 +00:00
return null;
}
2019-08-08 02:28:20 +00:00
} else {
return DirectiveContext(ARROBA, NAME, null, null, null, null, null);
}
2018-08-04 19:18:53 +00:00
} else {
2019-08-08 02:24:19 +00:00
errors.add(SyntaxError('Missing name for directive.', ARROBA.span));
2018-08-04 19:18:53 +00:00
return null;
}
2019-08-08 02:28:20 +00:00
} else {
2017-07-03 15:37:35 +00:00
return null;
2019-08-08 02:28:20 +00:00
}
2017-07-03 15:37:35 +00:00
}
2017-07-04 15:58:22 +00:00
List<ArgumentContext> parseArguments() {
if (next(TokenType.LPAREN)) {
var LPAREN = current;
List<ArgumentContext> out = [];
ArgumentContext arg = parseArgument();
while (arg != null) {
out.add(arg);
2018-08-04 19:18:53 +00:00
eatCommas();
arg = parseArgument();
2017-07-04 15:58:22 +00:00
}
2019-08-08 02:28:20 +00:00
if (next(TokenType.RPAREN)) {
2017-07-04 15:58:22 +00:00
return out;
2019-08-08 02:28:20 +00:00
} else {
errors.add(SyntaxError('Missing ")" in argument list.', LPAREN.span));
2018-08-04 19:18:53 +00:00
return null;
}
2019-08-08 02:28:20 +00:00
} else {
2017-07-04 15:58:22 +00:00
return [];
2019-08-08 02:28:20 +00:00
}
2017-07-04 15:58:22 +00:00
}
2017-07-03 15:37:35 +00:00
ArgumentContext parseArgument() {
if (next(TokenType.NAME)) {
var NAME = current;
if (next(TokenType.COLON)) {
var COLON = current;
2019-08-08 01:57:36 +00:00
var val = parseInputValue();
2019-08-08 02:28:20 +00:00
if (val != null) {
2019-08-08 02:24:19 +00:00
return ArgumentContext(NAME, COLON, val);
2019-08-08 02:28:20 +00:00
} else {
2019-08-08 02:24:19 +00:00
errors.add(SyntaxError(
2018-08-04 19:18:53 +00:00
'Missing value or variable in argument.', COLON.span));
return null;
}
} else {
2019-08-08 02:28:20 +00:00
errors.add(
SyntaxError('Missing colon after name in argument.', NAME.span));
2018-08-04 19:18:53 +00:00
return null;
}
2019-08-08 02:28:20 +00:00
} else {
2017-07-03 15:37:35 +00:00
return null;
2019-08-08 02:28:20 +00:00
}
2017-01-25 04:28:09 +00:00
}
2019-08-08 01:53:11 +00:00
/// Use [parseInputValue] instead.
@deprecated
InputValueContext parseValueOrVariable() => parseInputValue();
2017-02-05 23:08:03 +00:00
2017-07-03 15:37:35 +00:00
VariableContext parseVariable() {
if (next(TokenType.DOLLAR)) {
var DOLLAR = current;
2019-08-08 02:28:20 +00:00
if (next(TokenType.NAME)) {
2019-08-08 02:24:19 +00:00
return VariableContext(DOLLAR, current);
2019-08-08 02:28:20 +00:00
} else {
2019-08-08 02:24:19 +00:00
errors.add(SyntaxError(
2018-08-04 19:18:53 +00:00
'Missing name for variable; found a lone "\$" instead.',
DOLLAR.span));
return null;
}
2019-08-08 02:28:20 +00:00
} else {
2017-07-03 15:37:35 +00:00
return null;
2019-08-08 02:28:20 +00:00
}
2017-02-05 23:08:03 +00:00
}
2017-07-04 15:58:22 +00:00
DefaultValueContext parseDefaultValue() {
if (next(TokenType.EQUALS)) {
var EQUALS = current;
2019-08-08 01:57:36 +00:00
var value = parseInputValue();
2017-07-04 15:58:22 +00:00
if (value != null) {
2019-08-08 02:24:19 +00:00
return DefaultValueContext(EQUALS, value);
2018-08-04 19:18:53 +00:00
} else {
2019-08-08 02:28:20 +00:00
errors.add(SyntaxError('Missing value after "=" sign.', EQUALS.span));
2018-08-04 19:18:53 +00:00
return null;
}
2019-08-08 02:28:20 +00:00
} else {
2017-07-04 15:58:22 +00:00
return null;
2019-08-08 02:28:20 +00:00
}
2017-07-04 15:58:22 +00:00
}
TypeConditionContext parseTypeCondition() {
var name = parseTypeName();
2019-08-08 02:28:20 +00:00
if (name != null) {
2019-08-08 02:24:19 +00:00
return TypeConditionContext(name);
2019-08-08 02:28:20 +00:00
} else {
2017-07-04 15:58:22 +00:00
return null;
2019-08-08 02:28:20 +00:00
}
2017-07-04 15:58:22 +00:00
}
2017-02-05 23:08:03 +00:00
2017-07-04 15:58:22 +00:00
TypeNameContext parseTypeName() {
if (next(TokenType.NAME)) {
2019-08-08 02:24:19 +00:00
return TypeNameContext(current);
2019-08-08 02:28:20 +00:00
} else {
2017-07-04 15:58:22 +00:00
return null;
2019-08-08 02:28:20 +00:00
}
2017-07-04 15:58:22 +00:00
}
2017-02-05 23:08:03 +00:00
2019-08-08 01:53:11 +00:00
/// Use [parseInputValue] instead.
@deprecated
InputValueContext parseValue() => parseInputValue();
InputValueContext parseInputValue() {
2019-08-08 01:54:12 +00:00
return (parseVariable() ??
parseNumberValue() ??
2018-08-04 19:18:53 +00:00
parseStringValue() ??
2017-07-03 15:37:35 +00:00
parseBooleanValue() ??
2018-08-04 19:18:53 +00:00
parseNullValue() ??
parseEnumValue() ??
parseListValue() ??
2019-08-08 01:53:11 +00:00
parseObjectValue()) as InputValueContext;
2017-07-03 15:37:35 +00:00
}
2017-02-05 23:08:03 +00:00
2018-08-04 19:18:53 +00:00
StringValueContext parseStringValue() => next(TokenType.STRING)
2019-08-08 02:24:19 +00:00
? StringValueContext(current)
2018-08-04 19:18:53 +00:00
: (next(TokenType.BLOCK_STRING)
2019-08-08 02:24:19 +00:00
? StringValueContext(current, isBlockString: true)
2018-08-04 19:18:53 +00:00
: null);
2017-02-05 23:08:03 +00:00
2017-07-03 15:37:35 +00:00
NumberValueContext parseNumberValue() =>
2019-08-08 02:24:19 +00:00
next(TokenType.NUMBER) ? NumberValueContext(current) : null;
2017-02-05 23:08:03 +00:00
2017-07-03 15:37:35 +00:00
BooleanValueContext parseBooleanValue() =>
(nextName('true') || nextName('false'))
2019-08-08 02:24:19 +00:00
? BooleanValueContext(current)
: null;
2017-02-05 23:08:03 +00:00
2018-08-04 19:18:53 +00:00
EnumValueContext parseEnumValue() =>
2019-08-08 02:24:19 +00:00
next(TokenType.NAME) ? EnumValueContext(current) : null;
2018-08-04 19:18:53 +00:00
NullValueContext parseNullValue() =>
2019-08-08 02:24:19 +00:00
nextName('null') ? NullValueContext(current) : null;
2018-08-04 19:18:53 +00:00
ListValueContext parseListValue() {
2017-07-03 15:37:35 +00:00
if (next(TokenType.LBRACKET)) {
var LBRACKET = current;
2018-08-04 19:18:53 +00:00
var lastSpan = LBRACKET.span;
2019-08-08 01:53:11 +00:00
List<InputValueContext> values = [];
var value = parseInputValue();
2017-02-05 23:08:03 +00:00
2017-07-03 15:37:35 +00:00
while (value != null) {
2018-08-04 19:18:53 +00:00
lastSpan = value.span;
2017-07-03 15:37:35 +00:00
values.add(value);
2018-08-04 19:18:53 +00:00
eatCommas();
2019-08-08 01:53:11 +00:00
value = parseInputValue();
2017-07-03 15:37:35 +00:00
}
2017-01-22 23:15:53 +00:00
2018-08-04 19:18:53 +00:00
eatCommas();
2017-07-03 15:37:35 +00:00
if (next(TokenType.RBRACKET)) {
2019-08-08 02:24:19 +00:00
return ListValueContext(LBRACKET, current)..values.addAll(values);
2018-08-04 19:18:53 +00:00
} else {
2019-08-08 02:24:19 +00:00
errors.add(SyntaxError('Unterminated list literal.', lastSpan));
2018-08-04 19:18:53 +00:00
return null;
}
2019-08-08 02:28:20 +00:00
} else {
2017-07-03 15:37:35 +00:00
return null;
2019-08-08 02:28:20 +00:00
}
2017-01-22 23:15:53 +00:00
}
2018-08-04 19:18:53 +00:00
ObjectValueContext parseObjectValue() {
if (next(TokenType.LBRACE)) {
var LBRACE = current;
var lastSpan = LBRACE.span;
var fields = <ObjectFieldContext>[];
var field = parseObjectField();
while (field != null) {
fields.add(field);
2018-08-04 19:18:53 +00:00
lastSpan = field.span;
eatCommas();
field = parseObjectField();
}
eatCommas();
if (next(TokenType.RBRACE)) {
2019-08-08 02:24:19 +00:00
return ObjectValueContext(LBRACE, fields, current);
2018-08-04 19:18:53 +00:00
} else {
2019-08-08 02:24:19 +00:00
errors.add(SyntaxError('Unterminated object literal.', lastSpan));
2018-08-04 19:18:53 +00:00
return null;
}
} else {
return null;
}
}
ObjectFieldContext parseObjectField() {
if (next(TokenType.NAME)) {
var NAME = current;
if (next(TokenType.COLON)) {
var COLON = current;
2019-08-08 01:57:36 +00:00
var value = parseInputValue();
2018-08-04 19:18:53 +00:00
if (value != null) {
2019-08-08 02:24:19 +00:00
return ObjectFieldContext(NAME, COLON, value);
2018-08-04 19:18:53 +00:00
} else {
2019-08-08 02:24:19 +00:00
errors.add(SyntaxError('Missing value after ":".', COLON.span));
2018-08-04 19:18:53 +00:00
return null;
}
} else {
2019-08-08 02:24:19 +00:00
errors.add(SyntaxError(
2018-08-04 19:18:53 +00:00
'Missing ":" after name "${NAME.span.text}".', NAME.span));
return null;
}
} else {
return null;
}
}
2017-01-22 23:15:53 +00:00
}