DartGrammar class
Dart grammar definition.
class DartGrammar extends CompositeParser2 { void initialize() { _whitespace(); _lexemes(); _keywords(); _types(); _declarations(); _expressions(); _statements(); _libraries(); } /** Defines the whitespace and comments. */ void _whitespace() { def('whitespace', whitespace() .or(ref('singe line comment')) .or(ref('multi line comment'))); def('singe line comment', string('//') .seq(Token.newlineParser().neg().star())); def('multi line comment', string('/*') .seq(string('*/').neg().star()) .seq(string('*/'))); } /** Defines a token parser that consumes whitespace. */ Parser _token(dynamic input) { var parser = input is Parser ? parser : input.length == 1 ? char(input) : string(input); return parser.token().trim(ref('whitespace')); } void _lexemes() { backSlash = _token('\\'); colon = _token(':'); comma = _token(','); dollar = _token('\$'); dot = _token('.'); doubleQuote = _token('"'); equalSign = _token('='); lparen = _token('('); minus = _token('-'); pluz = _token('+'); rparen = _token(')'); semicolon = _token(';'); singleQuote = _token("'"); tripleDoubleQuote = _token('"""'); tripleSingleQuote = _token("'''"); DIGIT = range('0', '9'); LETTER = letter(); HEX_DIGIT = range('a','f') | range('A','F') | DIGIT ; HEX_NUMBER = _token('0x') & HEX_DIGIT.plus() | _token('0X') & HEX_DIGIT.plus() ; EXPONENT = (_token('e') | _token('E')) & (pluz | minus).optional() & DIGIT.plus() ; NUMBER = DIGIT.plus() & (dot & DIGIT.plus()).optional() & EXPONENT.optional() | dot & DIGIT.plus() & EXPONENT.optional() ; HEX_DIGIT_SEQUENCE = HEX_DIGIT & HEX_DIGIT.optional() & HEX_DIGIT.optional() & HEX_DIGIT.optional() & HEX_DIGIT.optional() & HEX_DIGIT.optional(); ESCAPE_SEQUENCE = _token('\n') | _token('\r') | _token('\f') | _token('\b') | _token('\t') | _token('\v') | _token('\\x') & HEX_DIGIT & HEX_DIGIT | _token('\\u') & HEX_DIGIT & HEX_DIGIT & HEX_DIGIT & HEX_DIGIT | _token('\\u{') & HEX_DIGIT_SEQUENCE & _token('}') ; } void _keywords() { ASSERT = _token('assert'); BREAK = _token('break'); CASE = _token('case'); CATCH = _token('catch'); CLASS = _token('class'); CONST = _token('const'); CONTINUE = _token('continue'); DEFAULT = _token('default'); DO = _token('do'); ELSE = _token('else'); EXTENDS = _token('extends'); FALSE = _token('false'); FINAL = _token('final'); FINALLY = _token('finally'); FOR = _token('for'); IF = _token('if'); IN = _token('in'); IS = _token('is'); NEW = _token('new'); NULL = _token('null'); RETHROW = _token('rethrow'); RETURN = _token('return'); SUPER = _token('super'); SWITCH = _token('switch'); THIS = _token('this'); THROW = _token('throw'); TRUE = _token('true'); TRY = _token('try'); VAR = _token('var'); VOID = _token('void'); WHILE = _token('while'); WITH = _token('with'); // built-in identifiers ABSTRACT = _token('abstract'); AS = _token('as'); DYNAMIC = _token('dynamic'); EXPORT = _token('export'); EXTERNAL = _token('external'); FACTORY = _token('factory'); GET = _token('get'); IMPLEMENTS = _token('implements'); IMPORT = _token('import'); LIBRARY = _token('library'); OPERATOR = _token('operator'); PART = _token('part'); SET = _token('set'); STATIC = _token('static'); TYPEDEF = _token('typedef'); // special cases HIDE = _token('hide'); SHOW = _token('show'); OF = _token('of'); ON = _token('on'); } void _types() { typeArguments = _token('<') & typeList & _token('>'); typeName = qualified; type = typeName & typeArguments.optional(); typeList = type.separatedBy(comma).optional(); functionPrefix = returnType.optional() & identifier; functionTypeAlias = functionPrefix & typeParameters.optional() & formalParameterList & semicolon; typeAliasBody = identifier & typeParameters.optional() & equalSign & ABSTRACT.optional() & mixinApplication | functionTypeAlias; typeAlias = metadata & TYPEDEF & typeAliasBody; } void _declarations() { metadata = (_token('@') & qualified & (dot & identifier).optional() & arguments.optional()).star(); typeParameter = metadata & identifier & (EXTENDS & type).optional(); typeParameters = _token('<') & typeParameter.separatedBy(comma) & _token('>'); returnType = VOID | type ; varOrType = VAR | type ; finalConstVarOrType = FINAL & type.optional() | CONST & type.optional() | varOrType ; declaredIdentifier = metadata & finalConstVarOrType & identifier; variableDeclaration = declaredIdentifier.separatedBy(comma); initializedIdentifier = identifier & (equalSign & expression).optional(); initializedVariableDeclaration = declaredIdentifier & (equalSign & expression).optional() & (comma & initializedIdentifier).star(); initializedIdentifierList = initializedIdentifier.separatedBy(comma); fieldFormalParameter = metadata & finalConstVarOrType.optional() & THIS & dot & identifier; simpleFormalParameter = declaredIdentifier | metadata & identifier ; normalFormalParameter = functionSignature | fieldFormalParameter | simpleFormalParameter ; normalFormalParameters = normalFormalParameter.separatedBy(comma); defaultFormalParameter = normalFormalParameter & (equalSign & expression).optional(); defaultNamedParameter = normalFormalParameter & (colon & expression).optional(); optionalPositionalFormalParameters = _token('[') & defaultFormalParameter.separatedBy(comma) & _token(']'); optionalFormalParameters = optionalPositionalFormalParameters | namedFormalParameters ; formalParameterList = lparen & rparen | lparen & normalFormalParameters & (comma & optionalFormalParameters).optional() & rparen | lparen & optionalFormalParameters & rparen ; namedFormalParameters = _token('{') & defaultNamedParameter.separatedBy(comma) & _token('}'); functionSignature = metadata & returnType.optional() & identifier & formalParameterList; block = _token('{') & statements & _token('}'); functionBody = _token('=>') & expression & semicolon | block ; interfaces = IMPLEMENTS & typeList; superclass = EXTENDS & type; ; constantConstructorSignature = CONST & qualified & formalParameterList; redirectingFactoryConstructorSignature = CONST.optional() & FACTORY & identifier & (dot & identifier).optional() & formalParameterList & equalSign & type & (dot & identifier).optional() ; factoryConstructorSignature = FACTORY & identifier & (dot & identifier).optional() & formalParameterList ; fieldInitializer = (THIS & dot).optional() & identifier & equalSign & conditionalExpression & cascadeSection.star(); superCallOrFieldInitializer = SUPER & arguments | SUPER & dot & identifier & arguments | fieldInitializer ; initializers = colon & superCallOrFieldInitializer.separatedBy(comma); redirection = colon & THIS & (dot & identifier).optional() & arguments; constructorSignature = identifier & (dot & identifier).optional() & formalParameterList; setterSignature = returnType.optional() & SET & identifier & formalParameterList; getterSignature = type.optional() & GET & identifier; binaryOperator = multiplicativeOperator | additiveOperator | shiftOperator | relationalOperator | _token('==') | bitwiseOperator ; operator = _token('~') | binaryOperator | _token('[') & _token(']') | _token('[') & _token(']') & equalSign ; operatorSignature = returnType.optional() & OPERATOR & operator & formalParameterList; mixins = WITH & typeList; methodSignature = constructorSignature & initializers.optional() | factoryConstructorSignature | STATIC.optional() & functionSignature | STATIC.optional() & getterSignature | STATIC.optional() & setterSignature | operatorSignature ; staticFinalDeclaration = identifier & equalSign & expression; staticFinalDeclarationList = staticFinalDeclaration.separatedBy(comma); declaration = constantConstructorSignature & (redirection | initializers).optional() | constructorSignature & (redirection | initializers).optional() | EXTERNAL & constantConstructorSignature | EXTERNAL & constructorSignature | EXTERNAL & factoryConstructorSignature | (EXTERNAL & STATIC.optional()).optional() & getterSignature | (EXTERNAL & STATIC.optional()).optional() & setterSignature | EXTERNAL.optional() & operatorSignature | (EXTERNAL & STATIC.optional()).optional() & functionSignature | getterSignature | setterSignature | operatorSignature | functionSignature | STATIC & (FINAL | CONST) & type.optional() & staticFinalDeclarationList | CONST & type.optional() & staticFinalDeclarationList | FINAL & type.optional() & initializedIdentifierList | STATIC.optional() & (VAR | type) & initializedIdentifierList ; classMemberDefinition = declaration & semicolon | methodSignature & functionBody ; classDefinition = metadata & ABSTRACT.optional() & CLASS & identifier & typeParameters.optional() & (superclass & mixins.optional()).optional() & interfaces.optional() & _token('{') & (metadata & classMemberDefinition).star() & _token('}') ; mixinApplication = type & mixins & interfaces.optional(); } void _expressions() { IDENTIFIER_START_NO_DOLLAR = LETTER | _token('_') ; IDENTIFIER_START = IDENTIFIER_START_NO_DOLLAR | dollar ; IDENTIFIER_PART_NO_DOLLAR = IDENTIFIER_START_NO_DOLLAR | DIGIT ; IDENTIFIER_PART = IDENTIFIER_START | DIGIT ; IDENTIFIER_NO_DOLLAR = IDENTIFIER_START_NO_DOLLAR & IDENTIFIER_PART_NO_DOLLAR.star(); IDENTIFIER = IDENTIFIER_START & IDENTIFIER_PART.star(); identifier = IDENTIFIER.flatten().token().trim(); qualified = identifier.separatedBy(dot); assignableSelector = _token('[') & expression & _token(']') | dot & identifier ; assignableExpression = primary & (arguments.star() & assignableSelector).plus() | SUPER & assignableSelector | identifier ; incrementOperator = _token('++') | _token('--'); selector = assignableSelector | arguments; postfixOperator = incrementOperator; postfixExpression = assignableExpression & postfixOperator | primary & selector.star() ; unaryOperator = _token('!') | _token('~'); prefixOperator = minus | unaryOperator; unaryExpression = prefixOperator & unaryExpression | postfixExpression | prefixOperator & SUPER | incrementOperator & assignableExpression ; multiplicativeOperator = _token('*') | _token('/') | _token('%') | _token('~/'); multiplicativeExpression = unaryExpression & (multiplicativeOperator & unaryExpression).star() | SUPER & (multiplicativeOperator & unaryExpression).plus() ; additiveOperator = pluz | minus; additiveExpression = multiplicativeExpression & (additiveOperator & multiplicativeExpression).star() | SUPER & (additiveOperator & multiplicativeExpression).plus() ; shiftOperator = _token('<<') | _token('>>'); shiftExpression = additiveExpression & (shiftOperator & additiveExpression).star() | SUPER & (shiftOperator & additiveExpression).plus() ; relationalOperator = _token('<') | _token('>') | _token('<=') | _token('>='); relationalExpression = shiftExpression & (typeTest | typeCast | relationalOperator & shiftExpression).optional() | SUPER & relationalOperator & shiftExpression ; equalityOperator = _token('==') | _token('!='); equalityExpression = relationalExpression & (equalityOperator & relationalExpression).optional() | SUPER & equalityOperator & relationalExpression ; bitwiseOperator = _token('|') | _token('&') | _token('^'); bitwiseAndExpression = equalityExpression & (_token('&') & equalityExpression).star() | SUPER & (_token('&') & equalityExpression).plus() ; bitwiseXorExpression = bitwiseAndExpression & (_token('^') & bitwiseAndExpression).star() | SUPER & (_token('^') & bitwiseAndExpression).plus() ; bitwiseOrExpression = bitwiseXorExpression & (_token('|') & bitwiseXorExpression).star() | SUPER & (_token('|') & bitwiseXorExpression).plus() ; logicalAndExpression = bitwiseOrExpression & (_token('&&') & bitwiseOrExpression).star(); logicalOrExpression = logicalAndExpression & (_token('||') & logicalAndExpression).star(); conditionalExpression = logicalOrExpression & (_token('?') & expressionWithoutCascade & colon & expressionWithoutCascade).optional(); compoundAssignmentOperator = _token('*=') | _token('/=') | _token('~/=') | _token('%=') | _token('+=') | _token('-=') | _token('<<=') | _token('>>=') | _token('&=') | _token('^=') | _token('|=') ; assignmentOperator = equalSign | compoundAssignmentOperator; cascadeSelector = _token('[') & expression & _token(']') | identifier ; cascadeSection = _token('..') & (cascadeSelector & arguments.star()) & (assignableSelector & arguments.star()).star() & (assignmentOperator & expressionWithoutCascade).optional() ; namedArgument = label & expression; argumentList = namedArgument.separatedBy(comma) | expressionList.separatedBy(comma) ; arguments = lparen & argumentList.optional() & rparen; isOperator = IS & _token('!').optional(); typeTest = isOperator & type; typeCast = AS & type; argumentDefinitionTest = _token('?') & identifier; constObjectExpression = CONST & type & (dot & identifier).optional() & arguments; newExpression = NEW & type & (dot & identifier).optional() & arguments; thisExpression = THIS; functionExpressionBody = _token('=>') & expression | block ; functionExpression = formalParameterList & functionExpressionBody; rethrowExpression = RETHROW; throwExpression = THROW & expression; throwExpressionWithoutCascade = THROW & expressionWithoutCascade; mapLiteralEntry = stringLiteral & colon & expression; mapLiteral = CONST.optional() & typeArguments.optional() & _token('{') & (mapLiteralEntry & (dot & mapLiteralEntry).star() & comma.optional()).optional() & _token('}'); listLiteral = CONST.optional() & typeArguments.optional() & _token('[') & (expressionList & comma.optional()).optional() & _token(']'); stringInterpolation = dollar & IDENTIFIER_NO_DOLLAR | dollar & _token('{') & expression & _token('}'); NEWLINE = _token('\\n') | _token('\r'); stringContentDQ = (backSlash | doubleQuote | dollar | NEWLINE).not() | backSlash & NEWLINE.not() | stringInterpolation; stringContentSQ = (backSlash | singleQuote | dollar | NEWLINE).not() | backSlash & NEWLINE.not() | stringInterpolation; stringContentTDQ = (backSlash | tripleDoubleQuote | dollar | NEWLINE).not() | backSlash & NEWLINE.not() | stringInterpolation; stringContentTSQ = (backSlash | tripleSingleQuote | dollar | NEWLINE).not() | backSlash & NEWLINE.not() | stringInterpolation; multilineString = tripleDoubleQuote & stringContentTDQ.star() & tripleDoubleQuote | tripleSingleQuote & stringContentTSQ.star() & tripleSingleQuote | _token('r') & tripleDoubleQuote & doubleQuote.not().star() & tripleDoubleQuote | _token('r') & tripleSingleQuote & singleQuote.not().star() & tripleSingleQuote ; singleLineString = doubleQuote & stringContentDQ.star() & doubleQuote | singleQuote & stringContentSQ.star() & singleQuote | _token('r') & doubleQuote & ( doubleQuote | NEWLINE ).not().star() & doubleQuote | _token('r') & singleQuote & ( singleQuote | NEWLINE ).not().star() & singleQuote ; stringLiteral = multilineString.plus() | singleLineString.plus() ; numericLiteral = NUMBER | HEX_NUMBER ; booleanLiteral = TRUE | FALSE ; nullLiteral = NULL; literal = nullLiteral | booleanLiteral | numericLiteral | stringLiteral | mapLiteral | listLiteral ; expression = assignableExpression & assignmentOperator & expression | conditionalExpression & cascadeSection.star() | throwExpression | rethrowExpression ; expressionWithoutCascade = assignableExpression & assignmentOperator & expressionWithoutCascade | conditionalExpression | throwExpressionWithoutCascade | rethrowExpression ; expressionList = expression.separatedBy(comma); primary = thisExpression | SUPER & assignableSelector | functionExpression | literal | identifier | newExpression | constObjectExpression | lparen & expression & rparen | argumentDefinitionTest ; } void _statements() { assertStatement = ASSERT & lparen & conditionalExpression & rparen & semicolon; continueStatement = CONTINUE & identifier.optional() & semicolon; breakStatement = BREAK & identifier.optional() & semicolon; label = identifier & colon; returnStatement = RETURN & expression.optional() & semicolon; finallyPart = FINALLY & block; catchPart = CATCH & lparen & identifier & (comma & identifier).optional() & rparen; onPart = catchPart & block | ON & type & catchPart.optional() & block ; tryStatement = TRY & block & (onPart.plus() & finallyPart.optional() | finallyPart); defaultCase = label.star() & DEFAULT & colon & statements; switchCase = label.star() & (CASE & expression & colon) & statements; switchStatement = SWITCH & lparen & expression & rparen & _token('{') & switchCase.star() & defaultCase.optional() & _token('}'); doStatement = DO & statement & WHILE & lparen & expression & rparen & semicolon; whileStatement = WHILE & lparen & expression & rparen & statement; forInitializerStatement = localVariableDeclaration & semicolon | expression.optional() & semicolon ; forLoopParts = forInitializerStatement & expression.optional() & semicolon & expressionList.optional() | declaredIdentifier & IN & expression | identifier & IN & expression ; forStatement = FOR & lparen & forLoopParts & rparen & statement; ifStatement = IF & lparen & expression & rparen & statement & (ELSE & statement).optional(); localFunctionDeclaration = functionSignature & functionBody; localVariableDeclaration = initializedVariableDeclaration & semicolon; expressionStatement = expression.optional() & semicolon; nonLabelledStatement = block | localVariableDeclaration & semicolon | forStatement | whileStatement | doStatement | switchStatement | ifStatement | tryStatement | breakStatement | continueStatement | returnStatement | expressionStatement | assertStatement | localFunctionDeclaration; statement = label.star() & nonLabelledStatement; statements = statement.star(); } void _libraries() { uri = stringLiteral; getOrSet = GET | SET; topLevelDefinition = classDefinition | mixinApplication | typeAlias | EXTERNAL & functionSignature | EXTERNAL & getterSignature | EXTERNAL & setterSignature | functionSignature & functionBody | returnType.optional() & getOrSet & identifier & formalParameterList & functionBody | (FINAL | CONST) & type.optional() & staticFinalDeclarationList & semicolon | variableDeclaration & semicolon ; identifierList = identifier.separatedBy(comma).optional(); combinator = SHOW & identifierList | HIDE & identifierList; libraryImport = metadata & IMPORT & (AS & identifier).optional() & combinator.star() & semicolon; libraryExport = metadata & EXPORT & uri & combinator.star() & semicolon; importOrExport = libraryImport | libraryExport; libraryName = metadata & LIBRARY & identifier.separatedBy(dot) & semicolon; partDirective = metadata & PART & stringLiteral & semicolon; partHeader = metadata & PART & OF & identifier.separatedBy(dot) & semicolon; partDeclaration = partHeader & topLevelDefinition.star(); libraryDefinition = libraryName.optional() & importOrExport.star() & partDirective.star() & topLevelDefinition.star(); scriptTag = _token('#!') & NEWLINE.not().star() & NEWLINE; scriptDefinition = scriptTag.optional() & libraryDefinition; start = scriptDefinition.end(); } }
Extends
Parser > _DelegateParser > CompositeParser > CompositeParser2 > DartGrammar
Properties
final List<Parser> children #
Returns a list of directly referenced parsers.
For example, letter().children
returns the empty collection []
,
because the letter parser is a primitive or leaf parser that does not
depend or call any other parser.
In contrast, letter().or(digit()).children
returns a collection
containing both the letter()
and digit()
parser.
List<Parser> get children => [_delegate];
Operators
Parser operator [](String name) #
Convenience operator returning a reference to a production with
a
name. See CompositeParser.ref
for details.
Parser operator [](String name) => ref(name);
Methods
bool accept(input) #
Tests if the input can be successfully parsed.
For example, letter().plus().accept('abc')
returns true
, and
letter().plus().accept('123')
returns false
.
bool accept(dynamic input) { return parse(input).isSuccess; }
void action(String name, function(Dynamic)) #
Attaches an action
function to an existing production
name. The code
raises an UndefinedProductionError
if
name is an undefined production.
Only call this method from initialize.
The following example attaches an action returning the size of list of the previously defined list production:
action('list', (list) => list.length);
void action(String name, dynamic function(Dynamic)) { redef(name, (parser) => parser.map(function)); }
Parser and() #
Returns a parser (logical and-predicate) that succeeds whenever the receiver does, but never consumes input.
For example, the parser char('_').and().seq(identifier)
accepts
identifiers that start with an underscore character. Since the predicate
does not consume accepted input, the parser identifier
is given the
ability to process the complete identifier.
Parser and() => new _AndParser(this);
Parser copy() #
Returns a shallow copy of the receiver.
Parser copy() => new _DelegateParser(_delegate);
void def(String name, Parser parser) #
Defines a production with a name and a parser. Only call this method from initialize.
The following example defines a list production that consumes several elements separated by a comma.
def('list', ref('element').separatedBy(char(',')));
void def(String name, Parser parser) { if (_completed) { throw new CompletedParserError(); } else if (_defined.containsKey(name)) { throw new RedefinedProductionError(name); } else { _defined[name] = parser; } }
Parser end([String message = 'end of input expected']) #
Returns a parser that succeeds only if the receiver consumes the complete input, otherwise return a failure with the optional message.
For example, the parser letter().end()
succeeds on the input 'a'
and fails on 'ab'
. In contrast the parser letter()
alone would
succeed on both inputs, but not consume everything for the second input.
Parser end([String message = 'end of input expected']) { return new _EndOfInputParser(this, message); }
Parser flatten() #
Returns a parser that discards the result of the receiver, and returns a sub-string of the consumed elements in the string/list being parsed.
For example, the parser letter().plus().flatten()
returns 'abc'
for the input 'abc'
. In contrast, the parser letter().plus()
would
return ['a', 'b', 'c']
for the same input instead.
Parser flatten() => new _FlattenParser(this);
void initialize() #
Initializes the composite grammar.
void initialize() { _whitespace(); _lexemes(); _keywords(); _types(); _declarations(); _expressions(); _statements(); _libraries(); }
Parser map(Function function) #
Returns a parser that evaluates function as action handler on success of the receiver.
For example, the parser digit().map((char) => int.parse(char))
returns
the number 1
for the input string '1'
.
Parser map(Function function) => new _ActionParser(this, function);
bool match(Parser other, [Set<Parser> seen]) #
Recusively tests for the equality of two parsers.
The code can automatically deals with recursive parsers and parsers that refer to other parsers. This code is supposed to be overridden by parsers that add other state.
bool match(Parser other, [Set<Parser> seen]) { if (seen == null) { seen = new Set(); } if (this == other || seen.contains(this)) { return true; } seen.add(this); return runtimeType == other.runtimeType && _matchChildren(other, seen); }
Iterable matches(input) #
Returns a list of all successful overlapping parses of the input.
For example, letter().plus().matches('abc de')
results in the list
[['a', 'b', 'c'], ['b', 'c'], ['c'], ['d', 'e'], ['e']]
. See
Parser.matchesSkipping
to retrieve non-overlapping parse results.
Iterable matches(dynamic input) { var list = new List(); and().map((each) => list.add(each)).seq(any()).or(any()).star().parse(input); return list; }
Iterable matchesSkipping(input) #
Returns a list of all successful non-overlapping parses of the input.
For example, letter().plus().matchesSkipping('abc de')
results in the
list [['a', 'b', 'c'], ['d', 'e']]
. See Parser.matches
to retrieve
overlapping parse results.
Iterable matchesSkipping(dynamic input) { var list = new List(); map((each) => list.add(each)).or(any()).star().parse(input); return list; }
Parser neg([String message]) #
Returns a parser that consumes any input token (character), but the receiver.
For example, the parser letter().neg()
accepts any input but a letter.
The parser fails for inputs like 'a'
or 'Z'
, but succeeds for
input like '1'
, '_'
or '$'
.
Parser neg([String message]) => not(message).seq(any()).pick(1);
dynamic noSuchMethod(Invocation mirror) #
noSuchMethod
is invoked when users invoke a non-existant method
on an object. The name of the method and the arguments of the
invocation are passed to noSuchMethod
in an Invocation
.
If noSuchMethod
returns a value, that value becomes the result of
the original invocation.
The default behavior of noSuchMethod
is to throw a
noSuchMethodError
.
dynamic noSuchMethod(Invocation mirror) { String name = MirrorSystem.getName(mirror.memberName); if (!name.startsWith('_')) { if (mirror.isGetter) { return ref(name); } else if (mirror.isSetter) { return def(name.substring(0, name.length - 1), mirror.positionalArguments.first); } else if (mirror.isMethod && mirror.positionalArguments.length == 1) { var argument = mirror.positionalArguments.first; return argument is Parser ? redef(name, argument) : action(name, argument); } } return super.noSuchMethod(mirror); }
Parser not([String message]) #
Returns a parser (logical not-predicate) that succeeds whenever the receiver fails, but never consumes input.
For example, the parser char('_').not().seq(identifier)
accepts
identifiers that do not start with an underscore character. If the parser
char('_')
accepts the input, the negation and subsequently the
complete parser fails. Otherwise the parser identifier
is given the
ability to process the complete identifier.
Parser not([String message]) => new _NotParser(this, message);
Parser optional([otherwise]) #
Returns new parser that accepts the receiver, if possible. The resulting
parser returns the result of the receiver, or null
if not applicable.
The returned value can be provided as an optional argument
otherwise.
For example, the parser letter().optional()
accepts a letter as input
and returns that letter. When given something else the parser succeeds as
well, does not consume anything and returns null
.
Parser optional([dynamic otherwise]) => new _OptionalParser(this, otherwise);
Parser or(Parser other) #
Returns a parser that accepts the receiver or other. The resulting parser returns the parse result of the receiver, if the receiver fails it returns the parse result of other (exclusive ordered choice).
For example, the parser letter().or(digit())
accepts a letter or a
digit. An example where the order matters is the following choice between
overlapping parsers: letter().or(char('a'))
. In the example the parser
char('a')
will never be activated, because the input is always consumed
letter()
. This can be problematic if the author intended to attach a
production action to char('a')
.
Parser or(Parser other) => new _ChoiceParser([this, other]);
Result parse(input) #
Returns the parse result of the input.
The implementation creates a default parse context on the input and calls the internal parsing logic of the receiving parser.
For example, letter().plus().parse('abc')
results in an instance of
Success
, where Result.position
is 3
and Success.value
is
[a, b, c]
.
Similarly, letter().plus().parse('123')
results in an instance of
Failure
, where Result.position
is 0
and Failure.message
is
'letter expected'
.
Result parse(dynamic input) { return _parse(new Context(input, 0)); }
Parser permute(List<int> indexes) #
Returns a parser that transforms a successful parse result by returning the permuted elements at indexes of a list. Negative indexes can be used to access the elements from the back of the list.
For example, the parser letter().star().permute([0, -1])
returns the
first and last letter parsed. For the input 'abc'
it returns
['a', 'c']
.
Parser permute(List<int> indexes) { return this.map((List list) { return indexes.map((index) { return list[index < 0 ? list.length + index : index]; }).toList(); }); }
Parser pick(int index) #
Returns a parser that transform a successful parse result by returning the element at index of a list. A negative index can be used to access the elements from the back of the list.
For example, the parser letter().star().pick(-1)
returns the last
letter parsed. For the input 'abc'
it returns 'c'
.
Parser pick(int index) { return this.map((List list) { return list[index < 0 ? list.length + index : index]; }); }
Parser plus() #
Returns a parser that accepts the receiver one or more times. The resulting parser returns a list of the parse results of the receiver.
This is a greedy and blind implementation that tries to consume as much input as possible and that does not consider what comes afterwards.
For example, the parser letter().plus()
accepts any sequence of
letters and returns a list of the parsed letters.
Parser plus() => repeat(1, 65536);
void redef(String name, replacement) #
Redefinies an existing production with a
name and a
replacement
parser or function producing a new parser. The code raises an
UndefinedProductionError
if
name is an undefined production. Only call
this method from initialize.
The following example redefines the previously defined list production by making it optional:
redef('list', (parser) => parser.optional());
void redef(String name, dynamic replacement) { if (_completed) { throw new CompletedParserError(); } else if (!_defined.containsKey(name)) { throw new UndefinedProductionError(name); } else { _defined[name] = replacement is Parser ? replacement : replacement(_defined[name]); } }
Parser ref(String name) #
Returns a reference to a production with a name.
This method works during initialization and after completion of the initialization. During the initialization it returns delegate parsers that are eventually replaced by the real parsers. Afterwards it returns the defined parser (mostly useful for testing).
Parser ref(String name) { if (_completed) { if (_defined.containsKey(name)) { return _defined[name]; } else { throw new UndefinedProductionError(name); } } else { return _undefined.putIfAbsent(name, () { return failure('Uninitalized production: $name').setable(); }); } }
Parser repeat(int min, int max) #
Returns a parser that accepts the receiver between min and max times. The resulting parser returns a list of the parse results of the receiver.
This is a greedy and blind implementation that tries to consume as much input as possible and that does not consider what comes afterwards.
For example, the parser letter().repeat(2, 4)
accepts a sequence of
two, three, or four letters and returns the accepted letters as a list.
Parser repeat(int min, int max) => new _RepeatingParser(this, min, max);
void replace(Parser source, Parser target) #
Changes the receiver by replacing
source with
target. Does nothing
if
source does not exist in Parser.children
.
The following example creates a letter parser and then defines a parser
called example
that accepts one or more letters. Eventually the parser
example
is modified by replacing the letter
parser with a new
parser that accepts a digit. The resulting example
parser accepts one
or more digits.
var letter = letter();
var example = letter.plus();
example.replace(letter, digit());
void replace(Parser source, Parser target) { super.replace(source, target); if (_delegate == source) { _delegate = target; } }
Parser separatedBy(Parser separator, {bool includeSeparators: true, bool optionalSeparatorAtEnd: false}) #
Returns a parser that consumes the receiver one or more times separated by the separator parser. The resulting parser returns a flat list of the parse results of the receiver interleaved with the parse result of the separator parser.
If the optional argument
includeSeparators is set to false
, then the
separators are not included in the parse result. If the optional argument
optionalSeparatorAtEnd is set to true
the parser also accepts an
optional separator at the end.
For example, the parser digit().separatedBy(char('-'))
returns a parser
that consumes input like '1-2-3'
and returns a list of the elements and
separators: ['1', '-', '2', '-', '3']
.
Parser separatedBy(Parser separator, {bool includeSeparators: true, bool optionalSeparatorAtEnd: false}) { var repeater = new _SequenceParser([separator, this]).star(); var parser = new _SequenceParser(optionalSeparatorAtEnd ? [this, repeater, separator.optional(separator)] : [this, repeater]); return parser.map((List list) { var result = new List(); result.add(list[0]); for (var tuple in list[1]) { if (includeSeparators) { result.add(tuple[0]); } result.add(tuple[1]); } if (includeSeparators && optionalSeparatorAtEnd && !identical(list[2], separator)) { result.add(list[2]); } return result; }); }
Parser seq(Parser other) #
Returns a parser that accepts the receiver followed by other. The resulting parser returns a list of the parse result of the receiver followed by the parse result of other. Calling this method on an existing sequence code not nest this sequence into a new one, but instead augments the existing sequence with other.
For example, the parser letter().seq(digit()).seq(letter())
accepts a
letter followed by a digit and another letter. The parse result of the
input string 'a1b'
is the list ['a', '1', 'b']
.
Parser seq(Parser other) => new _SequenceParser([this, other]);
SetableParser setable() #
Returns a parser that points to the receiver, but can be changed to point to something else at a later point in time.
For example, the parser letter().setable()
behaves exactly the same
as letter()
, but it can be replaced with another parser using
SetableParser.set
.
SetableParser setable() => new _SetableParser(this);
Parser star() #
Returns a parser that accepts the receiver zero or more times. The resulting parser returns a list of the parse results of the receiver.
This is a greedy and blind implementation that tries to consume as much input as possible and that does not consider what comes afterwards.
For example, the parser letter().star()
accepts the empty string or
any sequence of letters and returns a possibly empty list of the parsed
letters.
Parser star() => repeat(0, 65536);
Parser times(int count) #
Returns a parser that accepts the receiver exactly count times. The resulting parser returns a list of the parse results of the receiver.
For example, the parser letter().times(2)
accepts two letters and
returns a list of the two parsed letters.
Parser times(int count) => repeat(count, count);
Parser token() #
Returns a parser that discards the result of the receiver and returns
a Token
. The token carries information about where the token started and
stopped in the input stream.
For example, the parser letter().plus().token()
returns the token
Token[start: 0, stop: 3, value: abc]
for the input 'abc'
.
Parser token() => new _TokenParser(this);
Parser trim([Parser trimmer]) #
Returns a parser that consumes input before and after the receiver. The
optional argument
trimmer is a parser that consumes the excess input. By
default whitespace()
is used.
For example, the parser letter().plus().trim()
returns ['a', 'b']
for the input ' ab\n'
and consumes the complete input string.
Parser trim([Parser trimmer]) { return new _TrimmingParser(this, trimmer == null ? whitespace() : trimmer); }