Implement 'trailing' parameter for repeat() parser

This commit is contained in:
Sam Atkins
2024-05-24 13:29:26 +01:00
parent 837ec68371
commit 873dee7e51

View File

@@ -73,7 +73,7 @@ export class Optional extends Parser {
/**
* Parses a repeated sequence of values with separators between them.
* @param value_parser Parser for the value
* @param separator_parser Parser for the separator
* @param separator_parser Parser for the separator, optional
* @param trailing Whether to allow a trailing separator
*/
export class Repeat extends Parser {
@@ -85,40 +85,49 @@ export class Repeat extends Parser {
_parse (stream) {
const results = [];
for ( ;; ) {
const subStream = stream.fork();
const subStream = stream.fork();
// Value
const result = this.value_parser.parse(subStream);
if ( result.status === UNRECOGNIZED ) {
break;
}
if ( result.status === INVALID ) {
return { status: INVALID, value: result };
}
// Parse first value
const result = this.value_parser.parse(subStream);
if ( result.status === INVALID )
return { status: INVALID, value: result };
if ( result.status === VALUE ) {
stream.join(subStream);
if ( ! result.$discard ) results.push(result);
if (!result.$discard) results.push(result);
// Separator
if ( ! this.separator_parser ) {
continue;
}
const separatorResult = this.separator_parser.parse(subStream);
if ( separatorResult.status === UNRECOGNIZED ) {
break;
}
if ( separatorResult.status === INVALID ) {
return { status: INVALID, value: separatorResult };
}
stream.join(subStream);
if ( ! result.$discard ) results.push(separatorResult);
// Repeatedly parse <separator> <value>
for (;;) {
// Separator
if (!this.separator_parser)
continue;
// TODO: Detect trailing separator and reject it if trailing==false
const separatorResult = this.separator_parser.parse(subStream);
if (separatorResult.status === UNRECOGNIZED)
break;
if (separatorResult.status === INVALID)
return { status: INVALID, value: separatorResult };
stream.join(subStream);
if (!separatorResult.$discard) results.push(separatorResult);
// Value
const result = this.value_parser.parse(subStream);
if (result.status === UNRECOGNIZED) {
// If we failed to parse a value, we have a trailing separator
if (this.trailing === false)
return { status: INVALID, value: result };
break;
}
if (result.status === INVALID)
return { status: INVALID, value: result };
stream.join(subStream);
if (!result.$discard) results.push(result);
}
}
if ( results.length === 0 ) {
if ( results.length === 0 )
return UNRECOGNIZED;
}
return { status: VALUE, value: results };
}