platform/lib/src/language/parser.dart

181 lines
4.5 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 'dart:async';
import 'ast/ast.dart';
import 'stream_reader.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-02-05 23:08:03 +00:00
part 'base_parser.dart';
2017-01-22 23:15:53 +00:00
2017-02-05 23:08:03 +00:00
class Parser extends BaseParser {
2017-01-22 23:15:53 +00:00
bool _closed = false;
2017-01-25 04:28:09 +00:00
final Completer _closer = new Completer();
final List<SyntaxError> _errors = [];
2017-01-22 23:15:53 +00:00
final StreamReader<Token> _reader = new StreamReader();
2017-01-25 04:28:09 +00:00
List<SyntaxError> get errors => new List<SyntaxError>.unmodifiable(_errors);
Future _waterfall(List<Function> futures) async {
for (var f in futures) {
var r = await f();
if (r != null) return r;
}
}
2017-01-22 23:15:53 +00:00
@override
2017-01-25 04:28:09 +00:00
Future addStream(Stream<Token> stream) {
2017-01-22 23:15:53 +00:00
if (_closed) throw new StateError('Parser is already closed.');
2017-01-25 04:28:09 +00:00
_closed = true;
2017-02-05 23:08:03 +00:00
_reader.onData
.listen((data) => _waterfall([parseDocument, parseBooleanValue]))
..onDone(() => Future.wait([
_onBooleanValue.close(),
_onDocument.close(),
_onNode.close(),
]))
..onError(_closer.completeError);
2017-01-25 04:28:09 +00:00
return stream.pipe(_reader);
2017-01-22 23:15:53 +00:00
}
@override
2017-01-25 04:28:09 +00:00
Future close() {
return _closer.future;
}
Future<bool> expect(TokenType type) async {
var peek = await _reader.peek();
if (peek?.type != type) {
_errors.add(new SyntaxError.fromSourceLocation(
"Expected $type, found '${peek?.text ?? 'empty text'}' instead.",
peek?.span?.start));
return false;
} else {
await _reader.consume();
return true;
}
}
Future<bool> maybe(TokenType type) async {
var peek = await _reader.peek();
if (peek?.type == type) {
await _reader.consume();
return true;
}
return false;
}
Future<bool> nextIs(TokenType type) =>
_reader.peek().then((t) => t?.type == type);
2017-02-05 23:08:03 +00:00
Future<DocumentContext> parseDocument() async {
return null;
}
Future<ValueContext> parseValue() async {
ValueContext value;
var string = await parseStringValue();
if (string != null)
value = string;
else {
var number = await parseNumberValue();
if (number != null)
value = number;
else {
var boolean = await parseBooleanValue();
if (boolean != null)
value = boolean;
else {
var array = await parseArrayValue();
if (array != null) value = array;
}
}
}
if (value != null) _onValue.add(value);
return value;
}
Future<StringValueContext> parseStringValue() async {
if (await nextIs(TokenType.STRING)) {
var result = new StringValueContext(await _reader.consume());
_onStringValue.add(result);
return result;
}
return null;
}
Future<NumberValueContext> parseNumberValue() async {
if (await nextIs(TokenType.NUMBER)) {
var result = new NumberValueContext(await _reader.consume());
_onNumberValue.add(result);
return result;
}
2017-01-25 04:28:09 +00:00
return null;
}
2017-02-05 23:08:03 +00:00
Future<BooleanValueContext> parseBooleanValue() async {
if (await nextIs(TokenType.BOOLEAN)) {
var result = new BooleanValueContext(await _reader.consume());
_onBooleanValue.add(result);
return result;
}
return null;
}
Future<ArrayValueContext> parseArrayValue() async {
if (await nextIs(TokenType.LBRACKET)) {
ArrayValueContext result;
var LBRACKET = await _reader.consume();
List<ValueContext> values = [];
if (await nextIs(TokenType.RBRACKET)) {
result = new ArrayValueContext(LBRACKET, await _reader.consume());
_onArrayValue.add(result);
return result;
}
while (!_reader.isDone) {
ValueContext value = await parseValue();
if (value == null) break;
values.add(value);
if (await nextIs(TokenType.COMMA)) {
await _reader.consume();
continue;
} else if (await nextIs(TokenType.RBRACKET)) {
result = new ArrayValueContext(LBRACKET, await _reader.consume());
_onArrayValue.add(result);
return result;
}
throw new SyntaxError.fromSourceLocation(
'Expected comma or right bracket in array',
(await _reader.current())?.span?.start);
}
throw new SyntaxError.fromSourceLocation(
'Unterminated array literal.', LBRACKET.span?.start);
}
2017-01-25 04:28:09 +00:00
if (await nextIs(TokenType.BOOLEAN)) {
var result = new BooleanValueContext(await _reader.consume());
_onBooleanValue.add(result);
return result;
}
2017-01-22 23:15:53 +00:00
2017-01-25 04:28:09 +00:00
return null;
2017-01-22 23:15:53 +00:00
}
}