bread-n-butter
Advanced tools
Comparing version 0.4.1 to 0.6.0
@@ -8,2 +8,23 @@ # Changelog | ||
## [0.6.0] - 2020-11-18 | ||
### Changed | ||
- `bnb.choice` now automatically detects the correct union type when using | ||
parsers of many different types (thanks [@seanchas116]) | ||
## [0.5.0] - 2020-11-17 | ||
### Changed | ||
- Method `parser.many0()` is now `parser.repeat()` | ||
- Method `parser.many1()` is now `parser.repeat(1)` | ||
- Method `parser.sepBy0(separator)` is now `parser.sepBy(separator)` | ||
- Method `parser.sepBy1(separator)` is now `parser.sepBy(separator, 1)` | ||
### Added | ||
- Method `parser.repeat(min = 0, max = Infinity)` (thanks [@seanchas116]) | ||
- Method `parser.sepBy(separator, min = 0, max = Infinity)` (thanks [@seanchas116]) | ||
## [0.4.1] - 2020-09-26 | ||
@@ -57,3 +78,2 @@ | ||
[@sveyret]: https://github.com/sveyret | ||
## Unreleased | ||
[@seanchas116]: https://github.com/seanchas116 |
@@ -64,22 +64,12 @@ /** | ||
/** | ||
* Repeats the current parser zero or more times, yielding the results in an | ||
* array. | ||
* Repeats the current parser between min and max times, yielding the results | ||
* in an array. | ||
*/ | ||
many0(): Parser<A[]>; | ||
repeat(min?: number, max?: number): Parser<A[]>; | ||
/** | ||
* Parsers the current parser **one** or more times. See `many0` for more | ||
* details. | ||
*/ | ||
many1(): Parser<A[]>; | ||
/** | ||
* Returns a parser that parses zero or more times, separated by the separator | ||
* Returns a parser that parses between min and max times, separated by the separator | ||
* parser supplied. | ||
*/ | ||
sepBy0<B>(separator: Parser<B>): Parser<A[]>; | ||
sepBy<B>(separator: Parser<B>, min?: number, max?: number): Parser<A[]>; | ||
/** | ||
* Returns a parser that parses one or more times, separated by the separator | ||
* parser supplied. | ||
*/ | ||
sepBy1<B>(separator: Parser<B>): Parser<A[]>; | ||
/** | ||
* Returns a parser that adds name and start/end location metadata. | ||
@@ -130,3 +120,3 @@ */ | ||
/** Parse using the parsers given, returning the first one that succeeds. */ | ||
export declare function choice<A>(...parsers: Parser<A>[]): Parser<A>; | ||
export declare function choice<Parsers extends Parser<any>[]>(...parsers: Parsers): Parser<ReturnType<Parsers[number]["tryParse"]>>; | ||
/** | ||
@@ -133,0 +123,0 @@ * Takes a lazily invoked callback that returns a parser, so you can create |
@@ -143,13 +143,12 @@ "use strict"; | ||
/** | ||
* Repeats the current parser zero or more times, yielding the results in an | ||
* array. | ||
* Repeats the current parser between min and max times, yielding the results | ||
* in an array. | ||
*/ | ||
many0() { | ||
return this.many1().or(ok([])); | ||
} | ||
/** | ||
* Parsers the current parser **one** or more times. See `many0` for more | ||
* details. | ||
*/ | ||
many1() { | ||
repeat(min = 0, max = Infinity) { | ||
if (!isRangeValid(min, max)) { | ||
throw new Error(`repeat: bad range (${min} to ${max})`); | ||
} | ||
if (min === 0) { | ||
return this.repeat(1, max).or(ok([])); | ||
} | ||
return new Parser((context) => { | ||
@@ -161,6 +160,6 @@ const items = []; | ||
} | ||
while (result.type === "ActionOK") { | ||
while (result.type === "ActionOK" && items.length < max) { | ||
items.push(result.value); | ||
if (result.location.index === context.location.index) { | ||
throw new Error("infinite loop detected; don't call many0 or many1 with parsers that can accept zero characters"); | ||
throw new Error("infinite loop detected; don't call .repeat() with parsers that can accept zero characters"); | ||
} | ||
@@ -170,2 +169,5 @@ context = context.moveTo(result.location); | ||
} | ||
if (result.type === "ActionFail" && items.length < min) { | ||
return result; | ||
} | ||
return context.merge(result, context.ok(context.location.index, items)); | ||
@@ -175,17 +177,21 @@ }); | ||
/** | ||
* Returns a parser that parses zero or more times, separated by the separator | ||
* Returns a parser that parses between min and max times, separated by the separator | ||
* parser supplied. | ||
*/ | ||
sepBy0(separator) { | ||
return this.sepBy1(separator).or(ok([])); | ||
} | ||
/** | ||
* Returns a parser that parses one or more times, separated by the separator | ||
* parser supplied. | ||
*/ | ||
sepBy1(separator) { | ||
sepBy(separator, min = 0, max = Infinity) { | ||
if (!isRangeValid(min, max)) { | ||
throw new Error(`sepBy: bad range (${min} to ${max})`); | ||
} | ||
if (min === 0) { | ||
return this.sepBy(separator, 1, max).or(ok([])); | ||
} | ||
// We also know that min=1 due to previous checks, so we can skip the call | ||
// to `repeat` here | ||
if (max === 1) { | ||
return this.map((x) => [x]); | ||
} | ||
return this.chain((first) => { | ||
return separator | ||
.next(this) | ||
.many0() | ||
.repeat(min - 1, max - 1) | ||
.map((rest) => { | ||
@@ -207,2 +213,10 @@ return [first, ...rest]; | ||
exports.Parser = Parser; | ||
function isRangeValid(min, max) { | ||
return (min <= max && | ||
min >= 0 && | ||
max >= 0 && | ||
Number.isInteger(min) && | ||
min !== Infinity && | ||
(Number.isInteger(max) || max === Infinity)); | ||
} | ||
/** | ||
@@ -209,0 +223,0 @@ * Parser that yields the current `SourceLocation`, containing properties |
@@ -64,22 +64,12 @@ /** | ||
/** | ||
* Repeats the current parser zero or more times, yielding the results in an | ||
* array. | ||
* Repeats the current parser between min and max times, yielding the results | ||
* in an array. | ||
*/ | ||
many0(): Parser<A[]>; | ||
repeat(min?: number, max?: number): Parser<A[]>; | ||
/** | ||
* Parsers the current parser **one** or more times. See `many0` for more | ||
* details. | ||
*/ | ||
many1(): Parser<A[]>; | ||
/** | ||
* Returns a parser that parses zero or more times, separated by the separator | ||
* Returns a parser that parses between min and max times, separated by the separator | ||
* parser supplied. | ||
*/ | ||
sepBy0<B>(separator: Parser<B>): Parser<A[]>; | ||
sepBy<B>(separator: Parser<B>, min?: number, max?: number): Parser<A[]>; | ||
/** | ||
* Returns a parser that parses one or more times, separated by the separator | ||
* parser supplied. | ||
*/ | ||
sepBy1<B>(separator: Parser<B>): Parser<A[]>; | ||
/** | ||
* Returns a parser that adds name and start/end location metadata. | ||
@@ -130,3 +120,3 @@ */ | ||
/** Parse using the parsers given, returning the first one that succeeds. */ | ||
export declare function choice<A>(...parsers: Parser<A>[]): Parser<A>; | ||
export declare function choice<Parsers extends Parser<any>[]>(...parsers: Parsers): Parser<ReturnType<Parsers[number]["tryParse"]>>; | ||
/** | ||
@@ -133,0 +123,0 @@ * Takes a lazily invoked callback that returns a parser, so you can create |
@@ -140,13 +140,12 @@ /** | ||
/** | ||
* Repeats the current parser zero or more times, yielding the results in an | ||
* array. | ||
* Repeats the current parser between min and max times, yielding the results | ||
* in an array. | ||
*/ | ||
many0() { | ||
return this.many1().or(ok([])); | ||
} | ||
/** | ||
* Parsers the current parser **one** or more times. See `many0` for more | ||
* details. | ||
*/ | ||
many1() { | ||
repeat(min = 0, max = Infinity) { | ||
if (!isRangeValid(min, max)) { | ||
throw new Error(`repeat: bad range (${min} to ${max})`); | ||
} | ||
if (min === 0) { | ||
return this.repeat(1, max).or(ok([])); | ||
} | ||
return new Parser((context) => { | ||
@@ -158,6 +157,6 @@ const items = []; | ||
} | ||
while (result.type === "ActionOK") { | ||
while (result.type === "ActionOK" && items.length < max) { | ||
items.push(result.value); | ||
if (result.location.index === context.location.index) { | ||
throw new Error("infinite loop detected; don't call many0 or many1 with parsers that can accept zero characters"); | ||
throw new Error("infinite loop detected; don't call .repeat() with parsers that can accept zero characters"); | ||
} | ||
@@ -167,2 +166,5 @@ context = context.moveTo(result.location); | ||
} | ||
if (result.type === "ActionFail" && items.length < min) { | ||
return result; | ||
} | ||
return context.merge(result, context.ok(context.location.index, items)); | ||
@@ -172,17 +174,21 @@ }); | ||
/** | ||
* Returns a parser that parses zero or more times, separated by the separator | ||
* Returns a parser that parses between min and max times, separated by the separator | ||
* parser supplied. | ||
*/ | ||
sepBy0(separator) { | ||
return this.sepBy1(separator).or(ok([])); | ||
} | ||
/** | ||
* Returns a parser that parses one or more times, separated by the separator | ||
* parser supplied. | ||
*/ | ||
sepBy1(separator) { | ||
sepBy(separator, min = 0, max = Infinity) { | ||
if (!isRangeValid(min, max)) { | ||
throw new Error(`sepBy: bad range (${min} to ${max})`); | ||
} | ||
if (min === 0) { | ||
return this.sepBy(separator, 1, max).or(ok([])); | ||
} | ||
// We also know that min=1 due to previous checks, so we can skip the call | ||
// to `repeat` here | ||
if (max === 1) { | ||
return this.map((x) => [x]); | ||
} | ||
return this.chain((first) => { | ||
return separator | ||
.next(this) | ||
.many0() | ||
.repeat(min - 1, max - 1) | ||
.map((rest) => { | ||
@@ -203,2 +209,10 @@ return [first, ...rest]; | ||
} | ||
function isRangeValid(min, max) { | ||
return (min <= max && | ||
min >= 0 && | ||
max >= 0 && | ||
Number.isInteger(min) && | ||
min !== Infinity && | ||
(Number.isInteger(max) || max === Infinity)); | ||
} | ||
/** | ||
@@ -205,0 +219,0 @@ * Parser that yields the current `SourceLocation`, containing properties |
{ | ||
"name": "bread-n-butter", | ||
"version": "0.4.1", | ||
"version": "0.6.0", | ||
"description": "Parser combinators for JavaScript and TypeScript", | ||
@@ -5,0 +5,0 @@ "main": "dist/cjs/bread-n-butter.js", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
46233
1275