import 'package:petitparser/core.dart'; import 'package:petitparser/definition.dart'; import 'package:petitparser/indent.dart'; import 'package:petitparser/parser.dart'; import 'package:petitparser/reflection.dart'; import 'package:test/test.dart'; import 'utils/matchers.dart'; class IndentList extends GrammarDefinition { final indent = Indent(); @override Parser start() => [ ref0(newlines).optional(), ref0(things), ref0(newlines).optional(), endOfInput(), ].toSequenceParser().pick(1); Parser things() => [ indent.same, ref0(object) | ref0(line), ].toSequenceParser().pick(1).star(); Parser object() => [ ref0(key), ref0(block) | ref0(inline), ].toSequenceParser().map((values) => {values[0]: values[1]}); Parser key() => [ pattern('^ \t\r\n:').plusString(), indent.parser.star(), char(':'), indent.parser.star(), ].toSequenceParser().pick(0); Parser block() => [ ref0(newlines), indent.increase, ref0(things), indent.decrease, ].toSequenceParser().pick(2); Parser inline() => ref0(line).map((value) => [value]); Parser line() => [ ref0(newline).neg().plus().flatten(), ref0(newlines).optional(), ].toSequenceParser().pick(0); Parser newline() => Token.newlineParser(); Parser newlines() => [indent.parser.star(), ref0(newline)].toSequenceParser().plus(); } void main() { group('definition', () { final definition = IndentList(); final parser = definition.build(); tearDown(() { expect(definition.indent.stack, isEmpty); expect(definition.indent.current, ''); }); test('linter', () { expect(linter(parser), isEmpty); }); test('empty', () { expect(parser, isParseSuccess('', result: isEmpty)); expect(parser, isParseSuccess('\n', result: isEmpty)); expect(parser, isParseSuccess('\n\r', result: isEmpty)); expect(parser, isParseSuccess('\r', result: isEmpty)); expect(parser, isParseSuccess('\n\n', result: isEmpty)); expect(parser, isParseSuccess('\n\r\n\r', result: isEmpty)); expect(parser, isParseSuccess('\r\r', result: isEmpty)); }); test('newline before', () { expect(parser, isParseSuccess('\na', result: ['a'])); expect(parser, isParseSuccess('\n\ra', result: ['a'])); expect(parser, isParseSuccess('\ra', result: ['a'])); expect(parser, isParseSuccess('\n\na', result: ['a'])); expect(parser, isParseSuccess('\n\r\n\ra', result: ['a'])); expect(parser, isParseSuccess('\r\ra', result: ['a'])); }); test('newline after', () { expect(parser, isParseSuccess('a\n', result: ['a'])); expect(parser, isParseSuccess('a\n\r', result: ['a'])); expect(parser, isParseSuccess('a\r', result: ['a'])); expect(parser, isParseSuccess('a\n\n', result: ['a'])); expect(parser, isParseSuccess('a\n\r\n\r', result: ['a'])); expect(parser, isParseSuccess('a\r\r', result: ['a'])); }); test('single indent', () { expect( parser, isParseSuccess( 'a:\n b', result: [ { 'a': ['b'], }, ], ), ); expect( parser, isParseSuccess( 'a:\n\tb', result: [ { 'a': ['b'], }, ], ), ); expect( parser, isParseSuccess( 'a:\n \tb', result: [ { 'a': ['b'], }, ], ), ); expect( parser, isParseSuccess( 'a:\n\t b', result: [ { 'a': ['b'], }, ], ), ); }); test('same indent', () { expect( parser, isParseSuccess( 'a:\n b\n c', result: [ { 'a': ['b', 'c'], }, ], ), ); expect( parser, isParseSuccess( 'a:\n\tb\n\tc', result: [ { 'a': ['b', 'c'], }, ], ), ); expect( parser, isParseSuccess( 'a:\n \tb\n \tc', result: [ { 'a': ['b', 'c'], }, ], ), ); expect( parser, isParseSuccess( 'a:\n\t b\n\t c', result: [ { 'a': ['b', 'c'], }, ], ), ); }); test('different indent', () { expect(parser, isParseFailure('a:\n b\n\tc', position: 6)); expect(parser, isParseFailure('a:\n\tb\n c', position: 6)); }); test('missing indent', () { expect(parser, isParseSuccess('a:\nb', result: ['a:', 'b'])); }); test('unexpected indent', () { expect(parser, isParseFailure('a\n b', position: 2)); }); test('same level', () { expect(parser, isParseSuccess('a\nb\nc', result: ['a', 'b', 'c'])); }); test('inlined values', () { expect( parser, isParseSuccess( 'a:1\nb: 2\nc :3', result: [ { 'a': ['1'], }, { 'b': ['2'], }, { 'c': ['3'], }, ], ), ); }); test('increasing', () { expect( parser, isParseSuccess( 'a:\n b:\n c', result: [ { 'a': [ { 'b': ['c'], }, ], }, ], ), ); }); test('decreasing', () { expect( parser, isParseSuccess( 'a:\n\tb\nc', result: [ { 'a': ['b'], }, 'c', ], ), ); }); }); }