peg 0.0.26 copy "peg: ^0.0.26" to clipboard
peg: ^0.0.26 copied to clipboard

outdatedDart 1 only

PEG (Parsing expression grammar) parsers generator.

#peg #

PEG (Parsing expression grammar) parsers generator.

Version: 0.0.26

Status: Experimental

!!!NEW FEATURE!!!

Added the new parser generator: interpreter parser (NOT YET READY FOR USE).

Advantages:

  • Less source code size of the generated parser (the more complex grammar, the more noticeable difference in the size of)
  • Higher performance (with an upcoming the symbols transitions it will be much better)

Latest version always can be found at https://github.com/mezoni/peg

Features:

  • Generation of detailed comments
  • Generated parsers has no dependencies
  • Grammar analytics
  • Grammar reporting
  • Grammar statistics
  • High quality generated source code
  • High performance of parsing process
  • Lookahead mapping tables
  • Memoization
  • Possibility to trace parsing
  • Powerful error and mistakes detection
  • Printing grammar
  • Symbols transitions (upcomming)
  • Terminal and nonterminal symbol recognition

Error detection

  • Infinite loops
  • Left recursive rules
  • Optional expression in choices

Trace

Trace information are useful for diagnose the problems.

Trace displayed in the following format:

column, line:state rule padding code position

Eg:

94, 8: F* OPEN    '-' Char { $$ = [$1, $3]; (2343)
94, 8:  > Literal '-' Char { $$ = [$1, $3]; (2343)

State:

Cache : Match : Direction

Cache:

  • 'C' - Cache
  • ' ' - Not cache

Match:

  • 'F' - Failed
  • ' ' - Succeed

Direction:

  • '>' - Enter
  • '<' - Leave
  • 'S' - Skip (lookahead)

Examples:

  • ' >' Enter
  • ' <' Leave, success
  • ' F<' Leave, failed
  • 'C <' Leave, succeed, uses cached result
  • 'CF<' Leave, failed, uses cached result
  • ' S' Skip (lookahead), succeed
  • ' FS' Skip (lookahead), failed

Grammar

Grammar <- SPACING? GLOBALS? Members? Definition+ EOF

Members <- "{" ActionBody* "}" SPACING

Action <- "{" ActionBody* "}" SPACING

ActionBody <- Action / !"}" .

Definition <- IDENTIFIER LEFTARROW Expression

Expression <- Sequence (SLASH Sequence)*

Sequence <- Prefix+

Prefix <- (AND / NOT)? Suffix Action?

Suffix <- Primary (QUESTION / STAR / PLUS)?

Primary <- IDENTIFIER !LEFTARROW / OPEN Expression CLOSE / LITERAL / CLASS / DOT

CHAR <- "\\" ["'\-\[-\]nrt] / HEX_NUMBER / !"\\" !EOL .

CLASS <- "[" (!"]" RANGE)* "]" SPACING

LITERAL <- "\'" (!"\'" CHAR)* "\'" SPACING / "\"" (!"\"" CHAR)* "\"" SPACING

EOF <- !.

GLOBALS <- "%{" GLOBALS_BODY* "}%" SPACING

GLOBALS_BODY <- !"}%" .

IDENTIFIER <- IDENT_START IDENT_CONT* SPACING

IDENT_START <- [A-Z_a-z]

IDENT_CONT <- IDENT_START / [0-9]

LEFTARROW <- "<-" SPACING

RANGE <- CHAR "-" CHAR / CHAR

SLASH <- "/" SPACING

AND <- "&" SPACING

NOT <- "!" SPACING

QUESTION <- "?" SPACING

STAR <- "*" SPACING

PLUS <- "+" SPACING

OPEN <- "(" SPACING

CLOSE <- ")" SPACING

DOT <- "." SPACING

HEX_NUMBER <- [\] "u" [0-9A-Fa-f]+

COMMENT <- "#" (!EOL .)* EOL?

SPACE <- [\t ] / EOL

SPACING <- (SPACE / COMMENT)*

EOL <- "\r\n" / [\n\r]

Example

Arithmetic grammar

%{
part of peg.example.arithmetic;

num _binop(num left, num right, String op) {
  switch(op) {
    case "+":
      return left + right;
    case "-":
      return left - right;
    case "*":
      return left * right;
    case "/":
      return left / right;
    default:
      throw "Unsupported operation $op";  
  }
}

}%

Expr <-
  SPACES? Sentence EOF { $$ = $2; }

Sentence <-
  Term (PLUS / MINUS) Sentence { $$ = _binop($1, $3, $2); }
  / Term

Term <-
  Atom (MUL / DIV) Term { $$ = _binop($1, $3, $2); }
  / Atom

Atom <-
  NUMBER
  / OPEN Sentence CLOSE { $$ = $2; }

# Tokens

CLOSE <-
  ')' SPACES

DIV <-
  '/' SPACES { $$ = $1; }

EOF <-
  !.

MINUS <-
  '-' SPACES { $$ = $1; }

MUL <-
  '*' SPACES { $$ = $1; }

NUMBER <-
  [0-9]+ SPACES { $$ = int.parse($1.join()); }

OPEN <-
  '(' SPACES

PLUS <-
  '+' SPACES { $$ = $1; }
 
SPACES <-
  WS*

 WS <-
   [ \n\t\r] / '\r\n'

Source code of the generated parser for arithmetic grammar

Such (as an arithmetic) grammars parsed faster with a memoization.

peg general --comment --lookahead --memoize arithmetic.peg

// This code was generated by a tool.
// Processing tool available at https://github.com/mezoni/peg

part of peg.example.arithmetic;

num _binop(num left, num right, String op) {
  switch(op) {
    case "+":
      return left + right;
    case "-":
      return left - right;
    case "*":
      return left * right;
    case "/":
      return left / right;
    default:
      throw "Unsupported operation $op";  
  }
}
class ArithmeticParser {
  static final List<String> _ascii = new List<String>.generate(128, (c) => new String.fromCharCode(c));
  
  static final List<String> _expect0 = <String>["\'(\'", "NUMBER"];
  
  static final List<String> _expect1 = <String>["\'+\'"];
  
  static final List<String> _expect10 = <String>["EOF"];
  
  static final List<String> _expect11 = <String>["WS"];
  
  static final List<String> _expect12 = <String>["SPACES"];
  
  static final List<String> _expect2 = <String>["\'-\'"];
  
  static final List<String> _expect3 = <String>["\'+\'", "\'-\'"];
  
  static final List<String> _expect4 = <String>["\'*\'"];
  
  static final List<String> _expect5 = <String>["\'/\'"];
  
  static final List<String> _expect6 = <String>["\'*\'", "\'/\'"];
  
  static final List<String> _expect7 = <String>["NUMBER"];
  
  static final List<String> _expect8 = <String>["\'(\'"];
  
  static final List<String> _expect9 = <String>["\')\'"];
  
  static final List<bool> _lookahead = _unmap([0x800013, 0x3ff01]);
  
  // '\t', '\n', '\r', ' '
  static final List<bool> _mapping0 = _unmap([0x800013]);
  
  // '\r\n'
  static final List<int> _strings0 = <int>[13, 10];
  
  final List<int> _tokenFlags = [1, 1, 0, 1, 1, 1, 1, 1, 1, 1];
  
  final List<String> _tokenNames = ["\')\'", "\'/\'", "EOF", "\'-\'", "\'*\'", "NUMBER", "\'(\'", "\'+\'", "SPACES", "WS"];
  
  List _cache;
  
  int _cachePos;
  
  List<int> _cacheRule;
  
  List<int> _cacheState;
  
  int _ch;
  
  int _cursor;
  
  List<ArithmeticParserError> _errors;
  
  List<String> _expected;
  
  int _failurePos;
  
  List<int> _input;
  
  int _inputLen;
  
  int _testing;
  
  int _token;
  
  int _tokenLevel;
  
  int _tokenStart;
  
  bool success;
  
  final String text;
  
  ArithmeticParser(this.text) {
    if (text == null) {
      throw new ArgumentError('text: $text');
    }    
    _input = _toCodePoints(text);
    _inputLen = _input.length;
    if (_inputLen >= 0x3fffffe8 / 32) {
      throw new StateError('File size to big: $_inputLen');
    }  
    reset(0);    
  }
  
  void _addToCache(dynamic result, int start, int id) {  
    var cached = _cache[start];
    if (cached == null) {
      _cacheRule[start] = id;
      _cache[start] = [result, _cursor, success];
    } else {    
      var slot = start >> 5;
      var r1 = (slot << 5) & 0x3fffffff;    
      var mask = 1 << (start - r1);    
      if ((_cacheState[slot] & mask) == 0) {
        _cacheState[slot] |= mask;   
        cached = [new List.filled(2, 0), new Map<int, List>()];
        _cache[start] = cached;                                      
      }
      slot = id >> 5;
      r1 = (slot << 5) & 0x3fffffff;    
      mask = 1 << (id - r1);    
      cached[0][slot] |= mask;
      cached[1][id] = [result, _cursor, success];      
    }
    if (_cachePos < start) {
      _cachePos = start;
    }    
  }
  
  Iterable _compact(Iterable iterable) {  
    if (iterable is List) {
      var hasNull = false;
      var length = iterable.length;
      for (var i = 0; i < length; i++) {
        if (iterable[i] == null) {
          hasNull = true;
          break;
        }
      }
      if (!hasNull) {
        return iterable;
      }
      var result = [];
      for (var i = 0; i < length; i++) {
        var element = iterable[i];
        if (element != null) {
          result.add(element);
        }
      }
      return result;
    }   
    var result = [];
    for (var element in iterable) {   
      if (element != null) {
        result.add(element);
      }
    }
    return result;  
  }
  
  void _failure([List<String> expected]) {  
    if (_failurePos > _cursor) {
      return;
    }
    if (_failurePos < _cursor) {    
      _expected = [];
     _failurePos = _cursor;
    }
    if (_token != null) {
      var flag = _tokenFlags[_token];
      var name = _tokenNames[_token];
      if (_failurePos == _inputLen && (flag & 1) != 0) {             
        var message = "Unterminated $name";
        _errors.add(new ArithmeticParserError(ArithmeticParserError.UNTERMINATED, _failurePos, _tokenStart, message));            
      }
      else if (_failurePos > _tokenStart && (flag & 1) != 0) {             
        var message = "Malformed $name";
        _errors.add(new ArithmeticParserError(ArithmeticParserError.MALFORMED, _failurePos, _tokenStart, message));            
      }
      _expected.add(name);        
    } else if (expected == null) {
      _expected.add(null);
    } else {
      _expected.addAll(expected);
    }   
  }
  
  List _flatten(dynamic value) {
    if (value is List) {
      var result = [];
      var length = value.length;
      for (var i = 0; i < length; i++) {
        var element = value[i];
        if (element is Iterable) {
          result.addAll(_flatten(element));
        } else {
          result.add(element);
        }
      }
      return result;
    } else if (value is Iterable) {
      var result = [];
      for (var element in value) {
        if (element is! List) {
          result.add(element);
        } else {
          result.addAll(_flatten(element));
        }
      }
    }
    return [value];
  }
  
  dynamic _getFromCache(int id) {  
    var result = _cache[_cursor];
    if (result == null) {
      return null;
    }    
    var slot = _cursor >> 5;
    var r1 = (slot << 5) & 0x3fffffff;  
    var mask = 1 << (_cursor - r1);
    if ((_cacheState[slot] & mask) == 0) {
      if (_cacheRule[_cursor] == id) {      
        _cursor = result[1];
        success = result[2];      
        if (_cursor < _inputLen) {
          _ch = _input[_cursor];
        } else {
          _ch = -1;
        }      
        return result;
      } else {
        return null;
      }    
    }
    slot = id >> 5;
    r1 = (slot << 5) & 0x3fffffff;  
    mask = 1 << (id - r1);
    if ((result[0][slot] & mask) == 0) {
      return null;
    }
    var data = result[1][id];  
    _cursor = data[1];
    success = data[2];
    if (_cursor < _inputLen) {
      _ch = _input[_cursor];
    } else {
      _ch = -1;
    }   
    return data;  
  }
  
  String _matchAny() {
    success = _cursor < _inputLen;
    if (success) {
      String result;
      if (_ch < 128) {
        result = _ascii[_ch];  
      } else {
        result = new String.fromCharCode(_ch);
      }    
      if (++_cursor < _inputLen) {
        _ch = _input[_cursor];
      } else {
        _ch = -1;
      }    
      return result;
    }    
    return null;  
  }
  
  String _matchChar(int ch, String string) {
    success = _ch == ch;
    if (success) {
      var result = string;  
      if (++_cursor < _inputLen) {
        _ch = _input[_cursor];
      } else {
        _ch = -1;
      }    
      return result;
    }  
    return null;  
  }
  
  String _matchMapping(int start, int end, List<bool> mapping) {
    success = _ch >= start && _ch <= end;
    if (success) {    
      if(mapping[_ch - start]) {
        String result;
        if (_ch < 128) {
          result = _ascii[_ch];  
        } else {
          result = new String.fromCharCode(_ch);
        }     
        if (++_cursor < _inputLen) {
          _ch = _input[_cursor];
        } else {
          _ch = -1;
        }      
        return result;
      }
      success = false;
    }  
    return null;  
  }
  
  String _matchRange(int start, int end) {
    success = _ch >= start && _ch <= end;
    if (success) {
      String result;
      if (_ch < 128) {
        result = _ascii[_ch];  
      } else {
        result = new String.fromCharCode(_ch);
      }        
      if (++_cursor < _inputLen) {
        _ch = _input[_cursor];
      } else {
        _ch = -1;
      }  
      return result;
    }  
    return null;  
  }
  
  String _matchRanges(List<int> ranges) {
    var length = ranges.length;
    for (var i = 0; i < length; i += 2) {
      if (_ch <= ranges[i + 1]) {
        if (_ch >= ranges[i]) {
          String result;
          if (_ch < 128) {
            result = _ascii[_ch];  
          } else {
            result = new String.fromCharCode(_ch);
          }          
          if (++_cursor < _inputLen) {
            _ch = _input[_cursor];
          } else {
             _ch = -1;
          }
          success = true;    
          return result;
        }      
      } else break;  
    }
    success = false;  
    return null;  
  }
  
  String _matchString(List<int> runes, String string) {
    var length = runes.length;  
    success = true;  
    if (_cursor + length <= _inputLen) {
      for (var i = 0; i < length; i++) {
        if (runes[i] != _input[_cursor + i]) {
          success = false;
          break;
        }
      }
    } else {
      success = false;
    }  
    if (success) {
      _cursor += length;      
      if (_cursor < _inputLen) {
        _ch = _input[_cursor];
      } else {
        _ch = -1;
      }    
      return string;      
    }  
    return null; 
  }
  
  dynamic _parse_Atom() {
    // NONTERMINAL
    // Atom <- NUMBER / OPEN Sentence CLOSE
    var $$;
    // NUMBER / OPEN Sentence CLOSE
    while (true) {
      // NUMBER
      $$ = null;
      success = _ch >= 48 && _ch <= 57 && _lookahead[_ch + -9];
      // Lookahead (NUMBER)
      if (success) $$ = _parse_NUMBER();    
      if (!success) {    
        // Expected: NUMBER    
        if (_cursor > _testing) _failure(_expect7);
      }
      if (success) break;
      // OPEN Sentence CLOSE
      var ch0 = _ch, pos0 = _cursor;
      while (true) {  
        // OPEN
        $$ = null;
        success = _ch == 40; // '('
        // Lookahead (OPEN)
        if (success) $$ = _parse_OPEN();
        if (!success) {
          // Expected: '('
          if (_cursor > _testing) _failure(_expect8);  
          break;  
        }
        var seq = new List(3)..[0] = $$;
        // Sentence
        $$ = null;
        success = _ch >= 40 && _ch <= 57 && _lookahead[_ch + -9];
        // Lookahead (Sentence)
        if (success) $$ = _parse_Sentence();    
        if (!success) {    
          // Expected: NUMBER, '('    
          if (_cursor > _testing) _failure(_expect0);
          break;  
        }
        seq[1] = $$;
        // CLOSE
        $$ = null;
        success = _ch == 41; // ')'
        // Lookahead (CLOSE)
        if (success) $$ = _parse_CLOSE();
        if (!success) {
          // Expected: ')'
          if (_cursor > _testing) _failure(_expect9);  
          break;  
        }
        seq[2] = $$;
        $$ = seq;
        if (success) {    
          // OPEN
          final $1 = seq[0];
          // Sentence
          final $2 = seq[1];
          // CLOSE
          final $3 = seq[2];
          $$ = $2;    
        }
        break;  
      }
      if (!success) {
        _ch = ch0;
        _cursor = pos0;
      }
      break;
    }
    if (!success && _cursor > _testing) {
      // Expected: NUMBER, '('
      _failure(_expect0);
    }
    return $$;
  }
  
  dynamic _parse_CLOSE() {
    // TERMINAL
    // CLOSE <- ")" SPACES
    var $$;
    if (_tokenLevel++ == 0) {  
      _token = 0;  
      _tokenStart = _cursor;  
    }  
    // ")" SPACES
    var ch0 = _ch, pos0 = _cursor;
    while (true) {  
      // ")"
      $$ = _matchChar(41, ')');
      if (!success) break;
      var seq = new List(2)..[0] = $$;
      // SPACES
      $$ = null;
      success = _ch >= 9 && _ch <= 32 && _lookahead[_ch + -9];
      // Lookahead (SPACES is optional)
      if (success) $$ = _parse_SPACES();
      else success = true;
      seq[1] = $$;
      $$ = seq;
      break;  
    }
    if (!success) {
      _ch = ch0;
      _cursor = pos0;
    }
    if (!success && _cursor > _testing) {
      // Expected: ')'
      _failure(_expect9);
    }
    if (--_tokenLevel == 0) {
      _token = null;
      _tokenStart = null;
    }
    return $$;
  }
  
  dynamic _parse_DIV() {
    // TERMINAL
    // DIV <- "/" SPACES
    var $$;
    if (_tokenLevel++ == 0) {  
      _token = 1;  
      _tokenStart = _cursor;  
    }  
    // "/" SPACES
    var ch0 = _ch, pos0 = _cursor;
    while (true) {  
      // "/"
      $$ = _matchChar(47, '/');
      if (!success) break;
      var seq = new List(2)..[0] = $$;
      // SPACES
      $$ = null;
      success = _ch >= 9 && _ch <= 32 && _lookahead[_ch + -9];
      // Lookahead (SPACES is optional)
      if (success) $$ = _parse_SPACES();
      else success = true;
      seq[1] = $$;
      $$ = seq;
      if (success) {    
        // "/"
        final $1 = seq[0];
        // SPACES
        final $2 = seq[1];
        $$ = $1;    
      }
      break;  
    }
    if (!success) {
      _ch = ch0;
      _cursor = pos0;
    }
    if (!success && _cursor > _testing) {
      // Expected: '/'
      _failure(_expect5);
    }
    if (--_tokenLevel == 0) {
      _token = null;
      _tokenStart = null;
    }
    return $$;
  }
  
  dynamic _parse_EOF() {
    // TERMINAL
    // EOF <- !.
    var $$;
    if (_tokenLevel++ == 0) {  
      _token = 2;  
      _tokenStart = _cursor;  
    }  
    // !.
    var ch0 = _ch, pos0 = _cursor, testing0 = _testing; 
    _testing = _inputLen + 1;
    // .
    $$ = _matchAny();
    _ch = ch0;
    _cursor = pos0; 
    _testing = testing0;
    $$ = null;
    success = !success;
    if (!success && _cursor > _testing) {
      // Expected: EOF
      _failure(_expect10);
    }
    if (--_tokenLevel == 0) {
      _token = null;
      _tokenStart = null;
    }
    return $$;
  }
  
  dynamic _parse_MINUS() {
    // TERMINAL
    // MINUS <- "-" SPACES
    var $$;
    if (_tokenLevel++ == 0) {  
      _token = 3;  
      _tokenStart = _cursor;  
    }  
    // "-" SPACES
    var ch0 = _ch, pos0 = _cursor;
    while (true) {  
      // "-"
      $$ = _matchChar(45, '-');
      if (!success) break;
      var seq = new List(2)..[0] = $$;
      // SPACES
      $$ = null;
      success = _ch >= 9 && _ch <= 32 && _lookahead[_ch + -9];
      // Lookahead (SPACES is optional)
      if (success) $$ = _parse_SPACES();
      else success = true;
      seq[1] = $$;
      $$ = seq;
      if (success) {    
        // "-"
        final $1 = seq[0];
        // SPACES
        final $2 = seq[1];
        $$ = $1;    
      }
      break;  
    }
    if (!success) {
      _ch = ch0;
      _cursor = pos0;
    }
    if (!success && _cursor > _testing) {
      // Expected: '-'
      _failure(_expect2);
    }
    if (--_tokenLevel == 0) {
      _token = null;
      _tokenStart = null;
    }
    return $$;
  }
  
  dynamic _parse_MUL() {
    // TERMINAL
    // MUL <- "*" SPACES
    var $$;
    if (_tokenLevel++ == 0) {  
      _token = 4;  
      _tokenStart = _cursor;  
    }  
    // "*" SPACES
    var ch0 = _ch, pos0 = _cursor;
    while (true) {  
      // "*"
      $$ = _matchChar(42, '*');
      if (!success) break;
      var seq = new List(2)..[0] = $$;
      // SPACES
      $$ = null;
      success = _ch >= 9 && _ch <= 32 && _lookahead[_ch + -9];
      // Lookahead (SPACES is optional)
      if (success) $$ = _parse_SPACES();
      else success = true;
      seq[1] = $$;
      $$ = seq;
      if (success) {    
        // "*"
        final $1 = seq[0];
        // SPACES
        final $2 = seq[1];
        $$ = $1;    
      }
      break;  
    }
    if (!success) {
      _ch = ch0;
      _cursor = pos0;
    }
    if (!success && _cursor > _testing) {
      // Expected: '*'
      _failure(_expect4);
    }
    if (--_tokenLevel == 0) {
      _token = null;
      _tokenStart = null;
    }
    return $$;
  }
  
  dynamic _parse_NUMBER() {
    // TERMINAL
    // NUMBER <- [0-9]+ SPACES
    var $$;
    if (_tokenLevel++ == 0) {  
      _token = 5;  
      _tokenStart = _cursor;  
    }  
    // [0-9]+ SPACES
    var ch0 = _ch, pos0 = _cursor;
    while (true) {  
      // [0-9]+
      var testing0;
      for (var first = true, reps; ;) {  
        // [0-9]  
        $$ = _matchRange(48, 57);  
        if (success) {
         if (first) {      
            first = false;
            reps = [$$];
            testing0 = _testing;                  
          } else {
            reps.add($$);
          }
          _testing = _cursor;   
        } else {
          success = !first;
          if (success) {      
            _testing = testing0;
            $$ = reps;      
          } else $$ = null;
          break;
        }  
      }
      if (!success) break;
      var seq = new List(2)..[0] = $$;
      // SPACES
      $$ = null;
      success = _ch >= 9 && _ch <= 32 && _lookahead[_ch + -9];
      // Lookahead (SPACES is optional)
      if (success) $$ = _parse_SPACES();
      else success = true;
      seq[1] = $$;
      $$ = seq;
      if (success) {    
        // [0-9]+
        final $1 = seq[0];
        // SPACES
        final $2 = seq[1];
        $$ = int.parse($1.join());    
      }
      break;  
    }
    if (!success) {
      _ch = ch0;
      _cursor = pos0;
    }
    if (!success && _cursor > _testing) {
      // Expected: NUMBER
      _failure(_expect7);
    }
    if (--_tokenLevel == 0) {
      _token = null;
      _tokenStart = null;
    }
    return $$;
  }
  
  dynamic _parse_OPEN() {
    // TERMINAL
    // OPEN <- "(" SPACES
    var $$;
    if (_tokenLevel++ == 0) {  
      _token = 6;  
      _tokenStart = _cursor;  
    }  
    // "(" SPACES
    var ch0 = _ch, pos0 = _cursor;
    while (true) {  
      // "("
      $$ = _matchChar(40, '(');
      if (!success) break;
      var seq = new List(2)..[0] = $$;
      // SPACES
      $$ = null;
      success = _ch >= 9 && _ch <= 32 && _lookahead[_ch + -9];
      // Lookahead (SPACES is optional)
      if (success) $$ = _parse_SPACES();
      else success = true;
      seq[1] = $$;
      $$ = seq;
      break;  
    }
    if (!success) {
      _ch = ch0;
      _cursor = pos0;
    }
    if (!success && _cursor > _testing) {
      // Expected: '('
      _failure(_expect8);
    }
    if (--_tokenLevel == 0) {
      _token = null;
      _tokenStart = null;
    }
    return $$;
  }
  
  dynamic _parse_PLUS() {
    // TERMINAL
    // PLUS <- "+" SPACES
    var $$;
    if (_tokenLevel++ == 0) {  
      _token = 7;  
      _tokenStart = _cursor;  
    }  
    // "+" SPACES
    var ch0 = _ch, pos0 = _cursor;
    while (true) {  
      // "+"
      $$ = _matchChar(43, '+');
      if (!success) break;
      var seq = new List(2)..[0] = $$;
      // SPACES
      $$ = null;
      success = _ch >= 9 && _ch <= 32 && _lookahead[_ch + -9];
      // Lookahead (SPACES is optional)
      if (success) $$ = _parse_SPACES();
      else success = true;
      seq[1] = $$;
      $$ = seq;
      if (success) {    
        // "+"
        final $1 = seq[0];
        // SPACES
        final $2 = seq[1];
        $$ = $1;    
      }
      break;  
    }
    if (!success) {
      _ch = ch0;
      _cursor = pos0;
    }
    if (!success && _cursor > _testing) {
      // Expected: '+'
      _failure(_expect1);
    }
    if (--_tokenLevel == 0) {
      _token = null;
      _tokenStart = null;
    }
    return $$;
  }
  
  dynamic _parse_SPACES() {
    // TERMINAL
    // SPACES <- WS*
    var $$;        
    var pos = _cursor;    
    if(pos <= _cachePos) {
      $$ = _getFromCache(12);
    }
    if($$ != null) {
      return $$[0];       
    }  
    if (_tokenLevel++ == 0) {    
      _token = 8;    
      _tokenStart = _cursor;    
    }    
    // WS*
    var testing0 = _testing; 
    for (var reps = []; ; ) {
      _testing = _cursor;
      // WS
      $$ = null;
      success = _ch >= 9 && _ch <= 32 && _lookahead[_ch + -9];
      // Lookahead (WS)
      if (success) $$ = _parse_WS();    
      if (!success) {    
        // Expected: WS    
        if (_cursor > _testing) _failure(_expect11);
      }
      if (success) {  
        reps.add($$);
      } else {
        success = true;
        _testing = testing0;
        $$ = reps;
        break; 
      }
    }
    if (!success && _cursor > _testing) {
      // Expected: SPACES
      _failure(_expect12);
    }
    _addToCache($$, pos, 12);
    if (--_tokenLevel == 0) {
      _token = null;
      _tokenStart = null;
    }
    return $$;
  }
  
  dynamic _parse_Sentence() {
    // NONTERMINAL
    // Sentence <- Term (PLUS / MINUS) Sentence / Term
    var $$;        
    var pos = _cursor;    
    if(pos <= _cachePos) {
      $$ = _getFromCache(1);
    }
    if($$ != null) {
      return $$[0];       
    }  
    // Term (PLUS / MINUS) Sentence / Term
    while (true) {
      // Term (PLUS / MINUS) Sentence
      var ch0 = _ch, pos0 = _cursor;
      while (true) {  
        // Term
        $$ = null;
        success = _ch >= 40 && _ch <= 57 && _lookahead[_ch + -9];
        // Lookahead (Term)
        if (success) $$ = _parse_Term();    
        if (!success) {    
          // Expected: NUMBER, '('    
          if (_cursor > _testing) _failure(_expect0);
          break;  
        }
        var seq = new List(3)..[0] = $$;
        // PLUS / MINUS
        while (true) {
          // PLUS
          $$ = null;
          success = _ch == 43; // '+'
          // Lookahead (PLUS)
          if (success) $$ = _parse_PLUS();
          if (!success) {
            // Expected: '+'
            if (_cursor > _testing) _failure(_expect1);  
          }
          if (success) break;
          // MINUS
          $$ = null;
          success = _ch == 45; // '-'
          // Lookahead (MINUS)
          if (success) $$ = _parse_MINUS();
          if (!success) {
            // Expected: '-'
            if (_cursor > _testing) _failure(_expect2);  
          }
          break;
        }
        if (!success && _cursor > _testing) {
          // Expected: '+', '-'
          _failure(_expect3);
        }
        if (!success) break;
        seq[1] = $$;
        // Sentence
        $$ = null;
        success = _ch >= 40 && _ch <= 57 && _lookahead[_ch + -9];
        // Lookahead (Sentence)
        if (success) $$ = _parse_Sentence();    
        if (!success) {    
          // Expected: NUMBER, '('    
          if (_cursor > _testing) _failure(_expect0);
          break;  
        }
        seq[2] = $$;
        $$ = seq;
        if (success) {    
          // Term
          final $1 = seq[0];
          // PLUS / MINUS
          final $2 = seq[1];
          // Sentence
          final $3 = seq[2];
          $$ = _binop($1, $3, $2);    
        }
        break;  
      }
      if (!success) {
        _ch = ch0;
        _cursor = pos0;
      }
      if (success) break;
      // Term
      $$ = null;
      success = _ch >= 40 && _ch <= 57 && _lookahead[_ch + -9];
      // Lookahead (Term)
      if (success) $$ = _parse_Term();    
      if (!success) {    
        // Expected: NUMBER, '('    
        if (_cursor > _testing) _failure(_expect0);
      }
      break;
    }
    if (!success && _cursor > _testing) {
      // Expected: NUMBER, '('
      _failure(_expect0);
    }
    _addToCache($$, pos, 1);
    return $$;
  }
  
  dynamic _parse_Term() {
    // NONTERMINAL
    // Term <- Atom (MUL / DIV) Term / Atom
    var $$;        
    var pos = _cursor;    
    if(pos <= _cachePos) {
      $$ = _getFromCache(2);
    }
    if($$ != null) {
      return $$[0];       
    }  
    // Atom (MUL / DIV) Term / Atom
    while (true) {
      // Atom (MUL / DIV) Term
      var ch0 = _ch, pos0 = _cursor;
      while (true) {  
        // Atom
        $$ = null;
        success = _ch >= 40 && _ch <= 57 && _lookahead[_ch + -9];
        // Lookahead (Atom)
        if (success) $$ = _parse_Atom();    
        if (!success) {    
          // Expected: NUMBER, '('    
          if (_cursor > _testing) _failure(_expect0);
          break;  
        }
        var seq = new List(3)..[0] = $$;
        // MUL / DIV
        while (true) {
          // MUL
          $$ = null;
          success = _ch == 42; // '*'
          // Lookahead (MUL)
          if (success) $$ = _parse_MUL();
          if (!success) {
            // Expected: '*'
            if (_cursor > _testing) _failure(_expect4);  
          }
          if (success) break;
          // DIV
          $$ = null;
          success = _ch == 47; // '/'
          // Lookahead (DIV)
          if (success) $$ = _parse_DIV();
          if (!success) {
            // Expected: '/'
            if (_cursor > _testing) _failure(_expect5);  
          }
          break;
        }
        if (!success && _cursor > _testing) {
          // Expected: '*', '/'
          _failure(_expect6);
        }
        if (!success) break;
        seq[1] = $$;
        // Term
        $$ = null;
        success = _ch >= 40 && _ch <= 57 && _lookahead[_ch + -9];
        // Lookahead (Term)
        if (success) $$ = _parse_Term();    
        if (!success) {    
          // Expected: NUMBER, '('    
          if (_cursor > _testing) _failure(_expect0);
          break;  
        }
        seq[2] = $$;
        $$ = seq;
        if (success) {    
          // Atom
          final $1 = seq[0];
          // MUL / DIV
          final $2 = seq[1];
          // Term
          final $3 = seq[2];
          $$ = _binop($1, $3, $2);    
        }
        break;  
      }
      if (!success) {
        _ch = ch0;
        _cursor = pos0;
      }
      if (success) break;
      // Atom
      $$ = null;
      success = _ch >= 40 && _ch <= 57 && _lookahead[_ch + -9];
      // Lookahead (Atom)
      if (success) $$ = _parse_Atom();    
      if (!success) {    
        // Expected: NUMBER, '('    
        if (_cursor > _testing) _failure(_expect0);
      }
      break;
    }
    if (!success && _cursor > _testing) {
      // Expected: NUMBER, '('
      _failure(_expect0);
    }
    _addToCache($$, pos, 2);
    return $$;
  }
  
  dynamic _parse_WS() {
    // TERMINAL
    // WS <- [\t-\n\r ] / "\r\n"
    var $$;
    if (_tokenLevel++ == 0) {  
      _token = 9;  
      _tokenStart = _cursor;  
    }  
    // [\t-\n\r ] / "\r\n"
    while (true) {
      // [\t-\n\r ]
      $$ = _matchMapping(9, 32, _mapping0);
      if (success) break;
      // "\r\n"
      $$ = _matchString(_strings0, '\r\n');
      break;
    }
    if (!success && _cursor > _testing) {
      // Expected: WS
      _failure(_expect11);
    }
    if (--_tokenLevel == 0) {
      _token = null;
      _tokenStart = null;
    }
    return $$;
  }
  
  int _toCodePoint(String string) {
    if (string == null) {
      throw new ArgumentError("string: $string");
    }
  
    var length = string.length;
    if (length == 0) {
      throw new StateError("An empty string contains no elements.");
    }
  
    var start = string.codeUnitAt(0);
    if (length == 1) {
      return start;
    }
  
    if ((start & 0xFC00) == 0xD800) {
      var end = string.codeUnitAt(1);
      if ((end & 0xFC00) == 0xDC00) {
        return (0x10000 + ((start & 0x3FF) << 10) + (end & 0x3FF));
      }
    }
  
    return start;
  }
  
  List<int> _toCodePoints(String string) {
    if (string == null) {
      throw new ArgumentError("string: $string");
    }
  
    var length = string.length;
    if (length == 0) {
      return const <int>[];
    }
  
    var codePoints = <int>[];
    codePoints.length = length;
    var i = 0;
    var pos = 0;
    for ( ; i < length; pos++) {
      var start = string.codeUnitAt(i);
      i++;
      if ((start & 0xFC00) == 0xD800 && i < length) {
        var end = string.codeUnitAt(i);
        if ((end & 0xFC00) == 0xDC00) {
          codePoints[pos] = (0x10000 + ((start & 0x3FF) << 10) + (end & 0x3FF));
          i++;
        } else {
          codePoints[pos] = start;
        }
      } else {
        codePoints[pos] = start;
      }
    }
  
    codePoints.length = pos;
    return codePoints;
  }
  
  static List<bool> _unmap(List<int> mapping) {
    var length = mapping.length;
    var result = new List<bool>(length * 31);
    var offset = 0;
    for (var i = 0; i < length; i++) {
      var v = mapping[i];
      for (var j = 0; j < 31; j++) {
        result[offset++] = v & (1 << j) == 0 ? false : true;
      }
    }
    return result;
  }
  
  List<ArithmeticParserError> errors() {
    if (success) {
      return <ArithmeticParserError>[];
    }
  
    String escape(int c) {
      switch (c) {
        case 10:
          return r"\n";
        case 13:
          return r"\r";
        case 09:
          return r"\t";
        case -1:
          return "";
      }
      return new String.fromCharCode(c);
    } 
    
    String getc(int position) {  
      if (position < _inputLen) {
        return "'${escape(_input[position])}'";      
      }       
      return "end of file";
    }
  
    var errors = <ArithmeticParserError>[];
    if (_failurePos >= _cursor) {
      var set = new Set<ArithmeticParserError>();
      set.addAll(_errors);
      for (var error in set) {
        if (error.position >= _failurePos) {
          errors.add(error);
        }
      }
      var names = new Set<String>();  
      names.addAll(_expected);
      if (names.contains(null)) {
        var string = getc(_failurePos);
        var message = "Unexpected $string";
        var error = new ArithmeticParserError(ArithmeticParserError.UNEXPECTED, _failurePos, _failurePos, message);
        errors.add(error);
      } else {      
        var found = getc(_failurePos);      
        var list = names.toList();
        list.sort();
        var message = "Expected ${list.join(", ")} but found $found";
        var error = new ArithmeticParserError(ArithmeticParserError.EXPECTED, _failurePos, _failurePos, message);
        errors.add(error);
      }        
    }
    errors.sort((a, b) => a.position.compareTo(b.position));
    return errors;  
  }
  
  dynamic parse_Expr() {
    // NONTERMINAL
    // Expr <- SPACES? Sentence EOF
    var $$;
    // SPACES? Sentence EOF
    var ch0 = _ch, pos0 = _cursor;
    while (true) {  
      // SPACES?
      var testing0 = _testing;
      _testing = _cursor;
      // SPACES
      $$ = null;
      success = _ch >= 9 && _ch <= 32 && _lookahead[_ch + -9];
      // Lookahead (SPACES is optional)
      if (success) $$ = _parse_SPACES();
      else success = true;
      success = true; 
      _testing = testing0;
      if (!success) break;
      var seq = new List(3)..[0] = $$;
      // Sentence
      $$ = null;
      success = _ch >= 40 && _ch <= 57 && _lookahead[_ch + -9];
      // Lookahead (Sentence)
      if (success) $$ = _parse_Sentence();    
      if (!success) {    
        // Expected: NUMBER, '('    
        if (_cursor > _testing) _failure(_expect0);
        break;  
      }
      seq[1] = $$;
      // EOF
      $$ = _parse_EOF();
      if (!success) break;
      seq[2] = $$;
      $$ = seq;
      if (success) {    
        // SPACES?
        final $1 = seq[0];
        // Sentence
        final $2 = seq[1];
        // EOF
        final $3 = seq[2];
        $$ = $2;    
      }
      break;  
    }
    if (!success) {
      _ch = ch0;
      _cursor = pos0;
    }
    if (!success && _cursor > _testing) {
      // Expected: NUMBER, '('
      _failure(_expect0);
    }
    return $$;
  }
  
  void reset(int pos) {
    if (pos == null) {
      throw new ArgumentError('pos: $pos');
    }
    if (pos < 0 || pos > _inputLen) {
      throw new RangeError('pos');
    }      
    _cursor = pos;
    _cache = new List(_inputLen + 1);
    _cachePos = -1;
    _cacheRule = new List(_inputLen + 1);
    _cacheState = new List.filled(((_inputLen + 1) >> 5) + 1, 0);
    _ch = -1;
    _errors = <ArithmeticParserError>[];   
    _expected = <String>[];
    _failurePos = -1;  
    success = true;      
    _testing = -1;
    _token = null;
    _tokenLevel = 0;
    _tokenStart = null;
    if (_cursor < _inputLen) {
      _ch = _input[_cursor];
    }    
  }
  
}

class ArithmeticParserError {
  static const int EXPECTED = 1;    
      
  static const int MALFORMED = 2;    
      
  static const int MISSING = 3;    
      
  static const int UNEXPECTED = 4;    
      
  static const int UNTERMINATED = 5;    
      
  final int hashCode = 0;
  
  final String message;
  
  final int position;
  
  final int start;
  
  final int type;
  
  ArithmeticParserError(this.type, this.position, this.start, this.message);
  
  bool operator ==(other) {
    if (identical(this, other)) return true;
    if (other is ArithmeticParserError) {
      return type == other.type && position == other.position &&
      start == other.start && message == other.message;  
    }
    return false;
  }
  
}


Arithmetic grammar statistics

--------------------------------
Starting rules:
Expr
--------------------------------
Rules:
--------------------------------
Atom:
 Type: Nonterminal
 Direct callees:
  CLOSE
  NUMBER
  OPEN
  Sentence
 All callees:
  Atom
  CLOSE
  DIV
  MINUS
  MUL
  NUMBER
  OPEN
  PLUS
  SPACES
  Sentence
  Term
  WS
 Direct callers:
  Term
 All callers:
  Atom
  Expr
  Sentence
  Term
 Start characters:
  [(][0-9]
 Expected lexemes:
  NUMBER '('
--------------------------------
CLOSE:
 Type: Lexeme
 Direct callees:
  SPACES
 All callees:
  SPACES
  WS
 Direct callers:
  Atom
 All callers:
  Atom
  Expr
  Sentence
  Term
 Start characters:
  [)]
 Expected lexemes:
  ')'
--------------------------------
DIV:
 Type: Lexeme
 Direct callees:
  SPACES
 All callees:
  SPACES
  WS
 Direct callers:
  Term
 All callers:
  Atom
  Expr
  Sentence
  Term
 Start characters:
  [/]
 Expected lexemes:
  '/'
--------------------------------
EOF:
 Type: Lexeme
 Direct callees:
 All callees:
 Direct callers:
  Expr
 All callers:
  Expr
 Start characters:
 Expected lexemes:
  EOF
--------------------------------
Expr:
 Type: Nonterminal
 Direct callees:
  EOF
  SPACES
  Sentence
 All callees:
  Atom
  CLOSE
  DIV
  EOF
  MINUS
  MUL
  NUMBER
  OPEN
  PLUS
  SPACES
  Sentence
  Term
  WS
 Direct callers:
 All callers:
 Start characters:
  [\t-\n][\r][ ][(][0-9]
 Expected lexemes:
  NUMBER '('
--------------------------------
MINUS:
 Type: Lexeme
 Direct callees:
  SPACES
 All callees:
  SPACES
  WS
 Direct callers:
  Sentence
 All callers:
  Atom
  Expr
  Sentence
  Term
 Start characters:
  [-]
 Expected lexemes:
  '-'
--------------------------------
MUL:
 Type: Lexeme
 Direct callees:
  SPACES
 All callees:
  SPACES
  WS
 Direct callers:
  Term
 All callers:
  Atom
  Expr
  Sentence
  Term
 Start characters:
  [*]
 Expected lexemes:
  '*'
--------------------------------
NUMBER:
 Type: Lexeme
 Direct callees:
  SPACES
 All callees:
  SPACES
  WS
 Direct callers:
  Atom
 All callers:
  Atom
  Expr
  Sentence
  Term
 Start characters:
  [0-9]
 Expected lexemes:
  NUMBER
--------------------------------
OPEN:
 Type: Lexeme
 Direct callees:
  SPACES
 All callees:
  SPACES
  WS
 Direct callers:
  Atom
 All callers:
  Atom
  Expr
  Sentence
  Term
 Start characters:
  [(]
 Expected lexemes:
  '('
--------------------------------
PLUS:
 Type: Lexeme
 Direct callees:
  SPACES
 All callees:
  SPACES
  WS
 Direct callers:
  Sentence
 All callers:
  Atom
  Expr
  Sentence
  Term
 Start characters:
  [+]
 Expected lexemes:
  '+'
--------------------------------
SPACES:
 Type: Lexeme
 Direct callees:
  WS
 All callees:
  WS
 Direct callers:
  CLOSE
  DIV
  Expr
  MINUS
  MUL
  NUMBER
  OPEN
  PLUS
 All callers:
  Atom
  CLOSE
  DIV
  Expr
  MINUS
  MUL
  NUMBER
  OPEN
  PLUS
  Sentence
  Term
 Start characters:
  [\t-\n][\r][ ]
 Expected lexemes:
  SPACES
--------------------------------
Sentence:
 Type: Nonterminal
 Direct callees:
  MINUS
  PLUS
  Sentence
  Term
 All callees:
  Atom
  CLOSE
  DIV
  MINUS
  MUL
  NUMBER
  OPEN
  PLUS
  SPACES
  Sentence
  Term
  WS
 Direct callers:
  Atom
  Expr
  Sentence
 All callers:
  Atom
  Expr
  Sentence
  Term
 Start characters:
  [(][0-9]
 Expected lexemes:
  NUMBER '('
--------------------------------
Term:
 Type: Nonterminal
 Direct callees:
  Atom
  DIV
  MUL
  Term
 All callees:
  Atom
  CLOSE
  DIV
  MINUS
  MUL
  NUMBER
  OPEN
  PLUS
  SPACES
  Sentence
  Term
  WS
 Direct callers:
  Sentence
  Term
 All callers:
  Atom
  Expr
  Sentence
  Term
 Start characters:
  [(][0-9]
 Expected lexemes:
  NUMBER '('
--------------------------------
WS:
 Type: Morpheme
 Direct callees:
 All callees:
 Direct callers:
  SPACES
 All callers:
  Atom
  CLOSE
  DIV
  Expr
  MINUS
  MUL
  NUMBER
  OPEN
  PLUS
  SPACES
  Sentence
  Term
 Start characters:
  [\t-\n][\r][ ]
 Expected lexemes:
  WS
--------------------------------
Nonterminals:
  Atom
  Expr
  Sentence
  Term
--------------------------------
Lexemes:
  CLOSE
  DIV
  EOF
  MINUS
  MUL
  NUMBER
  OPEN
  PLUS
  SPACES
--------------------------------
Morphemes:
  SPACES
  WS
--------------------------------
Lexemes & morphemes:
  SPACES
--------------------------------
Lexeme names:
  CLOSE : ')'
  DIV : '/'
  EOF : EOF
  MINUS : '-'
  MUL : '*'
  NUMBER : NUMBER
  OPEN : '('
  PLUS : '+'
  SPACES : SPACES
--------------------------------
Recursives:
  Atom
  Sentence
  Term

2
likes
0
pub points
11%
popularity

Publisher

unverified uploader

PEG (Parsing expression grammar) parsers generator.

Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

args, args_helper, build_tools, lists, path, string_matching, strings, template_block, text, yaml

More

Packages that depend on peg