Dart DocumentationparsersLanguageParsers

LanguageParsers class

Programming language specific combinators

class LanguageParsers {
 String _commentStart;
 String _commentEnd;
 String _commentLine;
 bool _nestedComments;
 Parser<String> _identStart;
 Parser<String> _identLetter;
 Set<String> _reservedNames;
 bool _caseSensitive;

 ReservedNames _reserved;

 LanguageParsers({
   String         commentStart   : '/*',
   String         commentEnd     : '*/',
   String         commentLine    : '//',
   bool           nestedComments : false,
   Parser<String> identStart     : null, // letter | char('_')
   Parser<String> identLetter    : null, // alphanum | char('_')
   List<String>   reservedNames  : const []
 }) {
   final identStartDefault = letter | char('_');
   final identLetterDefault = alphanum | char('_');

   _commentStart = commentStart;
   _commentEnd = commentEnd;
   _commentLine = commentLine;
   _nestedComments = nestedComments;
   _identStart = (identStart == null) ? identStartDefault : identStart;
   _identLetter = (identLetter == null) ? identLetterDefault : identLetter;
   _reservedNames = new Set<String>.from(reservedNames);
 }

 Parser<String> get semi  => symbol(';') % 'semicolon';
 Parser<String> get comma => symbol(',') % 'comma';
 Parser<String> get colon => symbol(':') % 'colon';
 Parser<String> get dot   => symbol('.') % 'dot';

 Parser<String> get _ident =>
     success((c) => (cs) => _consStr(c)(cs.join()))
     * _identStart
     * _identLetter.many;

 Parser<String> get identifier =>
     lexeme(_ident >> (name) =>
            _reservedNames.contains(name) ? fail : success(name))
     % 'identifier';

 ReservedNames get reserved {
   if (_reserved == null) {
     final map = new Map<String, Parser<String>>();
     for (final name in _reservedNames) {
       map[name] = lexeme(string(name).notFollowedBy(_identLetter));
     }
     _reserved = new ReservedNames._(map);
   }
   return _reserved;
 }

 final Parser<String> _escapeCode =
     (char('a')  > success('\a'))
   | (char('b')  > success('\b'))
   | (char('f')  > success('\f'))
   | (char('n')  > success('\n'))
   | (char('r')  > success('\r'))
   | (char('t')  > success('\t'))
   | (char('v')  > success('\v'))
   | (char('\\') > success('\\'))
   | (char('"')  > success('"'))
   | (char("'")  > success("'"));

 Parser<String> get _charChar => (char('\\') > _escapeCode)
                               | pred((c) => c != "'");

 Parser<String> get charLiteral =>
     lexeme(_charChar.between(char("'"), char("'")))
     % 'character literal';

 Parser<String> get _stringChar => (char('\\') > _escapeCode)
                                 | pred((c) => c != '"');

 Parser<String> get stringLiteral =>
     lexeme(_stringChar.many.between(char('"'), char('"')))
     .map((cs) => cs.join())
     % 'string literal';

 Map<String, int> _digitToInt = {
   '0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8,
   '9': 9, 'a': 10, 'b': 11, 'c': 12, 'd': 13, 'e': 14, 'f': 15, 'A': 10,
   'B': 11, 'C': 12, 'D': 13, 'E': 14, 'F': 15
 };

 Parser<int> _number(int base, Parser baseDigit) => baseDigit.many1 >> (ds) {
   int res = 0;
   for (final d in ds) { res = base * res + _digitToInt[d]; }
   return success(res);
 };

 Parser<int> get _zeroNumber =>
     char('0') > (hexaDecimal | octal | decimal | success(0));

 Parser<int> get _nat => _zeroNumber | decimal;

 Parser<int> get _int => lexeme(_sign) * _nat;

 Parser<Function> get _sign => (char('-') > success((n) => -n))
                             | (char('+') > success((n) => n))
                             | success((n) => n);

 Parser<int> get natural => lexeme(_nat) % 'natural number';

 Parser<int> get intLiteral => lexeme(_int) % 'integer';

 num _power(num e) => e < 0 ? 1.0 / _power(-e) : pow(10, e);

 Parser<double> get _exponent =>
     oneOf('eE') > success((f) => (e) => _power(f(e))) * _sign * decimal;

 Parser<double> get _fraction => char('.') > digit.many1 >> (ds) {
   double res = 0.0;
   for (int i = ds.length - 1; i >= 0; i--) {
     res = (res + _digitToInt[ds[i]]) / 10.0;
   }
   return success(res);
 };

 Parser<double> _fractExponent(int n) =>
     (success((fract) => (expo) => (n + fract) * expo)
         * _fraction
         * _exponent.orElse(1.0))
     | _exponent.map((expo) => n * expo);

 Parser<double> get floatLiteral =>
     lexeme(decimal >> _fractExponent) % 'float';

 Parser<int> get decimal => _number(10, digit) % 'decimal number';

 Parser<int> get hexaDecimal =>
     (oneOf("xX") > _number(16, oneOf("0123456789abcdefABCDEF")))
     % 'hexadecimal number';

 Parser<int> get octal =>
     (oneOf("oO") > _number(8, oneOf("01234567")))
     % 'octal number';

 Parser<String> symbol(String symb) => lexeme(string(symb));

 Parser lexeme(Parser p) => p < whiteSpace;

 Parser get _start => string(_commentStart);
 Parser get _end => string(_commentEnd);
 Parser get _notStartNorEnd => (_start | _end).notAhead > anyChar;

 Parser _multiLineComment() => _start > _inComment();

 Parser _inComment() =>
     _nestedComments ? _inCommentMulti() : _inCommentSingle();

 Parser _inCommentMulti() => _notStartNorEnd.skipMany > _recOrEnd();

 Parser _recOrEnd() => (rec(_multiLineComment) > rec(_inCommentMulti))
                     | (_end > success(null));

 Parser _inCommentSingle() => anyChar.skipManyUntil(_end);

 Parser get _oneLineComment =>
     string(_commentLine) > (pred((c) => c != '\n').skipMany > success(null));

 Parser get whiteSpace => _whiteSpace % 'whitespace/comment';

 Parser get _whiteSpace {
   if (_commentLine.isEmpty && _commentStart.isEmpty) {
     return space.skipMany;
   } else if (_commentLine.isEmpty) {
     return (space | _multiLineComment()).skipMany;
   } else if (_commentStart.isEmpty) {
     return (space | _oneLineComment).skipMany;
   } else {
     return (space | _oneLineComment | _multiLineComment()).skipMany;
   }
 }

 Parser parens(Parser p) => p.between(symbol('('), symbol(')'));

 Parser braces(Parser p) => p.between(symbol('{'), symbol('}'));

 Parser angles(Parser p) => p.between(symbol('<'), symbol('>'));

 Parser brackets(Parser p) => p.between(symbol('['), symbol(']'));
}

Constructors

new LanguageParsers({String commentStart: '/*', String commentEnd: '*/', String commentLine: '//', bool nestedComments: false, Parser<String> identStart: null, Parser<String> identLetter: null, List<String> reservedNames: const[] }) #

Creates a new Object instance.

Object instances have no meaningful state, and are only useful through their identity. An Object instance is equal to itself only.

docs inherited from Object
LanguageParsers({
 String         commentStart   : '/*',
 String         commentEnd     : '*/',
 String         commentLine    : '//',
 bool           nestedComments : false,
 Parser<String> identStart     : null, // letter | char('_')
 Parser<String> identLetter    : null, // alphanum | char('_')
 List<String>   reservedNames  : const []
}) {
 final identStartDefault = letter | char('_');
 final identLetterDefault = alphanum | char('_');

 _commentStart = commentStart;
 _commentEnd = commentEnd;
 _commentLine = commentLine;
 _nestedComments = nestedComments;
 _identStart = (identStart == null) ? identStartDefault : identStart;
 _identLetter = (identLetter == null) ? identLetterDefault : identLetter;
 _reservedNames = new Set<String>.from(reservedNames);
}

Properties

final Parser<String> charLiteral #

Parser<String> get charLiteral =>
   lexeme(_charChar.between(char("'"), char("'")))
   % 'character literal';

final Parser<String> colon #

Parser<String> get colon => symbol(':') % 'colon';

final Parser<String> comma #

Parser<String> get comma => symbol(',') % 'comma';

final Parser<int> decimal #

Parser<int> get decimal => _number(10, digit) % 'decimal number';

final Parser<String> dot #

Parser<String> get dot   => symbol('.') % 'dot';

final Parser<double> floatLiteral #

Parser<double> get floatLiteral =>
   lexeme(decimal >> _fractExponent) % 'float';

final Parser<int> hexaDecimal #

Parser<int> get hexaDecimal =>
   (oneOf("xX") > _number(16, oneOf("0123456789abcdefABCDEF")))
   % 'hexadecimal number';

final Parser<String> identifier #

Parser<String> get identifier =>
   lexeme(_ident >> (name) =>
          _reservedNames.contains(name) ? fail : success(name))
   % 'identifier';

final Parser<int> intLiteral #

Parser<int> get intLiteral => lexeme(_int) % 'integer';

final Parser<int> natural #

Parser<int> get natural => lexeme(_nat) % 'natural number';

final Parser<int> octal #

Parser<int> get octal =>
   (oneOf("oO") > _number(8, oneOf("01234567")))
   % 'octal number';

final ReservedNames reserved #

ReservedNames get reserved {
 if (_reserved == null) {
   final map = new Map<String, Parser<String>>();
   for (final name in _reservedNames) {
     map[name] = lexeme(string(name).notFollowedBy(_identLetter));
   }
   _reserved = new ReservedNames._(map);
 }
 return _reserved;
}

final Parser<String> semi #

Parser<String> get semi  => symbol(';') % 'semicolon';

final Parser<String> stringLiteral #

Parser<String> get stringLiteral =>
   lexeme(_stringChar.many.between(char('"'), char('"')))
   .map((cs) => cs.join())
   % 'string literal';

final Parser whiteSpace #

Parser get whiteSpace => _whiteSpace % 'whitespace/comment';

Methods

Parser angles(Parser p) #

Parser angles(Parser p) => p.between(symbol('<'), symbol('>'));

Parser braces(Parser p) #

Parser braces(Parser p) => p.between(symbol('{'), symbol('}'));

Parser brackets(Parser p) #

Parser brackets(Parser p) => p.between(symbol('['), symbol(']'));

Parser lexeme(Parser p) #

Parser lexeme(Parser p) => p < whiteSpace;

Parser parens(Parser p) #

Parser parens(Parser p) => p.between(symbol('('), symbol(')'));

Parser<String> symbol(String symb) #

Parser<String> symbol(String symb) => lexeme(string(symb));