parser_combinator 0.1.3 copy "parser_combinator: ^0.1.3" to clipboard
parser_combinator: ^0.1.3 copied to clipboard

discontinuedreplaced by: peg
outdated

Parser combinator is a collection of parsers that can be used to combine basic parsers to create parsers for more complex rules.

example/example.dart

import 'package:parser_combinator/parser/choice.dart';
import 'package:parser_combinator/parser/delimited.dart';
import 'package:parser_combinator/parser/digit1.dart';
import 'package:parser_combinator/parser/eof.dart';
import 'package:parser_combinator/parser/expected.dart';
import 'package:parser_combinator/parser/fast.dart';
import 'package:parser_combinator/parser/handle_error.dart';
import 'package:parser_combinator/parser/integer.dart';
import 'package:parser_combinator/parser/mapped.dart';
import 'package:parser_combinator/parser/opt.dart';
import 'package:parser_combinator/parser/preceded.dart';
import 'package:parser_combinator/parser/predicate.dart';
import 'package:parser_combinator/parser/recognize.dart';
import 'package:parser_combinator/parser/ref.dart';
import 'package:parser_combinator/parser/separated_list.dart';
import 'package:parser_combinator/parser/separated_pair.dart';
import 'package:parser_combinator/parser/skip16_while.dart';
import 'package:parser_combinator/parser/string_chars.dart';
import 'package:parser_combinator/parser/tag.dart';
import 'package:parser_combinator/parser/tags.dart';
import 'package:parser_combinator/parser/take_while_m_n.dart';
import 'package:parser_combinator/parser/terminated.dart';
import 'package:parser_combinator/parser/tuple.dart';
import 'package:parser_combinator/parser/value.dart';
import 'package:parser_combinator/parser_combinator.dart';
import 'package:parser_combinator/parsing.dart';
import 'package:parser_combinator/runtime.dart';

void main(List<String> args) {
  final result = parseString(parser, '{"rocket": "🚀 flies to the stars"}');
  print(result);
}

const parser = Delimited(name: 'json', _ws, _value, Eof());

const value = Choice7(
  name: 'value',
  _object,
  _array,
  _string,
  _number,
  _false,
  _null,
  _true,
);

const _array = Delimited(name: 'array', _openBracket, _values, _closeBracket);

const _closeBrace = Terminated(name: '_closeBrace', Tag('}'), _ws);

const _closeBracket = Terminated(name: '_closeBracket', Tag(']'), _ws);

const _colon = Terminated(name: '_colon', Tag(':'), _ws);

const _comma = Terminated(name: '_comma', Tag(','), _ws);

const _digit1 = Expected(name: '_digit1', Digit1(), 'decimal digit');

const _doubleQuote = Terminated(name: '_doubleQuote', Tag('"'), _ws);

const _escape = _Escape(name: '_escape');

const _escapeHexValue = Mapped(
    name: '_escapeHexValue',
    Preceded(Tag('u'), _hexValueChecked),
    createStringFromHexValue);

const _exponent =
    Tuple3(name: '_exponent', Tags(['E', 'e']), Opt(Tags(['-', '+'])), _digit1);

const _false = ValueP(name: '_false', false, Terminated(Tag('false'), _ws));

const _fraction = Tuple2(name: '_fraction', Tag('.'), _digit1);

const _hexValue = TakeWhileMN(name: '_hexValue', 4, 4, isHexDigit);

const _hexValueChecked =
    HandleError(name: '_hexValueChecked', _hexValue, handleHexValueError);

const _integer = Integer(name: '_integer');

const _keyValue = Mapped(
    name: '_keyValue', SeparatedPair(_string, _colon, _value), createMapEntry);

const _keyValues = SeparatedList(name: '_keyValues', _keyValue, _comma);

const _null =
    // ignore: unnecessary_cast
    ValueP(name: '_null', null as Object?, Terminated(Tag('null'), _ws));

const _number = Expected(name: 'number', Terminated(_number_, _ws), 'number');

/// '-'?('0'|[1-9][0-9]*)('.'[0-9]+)?([eE][+-]?[0-9]+)?
const _number_ = Mapped(
    name: 'number_',
    Recognize(
      Fast3(
        _integer,
        Opt(_fraction),
        Opt(_exponent),
      ),
    ),
    num.parse);

const _object = Mapped(
    name: 'object',
    Delimited(_openBrace, _keyValues, _closeBrace),
    Map.fromEntries);

const _openBrace = Terminated(name: '_openBrace', Tag('{'), _ws);

const _openBracket = Terminated(name: '_openBracket', Tag('['), _ws);

const _string = Expected(
  name: 'string',
  Delimited(
    Tag('"'),
    StringChars(
      isNormalChar,
      92,
      Choice2(
        _escape,
        _escapeHexValue,
      ),
    ),
    _doubleQuote,
  ),
  'string',
);

const _true = ValueP(name: '_true', true, Terminated(Tag('true'), _ws));

const Parser<String, Object?> _value = Ref(name: '_value', getValueParser);

const _values = SeparatedList(name: '_values', _value, _comma);

const _ws = Skip16While(name: '_ws', isWhitespace);

MapEntry<String, Object?> createMapEntry((String, Object?) kv) {
  return MapEntry(kv.$1, kv.$2);
}

String createStringFromHexValue(String s) {
  return String.fromCharCode(toHexValue(s));
}

Parser<String, Object?> getValueParser() => value;

(bool, List<ParseError>) handleHexValueError(int start, int end) {
  return (
    false,
    [ErrorMessage(start - end, 'Expected 4 digit hexadecimal number')]
  );
}

bool isNormalChar(int c) => c <= 91
    ? c <= 33
        ? c >= 32
        : c >= 35
    : c <= 1114111 && c >= 93;

@pragma('vm:prefer-inline')
int toHexValue(String s) {
  var r = 0;
  for (var i = s.length - 1, j = 0; i >= 0; i--, j += 4) {
    final c = s.codeUnitAt(i);
    final int v;
    if (c >= 0x30 && c <= 0x39) {
      v = c - 0x30;
    } else if (c >= 0x41 && c <= 0x46) {
      v = c - 0x41 + 10;
    } else if (c >= 0x61 && c <= 0x66) {
      v = c - 0x61 + 10;
    } else {
      throw StateError('Internal error');
    }

    r += v * (1 << j);
  }

  return r;
}

class ParserErrorMessages {
  static const expected4DigitHexadecimalNumber =
      'Expected 4 digit hexadecimal number';

  final String text;

  const ParserErrorMessages(this.text);
}

class _Escape extends Parser<String, String> {
  const _Escape({String? name}) : super(name);

  @override
  Parser<String, String> build(ParserBuilder builder) {
    return _Escape(name: name);
  }

  @override
  bool fastParse(State<String> state) {
    final r = parse(state);
    return r != null;
  }

  @override
  Result<String>? parse(State<String> state) {
    final c = state.input.codeUnitAt(state.pos);
    switch (c) {
      case 34:
        state.pos++;
        return const Result('"');
      case 0x2F:
        state.pos++;
        return const Result('/');
      case 0x5C:
        state.pos++;
        return const Result(r'\\');
      case 0x62:
        state.pos++;
        return const Result('\b');
      case 0x66:
        state.pos++;
        return const Result('\f');
      case 0x6E:
        state.pos++;
        return const Result('\n');
      case 0x72:
        state.pos++;
        return const Result('\r');
      case 0x74:
        state.pos++;
        return const Result('\t');
    }

    return state.fail(const ErrorUnexpectedCharacter());
  }
}
0
likes
0
points
76
downloads

Publisher

unverified uploader

Weekly Downloads

Parser combinator is a collection of parsers that can be used to combine basic parsers to create parsers for more complex rules.

Repository (GitHub)
View/report issues

Topics

#parser #parser-combinator #parsing #peg

License

unknown (license)

Dependencies

_fe_analyzer_shared, intl, path

More

Packages that depend on parser_combinator