first commit
This commit is contained in:
46
node_modules/peberminta/CHANGELOG.md
generated
vendored
Normal file
46
node_modules/peberminta/CHANGELOG.md
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
# Changelog
|
||||
|
||||
## Version 0.9.0
|
||||
|
||||
- many functions got overloads for `Matcher` type propagation in less common scenarios;
|
||||
- `condition` function now accepts Parsers/Matchers with different value types, result value type is the union of the two;
|
||||
- added type tests for overloads using [expect-type](https://github.com/mmkal/expect-type).
|
||||
|
||||
## Version 0.8.0
|
||||
|
||||
- Targeting Node.js version 14 and ES2020;
|
||||
- Now should be discoverable with [denoify](https://github.com/garronej/denoify).
|
||||
|
||||
## Version 0.7.0
|
||||
|
||||
- `otherwise` function now has two overloads - `Parser * Matcher -> Matcher` and `Parser * Parser -> Parser`;
|
||||
- `otherwise` function now accepts Parsers/Matchers with different value types, result value type is the union of the two;
|
||||
- `otherwise` function now has an alias called `eitherOr` which might be more natural for combining parsers.
|
||||
|
||||
## Version 0.6.0
|
||||
|
||||
- ensure local imports have file extensions - fix "./core module cannot be found" issue.
|
||||
|
||||
## Version 0.5.4
|
||||
|
||||
- remove terser, source-map files;
|
||||
- use only `rollup-plugin-cleanup` to condition published files.
|
||||
|
||||
## Version 0.5.3
|
||||
|
||||
- source-map files;
|
||||
- minor documentation update.
|
||||
|
||||
## Version 0.5.2
|
||||
|
||||
- `peek` function keeps Parser/Matcher distinction;
|
||||
|
||||
## Version 0.5.1
|
||||
|
||||
- documentation updates;
|
||||
- package marked as free of side effects for tree shaking.
|
||||
|
||||
## Version 0.5.0
|
||||
|
||||
- Initial release;
|
||||
- Aiming at Node.js version 12 and up.
|
21
node_modules/peberminta/LICENSE
generated
vendored
Normal file
21
node_modules/peberminta/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021-2022 KillyMXI <killy@mxii.eu.org>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
212
node_modules/peberminta/README.md
generated
vendored
Normal file
212
node_modules/peberminta/README.md
generated
vendored
Normal file
@@ -0,0 +1,212 @@
|
||||
# peberminta
|
||||
|
||||

|
||||

|
||||
[](https://codecov.io/gh/mxxii/peberminta)
|
||||
[](https://github.com/mxxii/peberminta/blob/main/LICENSE)
|
||||
[](https://www.npmjs.com/package/peberminta)
|
||||
[](https://www.npmjs.com/package/peberminta)
|
||||
[](https://deno.land/x/peberminta)
|
||||
|
||||
Simple, transparent parser combinators toolkit that supports tokens of any type.
|
||||
|
||||
For when you wanna do weird things with parsers.
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
- **Well typed** - written in TypeScript and with a lot of attention to keep types well defined.
|
||||
|
||||
- **Highly generic** - no constraints on tokens, options (additional state data) and output types. Core module has not a single mention of strings as a part of normal flow. Some string-specific building blocks can be loaded from a separate module in case you need them.
|
||||
|
||||
- **Transparent**. Built on a very simple base idea - just a few type aliases. Whole parser state is accessible at any time.
|
||||
|
||||
- **Lightweight**. Zero dependencies. Just type aliases and functions.
|
||||
|
||||
- **Batteries included** - comes with a pretty big set of building blocks.
|
||||
|
||||
- **Easy to extend** - just follow the convention defined by type aliases when making your own building blocks. *(And maybe let me know what you think can be universally useful to be included in the package itself.)*
|
||||
|
||||
- **Easy to make configurable parsers**. Rather than dynamically composing parsers based on options or manually weaving options into a dynamic parser state, this package offers a standard way to treat options as a part of static data and access them at any moment for course correction.
|
||||
|
||||
- **Well tested** - comes with tests for everything including examples.
|
||||
|
||||
- **Practicality over "purity"**. To be understandable and self-consistent is more important than to follow an established encoding of abstract ideas. More on this below.
|
||||
|
||||
- **No streaming** - accepts a fixed array of tokens. It is simple, whole input can be accessed at any time if needed. More on this below.
|
||||
|
||||
- **Bring your own lexer/tokenizer** - if you need it. It doesn't matter how tokens are made - this package can consume anything you can type. I have a lexer as well, called [leac](https://github.com/mxxii/leac), and it is used in some examples, but there is nothing special about it to make it the best match (well, maybe the fact it is written in TypeScript, has equal level of maintenance and is made with arrays instead of iterators in mind as well).
|
||||
|
||||
|
||||
## Changelog
|
||||
|
||||
Available here: [CHANGELOG.md](https://github.com/mxxii/peberminta/blob/main/CHANGELOG.md)
|
||||
|
||||
|
||||
## Install
|
||||
|
||||
### Node
|
||||
|
||||
```shell
|
||||
> npm i peberminta
|
||||
```
|
||||
|
||||
```ts
|
||||
import * as p from 'peberminta';
|
||||
import * as pc from 'peberminta/char';
|
||||
```
|
||||
|
||||
### Deno
|
||||
|
||||
```ts
|
||||
import * as p from 'https://deno.land/x/peberminta@.../core.ts';
|
||||
import * as pc from 'https://deno.land/x/peberminta@.../char.ts';
|
||||
```
|
||||
|
||||
|
||||
## Examples
|
||||
|
||||
- [JSON](https://github.com/mxxii/peberminta/blob/main/examples/json.ts);
|
||||
- [CSV](https://github.com/mxxii/peberminta/blob/main/examples/csv.ts);
|
||||
- [Hex Color](https://github.com/mxxii/peberminta/blob/main/examples/hexColor.ts);
|
||||
- [Calc](https://github.com/mxxii/peberminta/blob/main/examples/calc.ts);
|
||||
- [Brainfuck](https://github.com/mxxii/peberminta/blob/main/examples/bf1.ts) (and [another implementation](https://github.com/mxxii/peberminta/blob/main/examples/bf2.ts));
|
||||
- [Non-decreasing sequences](https://github.com/mxxii/peberminta/blob/main/examples/nonDec.ts);
|
||||
- *feel free to PR or request interesting compact grammar examples.*
|
||||
|
||||
### Published packages using `peberminta`
|
||||
|
||||
- [aspargvs](https://github.com/mxxii/aspargvs) - arg parser, CLI wrapper
|
||||
- [parseley](https://github.com/mxxii/parseley) - CSS selectors parser
|
||||
|
||||
|
||||
## API
|
||||
|
||||
Detailed API documentation with navigation and search:
|
||||
|
||||
- [core module](https://mxxii.github.io/peberminta/modules/core.html);
|
||||
- [char module](https://mxxii.github.io/peberminta/modules/char.html).
|
||||
|
||||
### Convention
|
||||
|
||||
Whole package is built around these type aliases:
|
||||
|
||||
```typescript
|
||||
export type Data<TToken,TOptions> = {
|
||||
tokens: TToken[],
|
||||
options: TOptions
|
||||
};
|
||||
|
||||
export type Parser<TToken,TOptions,TValue> =
|
||||
(data: Data<TToken,TOptions>, i: number) => Result<TValue>;
|
||||
|
||||
export type Matcher<TToken,TOptions,TValue> =
|
||||
(data: Data<TToken,TOptions>, i: number) => Match<TValue>;
|
||||
|
||||
export type Result<TValue> = Match<TValue> | NonMatch;
|
||||
|
||||
export type Match<TValue> = {
|
||||
matched: true,
|
||||
position: number,
|
||||
value: TValue
|
||||
};
|
||||
|
||||
export type NonMatch = {
|
||||
matched: false
|
||||
};
|
||||
```
|
||||
|
||||
- **Data** object holds tokens array and possibly an options object - it's just a container for all static data used by a parser. Parser position, on the other hand, has it's own life cycle and passed around separately.
|
||||
|
||||
- A **Parser** is a function that accepts Data object and a parser position, looks into the tokens array at the given position and returns either a Match with a parsed value (use `null` if there is no value) and a new position or a NonMatch.
|
||||
|
||||
- A **Matcher** is a special case of Parser that never fails and always returns a Match.
|
||||
|
||||
- **Result** object from a Parser can be either a Match or a NonMatch.
|
||||
|
||||
- **Match** is a result of successful parsing - it contains a parsed value and a new parser position.
|
||||
|
||||
- **NonMatch** is a result of unsuccessful parsing. It doesn't have any data attached to it.
|
||||
|
||||
- **TToken** can be any type.
|
||||
|
||||
- **TOptions** can be any type. Use it to make your parser customizable. Or set it as `undefined` and type as `unknown` if not needed.
|
||||
|
||||
### Building blocks
|
||||
|
||||
#### Core blocks
|
||||
|
||||
<div class="headlessTable">
|
||||
|
||||
| <!-- --> | <!-- --> | <!-- --> | <!-- -->
|
||||
| -------- | -------- | -------- | --------
|
||||
| [ab](https://mxxii.github.io/peberminta/modules/core.html#ab) | [abc](https://mxxii.github.io/peberminta/modules/core.html#abc) | [action](https://mxxii.github.io/peberminta/modules/core.html#action) | [ahead](https://mxxii.github.io/peberminta/modules/core.html#ahead)
|
||||
| [all](https://mxxii.github.io/peberminta/modules/core.html#all) | _[and](https://mxxii.github.io/peberminta/modules/core.html#and)_ | [any](https://mxxii.github.io/peberminta/modules/core.html#any) | [chain](https://mxxii.github.io/peberminta/modules/core.html#chain)
|
||||
| [chainReduce](https://mxxii.github.io/peberminta/modules/core.html#chainReduce) | [choice](https://mxxii.github.io/peberminta/modules/core.html#choice) | [condition](https://mxxii.github.io/peberminta/modules/core.html#condition) | [decide](https://mxxii.github.io/peberminta/modules/core.html#decide)
|
||||
| _[discard](https://mxxii.github.io/peberminta/modules/core.html#discard)_ | _[eitherOr](https://mxxii.github.io/peberminta/modules/core.html#eitherOr)_ | [emit](https://mxxii.github.io/peberminta/modules/core.html#emit) | [end](https://mxxii.github.io/peberminta/modules/core.html#end)
|
||||
| _[eof](https://mxxii.github.io/peberminta/modules/core.html#eof)_ | [error](https://mxxii.github.io/peberminta/modules/core.html#error) | [fail](https://mxxii.github.io/peberminta/modules/core.html#fail) | [flatten](https://mxxii.github.io/peberminta/modules/core.html#flatten)
|
||||
| [flatten1](https://mxxii.github.io/peberminta/modules/core.html#flatten1) | [left](https://mxxii.github.io/peberminta/modules/core.html#left) | [leftAssoc1](https://mxxii.github.io/peberminta/modules/core.html#leftAssoc1) | [leftAssoc2](https://mxxii.github.io/peberminta/modules/core.html#leftAssoc2)
|
||||
| [longest](https://mxxii.github.io/peberminta/modules/core.html#longest) | _[lookAhead](https://mxxii.github.io/peberminta/modules/core.html#lookAhead)_ | [make](https://mxxii.github.io/peberminta/modules/core.html#make) | [many](https://mxxii.github.io/peberminta/modules/core.html#many)
|
||||
| [many1](https://mxxii.github.io/peberminta/modules/core.html#many1) | [map](https://mxxii.github.io/peberminta/modules/core.html#map) | [map1](https://mxxii.github.io/peberminta/modules/core.html#map1) | [middle](https://mxxii.github.io/peberminta/modules/core.html#middle)
|
||||
| [not](https://mxxii.github.io/peberminta/modules/core.html#not) | _[of](https://mxxii.github.io/peberminta/modules/core.html#of)_ | [option](https://mxxii.github.io/peberminta/modules/core.html#option) | _[or](https://mxxii.github.io/peberminta/modules/core.html#or)_
|
||||
| [otherwise](https://mxxii.github.io/peberminta/modules/core.html#otherwise) | [peek](https://mxxii.github.io/peberminta/modules/core.html#peek) | [recursive](https://mxxii.github.io/peberminta/modules/core.html#recursive) | [reduceLeft](https://mxxii.github.io/peberminta/modules/core.html#reduceLeft)
|
||||
| [reduceRight](https://mxxii.github.io/peberminta/modules/core.html#reduceRight) | [right](https://mxxii.github.io/peberminta/modules/core.html#right) | [rightAssoc1](https://mxxii.github.io/peberminta/modules/core.html#rightAssoc1) | [rightAssoc2](https://mxxii.github.io/peberminta/modules/core.html#rightAssoc2)
|
||||
| [satisfy](https://mxxii.github.io/peberminta/modules/core.html#satisfy) | [sepBy](https://mxxii.github.io/peberminta/modules/core.html#sepBy) | [sepBy1](https://mxxii.github.io/peberminta/modules/core.html#sepBy1) | [skip](https://mxxii.github.io/peberminta/modules/core.html#skip)
|
||||
| _[some](https://mxxii.github.io/peberminta/modules/core.html#some)_ | [start](https://mxxii.github.io/peberminta/modules/core.html#start) | [takeUntil](https://mxxii.github.io/peberminta/modules/core.html#takeUntil) | [takeUntilP](https://mxxii.github.io/peberminta/modules/core.html#takeUntilP)
|
||||
| [takeWhile](https://mxxii.github.io/peberminta/modules/core.html#takeWhile) | [takeWhileP](https://mxxii.github.io/peberminta/modules/core.html#takeWhileP) | [token](https://mxxii.github.io/peberminta/modules/core.html#token)
|
||||
|
||||
</div>
|
||||
|
||||
#### Core utilities
|
||||
|
||||
<div class="headlessTable">
|
||||
|
||||
| <!-- --> | <!-- --> | <!-- --> | <!-- -->
|
||||
| -------- | -------- | -------- | --------
|
||||
| [match](https://mxxii.github.io/peberminta/modules/core.html#match) | [parse](https://mxxii.github.io/peberminta/modules/core.html#parse) | [parserPosition](https://mxxii.github.io/peberminta/modules/core.html#parserPosition) | [remainingTokensNumber](https://mxxii.github.io/peberminta/modules/core.html#remainingTokensNumber)
|
||||
| [tryParse](https://mxxii.github.io/peberminta/modules/char.html#tryParse)
|
||||
|
||||
</div>
|
||||
|
||||
#### Char blocks
|
||||
|
||||
<div class="headlessTable">
|
||||
|
||||
| <!-- --> | <!-- --> | <!-- --> | <!-- -->
|
||||
| -------- | -------- | -------- | --------
|
||||
| _[anyOf](https://mxxii.github.io/peberminta/modules/char.html#anyOf)_ | [char](https://mxxii.github.io/peberminta/modules/char.html#char) | [charTest](https://mxxii.github.io/peberminta/modules/char.html#charTest) | [concat](https://mxxii.github.io/peberminta/modules/char.html#concat)
|
||||
| [noneOf](https://mxxii.github.io/peberminta/modules/char.html#noneOf) | [oneOf](https://mxxii.github.io/peberminta/modules/char.html#oneOf) | [str](https://mxxii.github.io/peberminta/modules/char.html#str)
|
||||
|
||||
</div>
|
||||
|
||||
#### Char utilities
|
||||
|
||||
<div class="headlessTable">
|
||||
|
||||
| <!-- --> | <!-- --> | <!-- --> | <!-- -->
|
||||
| -------- | -------- | -------- | --------
|
||||
| [match](https://mxxii.github.io/peberminta/modules/char.html#match) | [parse](https://mxxii.github.io/peberminta/modules/char.html#parse) | [parserPosition](https://mxxii.github.io/peberminta/modules/char.html#parserPosition) | [tryParse](https://mxxii.github.io/peberminta/modules/char.html#tryParse)
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
## What about ...?
|
||||
|
||||
- performance - The code is very simple but I won't put any unverified assumptions here. I'd be grateful to anyone who can set up a good benchmark project to compare different parser combinators.
|
||||
|
||||
- stable release - Current release is well thought out and tested. I leave a chance that some supplied functions may need an incompatible change. Before version 1.0.0 this will be done without a deprecation cycle.
|
||||
|
||||
- streams/iterators - Maybe some day, if the need to parse a stream of non-string data arise. For now I don't have a task that would force me to think well on how to design it. It would require a significant trade off and may end up being a separate module (like `char`) at best or even a separate package.
|
||||
|
||||
- Fantasy Land - You can find some familiar ideas here, especially when compared to Static Land. But I'm not concerned about compatibility with that spec - see "Practicality over "purity"" entry above. What I think might make sense is to add separate tests for laws applicable in context of this package. Low priority though.
|
||||
|
||||
|
||||
## Some other parser combinator packages
|
||||
|
||||
- [arcsecond](https://github.com/francisrstokes/arcsecond);
|
||||
- [parsimmon](https://github.com/jneen/parsimmon);
|
||||
- [chevrotain](https://github.com/Chevrotain/chevrotain);
|
||||
- [prsc.js](https://github.com/bwrrp/prsc.js);
|
||||
- [lop](https://github.com/mwilliamson/lop);
|
||||
- [parser-lang](https://github.com/disnet/parser-lang);
|
||||
- *and more, with varied level of maintenance.*
|
103
node_modules/peberminta/lib/char.cjs
generated
vendored
Normal file
103
node_modules/peberminta/lib/char.cjs
generated
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
'use strict';
|
||||
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
|
||||
var core = require('./core.cjs');
|
||||
var util = require('./util.cjs');
|
||||
|
||||
function char(char) {
|
||||
return core.token((c) => (c === char) ? c : undefined);
|
||||
}
|
||||
function oneOf(chars) {
|
||||
return core.token((c) => (chars.includes(c)) ? c : undefined);
|
||||
}
|
||||
function noneOf(chars) {
|
||||
return core.token((c) => (chars.includes(c)) ? undefined : c);
|
||||
}
|
||||
function charTest(regex) {
|
||||
return core.token((c) => regex.test(c) ? c : undefined);
|
||||
}
|
||||
function str(str) {
|
||||
const len = str.length;
|
||||
return (data, i) => {
|
||||
const tokensNumber = core.remainingTokensNumber(data, i);
|
||||
let substr = '';
|
||||
let j = 0;
|
||||
while (j < tokensNumber && substr.length < len) {
|
||||
substr += data.tokens[i + j];
|
||||
j++;
|
||||
}
|
||||
return (substr === str)
|
||||
? {
|
||||
matched: true,
|
||||
position: i + j,
|
||||
value: str
|
||||
}
|
||||
: { matched: false };
|
||||
};
|
||||
}
|
||||
function concat(...ps) {
|
||||
return core.map(core.flatten(...ps), (vs) => vs.join(''));
|
||||
}
|
||||
function parserPosition(data, i, contextTokens = 11) {
|
||||
const len = data.tokens.length;
|
||||
const lowIndex = util.clamp(0, i - contextTokens, len - contextTokens);
|
||||
const highIndex = util.clamp(contextTokens, i + 1 + contextTokens, len);
|
||||
const tokensSlice = data.tokens.slice(lowIndex, highIndex);
|
||||
if (tokensSlice.some((t) => t.length !== 1)) {
|
||||
return core.parserPosition(data, i, (t) => t);
|
||||
}
|
||||
let line = '';
|
||||
let offset = 0;
|
||||
let markerLen = 1;
|
||||
if (i < 0) {
|
||||
line += ' ';
|
||||
}
|
||||
if (0 < lowIndex) {
|
||||
line += '...';
|
||||
}
|
||||
for (let j = 0; j < tokensSlice.length; j++) {
|
||||
const token = util.escapeWhitespace(tokensSlice[j]);
|
||||
if (lowIndex + j === i) {
|
||||
offset = line.length;
|
||||
markerLen = token.length;
|
||||
}
|
||||
line += token;
|
||||
}
|
||||
if (highIndex < len) {
|
||||
line += '...';
|
||||
}
|
||||
if (len <= i) {
|
||||
offset = line.length;
|
||||
}
|
||||
return `${''.padEnd(offset)}${i}\n${line}\n${''.padEnd(offset)}${'^'.repeat(markerLen)}`;
|
||||
}
|
||||
function parse(parser, str, options) {
|
||||
const data = { tokens: [...str], options: options };
|
||||
const result = parser(data, 0);
|
||||
if (!result.matched) {
|
||||
throw new Error('No match');
|
||||
}
|
||||
if (result.position < data.tokens.length) {
|
||||
throw new Error(`Partial match. Parsing stopped at:\n${parserPosition(data, result.position)}`);
|
||||
}
|
||||
return result.value;
|
||||
}
|
||||
function tryParse(parser, str, options) {
|
||||
return core.tryParse(parser, [...str], options);
|
||||
}
|
||||
function match(matcher, str, options) {
|
||||
return core.match(matcher, [...str], options);
|
||||
}
|
||||
|
||||
exports.anyOf = oneOf;
|
||||
exports.char = char;
|
||||
exports.charTest = charTest;
|
||||
exports.concat = concat;
|
||||
exports.match = match;
|
||||
exports.noneOf = noneOf;
|
||||
exports.oneOf = oneOf;
|
||||
exports.parse = parse;
|
||||
exports.parserPosition = parserPosition;
|
||||
exports.str = str;
|
||||
exports.tryParse = tryParse;
|
154
node_modules/peberminta/lib/char.d.ts
generated
vendored
Normal file
154
node_modules/peberminta/lib/char.d.ts
generated
vendored
Normal file
@@ -0,0 +1,154 @@
|
||||
/**
|
||||
* This is an additional module specifically for string parsers.
|
||||
*
|
||||
* It contains parsers with token type bound to be `string`
|
||||
* and expected to work with individual characters.
|
||||
*
|
||||
* It should work even if you have a custom way to split
|
||||
* a string into symbols such as graphemes.
|
||||
*
|
||||
* Node:
|
||||
* ```ts
|
||||
* import * as pc from 'peberminta/char';
|
||||
* ```
|
||||
*
|
||||
* Deno:
|
||||
* ```ts
|
||||
* import * as p from 'https://deno.land/x/peberminta@.../char.ts';
|
||||
* ```
|
||||
*
|
||||
* @packageDocumentation
|
||||
*/
|
||||
import { Parser, Matcher, Data } from './core';
|
||||
/**
|
||||
* Make a parser that looks for the exact match for a given character
|
||||
* and returns a match with that character.
|
||||
*
|
||||
* Tokens expected to be individual characters/graphemes.
|
||||
*
|
||||
* @param char - A character to look for.
|
||||
*/
|
||||
export declare function char<TOptions>(char: string): Parser<string, TOptions, string>;
|
||||
/**
|
||||
* Make a parser that matches and returns a character
|
||||
* if it is present in a given character samples string/array.
|
||||
*
|
||||
* Tokens expected to be individual characters/graphemes.
|
||||
*
|
||||
* @param chars - An array (or a string) of all acceptable characters.
|
||||
*/
|
||||
export declare function oneOf<TOptions>(chars: string | string[]): Parser<string, TOptions, string>;
|
||||
export { oneOf as anyOf };
|
||||
/**
|
||||
* Make a parser that matches and returns a character
|
||||
* if it is absent in a given character samples string/array.
|
||||
*
|
||||
* Tokens expected to be individual characters/graphemes.
|
||||
*
|
||||
* @param chars - An array (or a string) of all characters that are not acceptable.
|
||||
*/
|
||||
export declare function noneOf<TOptions>(chars: string | string[]): Parser<string, TOptions, string>;
|
||||
/**
|
||||
* Make a parser that matches input character against given regular expression.
|
||||
*
|
||||
* Use this to match characters belonging to a certain range
|
||||
* or having a certain [unicode property](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Unicode_Property_Escapes).
|
||||
*
|
||||
* Use `satisfy` from core module instead if you need a predicate.
|
||||
*
|
||||
* Tokens expected to be individual characters/graphemes.
|
||||
*
|
||||
* @param regex - Tester regular expression.
|
||||
*/
|
||||
export declare function charTest<TOptions>(regex: RegExp): Parser<string, TOptions, string>;
|
||||
/**
|
||||
* Make a parser that looks for the exact match for a given string,
|
||||
* returns a match with that string and consumes an according number of tokens.
|
||||
*
|
||||
* Empty string matches without consuming input.
|
||||
*
|
||||
* Tokens expected to be individual characters/graphemes.
|
||||
*
|
||||
* @param str - A string to look for.
|
||||
*/
|
||||
export declare function str<TOptions>(str: string): Parser<string, TOptions, string>;
|
||||
/**
|
||||
* Make a parser that concatenates characters/strings
|
||||
* from all provided parsers into a single string.
|
||||
*
|
||||
* Nonmatch is returned if any of parsers didn't match.
|
||||
*
|
||||
* @param ps - Parsers sequence.
|
||||
* Each parser can return a string or an array of strings.
|
||||
*/
|
||||
export declare function concat<TOptions>(...ps: Parser<string, TOptions, string | string[]>[]): Parser<string, TOptions, string>;
|
||||
/**
|
||||
* Utility function to render a given parser position
|
||||
* for error reporting and debug purposes.
|
||||
*
|
||||
* This is a version specific for char parsers.
|
||||
*
|
||||
* Note: it will fall back to core version (one token per line)
|
||||
* in case any multicharacter tokens are present.
|
||||
*
|
||||
* @param data - Data object (tokens and options).
|
||||
* @param i - Parser position in the tokens array.
|
||||
* @param contextTokens - How many tokens (characters) around the current one to render.
|
||||
* @returns A multiline string.
|
||||
*
|
||||
* @category Utility functions
|
||||
*/
|
||||
export declare function parserPosition(data: Data<string, unknown>, i: number, contextTokens?: number): string;
|
||||
/**
|
||||
* Utility function that provides a bit cleaner interface for running a parser.
|
||||
*
|
||||
* This one throws an error in case parser didn't match
|
||||
* OR the match is incomplete (some part of input string left unparsed).
|
||||
*
|
||||
* Input string is broken down to characters as `[...str]`
|
||||
* unless you provide a pre-split array.
|
||||
*
|
||||
* @param parser - A parser to run.
|
||||
* @param str - Input string or an array of graphemes.
|
||||
* @param options - Parser options.
|
||||
* @returns A matched value.
|
||||
*
|
||||
* @category Utility functions
|
||||
*/
|
||||
export declare function parse<TOptions, TValue>(parser: Parser<string, TOptions, TValue>, str: string | string[], options: TOptions): TValue;
|
||||
/**
|
||||
* Utility function that provides a bit cleaner interface
|
||||
* for running a parser over a string.
|
||||
* Returns `undefined` in case parser did not match.
|
||||
*
|
||||
* Input string is broken down to characters as `[...str]`
|
||||
* unless you provide a pre-split array.
|
||||
*
|
||||
* Note: this doesn't capture errors thrown during parsing.
|
||||
* Nonmatch is considered a part or normal flow.
|
||||
* Errors mean unrecoverable state and it's up to client code to decide
|
||||
* where to throw errors and how to get back to safe state.
|
||||
*
|
||||
* @param parser - A parser to run.
|
||||
* @param str - Input string or an array of graphemes.
|
||||
* @param options - Parser options.
|
||||
* @returns A matched value or `undefined` in case of nonmatch.
|
||||
*
|
||||
* @category Utility functions
|
||||
*/
|
||||
export declare function tryParse<TOptions, TValue>(parser: Parser<string, TOptions, TValue>, str: string | string[], options: TOptions): TValue | undefined;
|
||||
/**
|
||||
* Utility function that provides a bit cleaner interface
|
||||
* for running a {@link Matcher} over a string.
|
||||
*
|
||||
* Input string is broken down to characters as `[...str]`
|
||||
* unless you provide a pre-split array.
|
||||
*
|
||||
* @param matcher - A matcher to run.
|
||||
* @param str - Input string or an array of graphemes.
|
||||
* @param options - Parser options.
|
||||
* @returns A matched value.
|
||||
*
|
||||
* @category Utility functions
|
||||
*/
|
||||
export declare function match<TOptions, TValue>(matcher: Matcher<string, TOptions, TValue>, str: string | string[], options: TOptions): TValue;
|
89
node_modules/peberminta/lib/char.mjs
generated
vendored
Normal file
89
node_modules/peberminta/lib/char.mjs
generated
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
import { token, remainingTokensNumber, map, flatten, parserPosition as parserPosition$1, tryParse as tryParse$1, match as match$1 } from './core.mjs';
|
||||
import { clamp, escapeWhitespace } from './util.mjs';
|
||||
|
||||
function char(char) {
|
||||
return token((c) => (c === char) ? c : undefined);
|
||||
}
|
||||
function oneOf(chars) {
|
||||
return token((c) => (chars.includes(c)) ? c : undefined);
|
||||
}
|
||||
function noneOf(chars) {
|
||||
return token((c) => (chars.includes(c)) ? undefined : c);
|
||||
}
|
||||
function charTest(regex) {
|
||||
return token((c) => regex.test(c) ? c : undefined);
|
||||
}
|
||||
function str(str) {
|
||||
const len = str.length;
|
||||
return (data, i) => {
|
||||
const tokensNumber = remainingTokensNumber(data, i);
|
||||
let substr = '';
|
||||
let j = 0;
|
||||
while (j < tokensNumber && substr.length < len) {
|
||||
substr += data.tokens[i + j];
|
||||
j++;
|
||||
}
|
||||
return (substr === str)
|
||||
? {
|
||||
matched: true,
|
||||
position: i + j,
|
||||
value: str
|
||||
}
|
||||
: { matched: false };
|
||||
};
|
||||
}
|
||||
function concat(...ps) {
|
||||
return map(flatten(...ps), (vs) => vs.join(''));
|
||||
}
|
||||
function parserPosition(data, i, contextTokens = 11) {
|
||||
const len = data.tokens.length;
|
||||
const lowIndex = clamp(0, i - contextTokens, len - contextTokens);
|
||||
const highIndex = clamp(contextTokens, i + 1 + contextTokens, len);
|
||||
const tokensSlice = data.tokens.slice(lowIndex, highIndex);
|
||||
if (tokensSlice.some((t) => t.length !== 1)) {
|
||||
return parserPosition$1(data, i, (t) => t);
|
||||
}
|
||||
let line = '';
|
||||
let offset = 0;
|
||||
let markerLen = 1;
|
||||
if (i < 0) {
|
||||
line += ' ';
|
||||
}
|
||||
if (0 < lowIndex) {
|
||||
line += '...';
|
||||
}
|
||||
for (let j = 0; j < tokensSlice.length; j++) {
|
||||
const token = escapeWhitespace(tokensSlice[j]);
|
||||
if (lowIndex + j === i) {
|
||||
offset = line.length;
|
||||
markerLen = token.length;
|
||||
}
|
||||
line += token;
|
||||
}
|
||||
if (highIndex < len) {
|
||||
line += '...';
|
||||
}
|
||||
if (len <= i) {
|
||||
offset = line.length;
|
||||
}
|
||||
return `${''.padEnd(offset)}${i}\n${line}\n${''.padEnd(offset)}${'^'.repeat(markerLen)}`;
|
||||
}
|
||||
function parse(parser, str, options) {
|
||||
const data = { tokens: [...str], options: options };
|
||||
const result = parser(data, 0);
|
||||
if (!result.matched) {
|
||||
throw new Error('No match');
|
||||
}
|
||||
if (result.position < data.tokens.length) {
|
||||
throw new Error(`Partial match. Parsing stopped at:\n${parserPosition(data, result.position)}`);
|
||||
}
|
||||
return result.value;
|
||||
}
|
||||
function tryParse(parser, str, options) {
|
||||
return tryParse$1(parser, [...str], options);
|
||||
}
|
||||
function match(matcher, str, options) {
|
||||
return match$1(matcher, [...str], options);
|
||||
}
|
||||
|
||||
export { oneOf as anyOf, char, charTest, concat, match, noneOf, oneOf, parse, parserPosition, str, tryParse };
|
447
node_modules/peberminta/lib/core.cjs
generated
vendored
Normal file
447
node_modules/peberminta/lib/core.cjs
generated
vendored
Normal file
@@ -0,0 +1,447 @@
|
||||
'use strict';
|
||||
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
|
||||
var util = require('./util.cjs');
|
||||
|
||||
function emit(value) {
|
||||
return (data, i) => ({
|
||||
matched: true,
|
||||
position: i,
|
||||
value: value
|
||||
});
|
||||
}
|
||||
function make(
|
||||
f) {
|
||||
return (data, i) => ({
|
||||
matched: true,
|
||||
position: i,
|
||||
value: f(data, i)
|
||||
});
|
||||
}
|
||||
function action(
|
||||
f) {
|
||||
return (data, i) => {
|
||||
f(data, i);
|
||||
return {
|
||||
matched: true,
|
||||
position: i,
|
||||
value: null
|
||||
};
|
||||
};
|
||||
}
|
||||
function fail(
|
||||
data, i) {
|
||||
return { matched: false };
|
||||
}
|
||||
function error(message) {
|
||||
return (data, i) => {
|
||||
throw new Error((message instanceof Function) ? message(data, i) : message);
|
||||
};
|
||||
}
|
||||
function token(
|
||||
onToken,
|
||||
onEnd) {
|
||||
return (data, i) => {
|
||||
let position = i;
|
||||
let value = undefined;
|
||||
if (i < data.tokens.length) {
|
||||
value = onToken(data.tokens[i], data, i);
|
||||
if (value !== undefined) {
|
||||
position++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
onEnd?.(data, i);
|
||||
}
|
||||
return (value === undefined)
|
||||
? { matched: false }
|
||||
: {
|
||||
matched: true,
|
||||
position: position,
|
||||
value: value
|
||||
};
|
||||
};
|
||||
}
|
||||
function any(data, i) {
|
||||
return (i < data.tokens.length)
|
||||
? {
|
||||
matched: true,
|
||||
position: i + 1,
|
||||
value: data.tokens[i]
|
||||
}
|
||||
: { matched: false };
|
||||
}
|
||||
function satisfy(
|
||||
test) {
|
||||
return (data, i) => (i < data.tokens.length && test(data.tokens[i], data, i))
|
||||
? {
|
||||
matched: true,
|
||||
position: i + 1,
|
||||
value: data.tokens[i]
|
||||
}
|
||||
: { matched: false };
|
||||
}
|
||||
function mapInner(r, f) {
|
||||
return (r.matched) ? ({
|
||||
matched: true,
|
||||
position: r.position,
|
||||
value: f(r.value, r.position)
|
||||
}) : r;
|
||||
}
|
||||
function mapOuter(r, f) {
|
||||
return (r.matched) ? f(r) : r;
|
||||
}
|
||||
function map(p, mapper) {
|
||||
return (data, i) => mapInner(p(data, i), (v, j) => mapper(v, data, i, j));
|
||||
}
|
||||
function map1(p,
|
||||
mapper) {
|
||||
return (data, i) => mapOuter(p(data, i), (m) => mapper(m, data, i));
|
||||
}
|
||||
function peek(p, f) {
|
||||
return (data, i) => {
|
||||
const r = p(data, i);
|
||||
f(r, data, i);
|
||||
return r;
|
||||
};
|
||||
}
|
||||
function option(p, def) {
|
||||
return (data, i) => {
|
||||
const r = p(data, i);
|
||||
return (r.matched)
|
||||
? r
|
||||
: {
|
||||
matched: true,
|
||||
position: i,
|
||||
value: def
|
||||
};
|
||||
};
|
||||
}
|
||||
function not(p) {
|
||||
return (data, i) => {
|
||||
const r = p(data, i);
|
||||
return (r.matched)
|
||||
? { matched: false }
|
||||
: {
|
||||
matched: true,
|
||||
position: i,
|
||||
value: true
|
||||
};
|
||||
};
|
||||
}
|
||||
function choice(...ps) {
|
||||
return (data, i) => {
|
||||
for (const p of ps) {
|
||||
const result = p(data, i);
|
||||
if (result.matched) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return { matched: false };
|
||||
};
|
||||
}
|
||||
function otherwise(pa, pb) {
|
||||
return (data, i) => {
|
||||
const r1 = pa(data, i);
|
||||
return (r1.matched)
|
||||
? r1
|
||||
: pb(data, i);
|
||||
};
|
||||
}
|
||||
function longest(...ps) {
|
||||
return (data, i) => {
|
||||
let match = undefined;
|
||||
for (const p of ps) {
|
||||
const result = p(data, i);
|
||||
if (result.matched && (!match || match.position < result.position)) {
|
||||
match = result;
|
||||
}
|
||||
}
|
||||
return match || { matched: false };
|
||||
};
|
||||
}
|
||||
function takeWhile(p,
|
||||
test) {
|
||||
return (data, i) => {
|
||||
const values = [];
|
||||
let success = true;
|
||||
do {
|
||||
const r = p(data, i);
|
||||
if (r.matched && test(r.value, values.length + 1, data, i, r.position)) {
|
||||
values.push(r.value);
|
||||
i = r.position;
|
||||
}
|
||||
else {
|
||||
success = false;
|
||||
}
|
||||
} while (success);
|
||||
return {
|
||||
matched: true,
|
||||
position: i,
|
||||
value: values
|
||||
};
|
||||
};
|
||||
}
|
||||
function takeUntil(p,
|
||||
test) {
|
||||
return takeWhile(p, (value, n, data, i, j) => !test(value, n, data, i, j));
|
||||
}
|
||||
function takeWhileP(pValue, pTest) {
|
||||
return takeWhile(pValue, (value, n, data, i) => pTest(data, i).matched);
|
||||
}
|
||||
function takeUntilP(pValue, pTest) {
|
||||
return takeWhile(pValue, (value, n, data, i) => !pTest(data, i).matched);
|
||||
}
|
||||
function many(p) {
|
||||
return takeWhile(p, () => true);
|
||||
}
|
||||
function many1(p) {
|
||||
return ab(p, many(p), (head, tail) => [head, ...tail]);
|
||||
}
|
||||
function ab(pa, pb, join) {
|
||||
return (data, i) => mapOuter(pa(data, i), (ma) => mapInner(pb(data, ma.position), (vb, j) => join(ma.value, vb, data, i, j)));
|
||||
}
|
||||
function left(pa, pb) {
|
||||
return ab(pa, pb, (va) => va);
|
||||
}
|
||||
function right(pa, pb) {
|
||||
return ab(pa, pb, (va, vb) => vb);
|
||||
}
|
||||
function abc(pa, pb, pc, join) {
|
||||
return (data, i) => mapOuter(pa(data, i), (ma) => mapOuter(pb(data, ma.position), (mb) => mapInner(pc(data, mb.position), (vc, j) => join(ma.value, mb.value, vc, data, i, j))));
|
||||
}
|
||||
function middle(pa, pb, pc) {
|
||||
return abc(pa, pb, pc, (ra, rb) => rb);
|
||||
}
|
||||
function all(...ps) {
|
||||
return (data, i) => {
|
||||
const result = [];
|
||||
let position = i;
|
||||
for (const p of ps) {
|
||||
const r1 = p(data, position);
|
||||
if (r1.matched) {
|
||||
result.push(r1.value);
|
||||
position = r1.position;
|
||||
}
|
||||
else {
|
||||
return { matched: false };
|
||||
}
|
||||
}
|
||||
return {
|
||||
matched: true,
|
||||
position: position,
|
||||
value: result
|
||||
};
|
||||
};
|
||||
}
|
||||
function skip(...ps) {
|
||||
return map(all(...ps), () => null);
|
||||
}
|
||||
function flatten(...ps) {
|
||||
return flatten1(all(...ps));
|
||||
}
|
||||
function flatten1(p) {
|
||||
return map(p, (vs) => vs.flatMap((v) => v));
|
||||
}
|
||||
function sepBy1(pValue, pSep) {
|
||||
return ab(pValue, many(right(pSep, pValue)), (head, tail) => [head, ...tail]);
|
||||
}
|
||||
function sepBy(pValue, pSep) {
|
||||
return otherwise(sepBy1(pValue, pSep), emit([]));
|
||||
}
|
||||
function chainReduce(acc,
|
||||
f) {
|
||||
return (data, i) => {
|
||||
let loop = true;
|
||||
let acc1 = acc;
|
||||
let pos = i;
|
||||
do {
|
||||
const r = f(acc1, data, pos)(data, pos);
|
||||
if (r.matched) {
|
||||
acc1 = r.value;
|
||||
pos = r.position;
|
||||
}
|
||||
else {
|
||||
loop = false;
|
||||
}
|
||||
} while (loop);
|
||||
return {
|
||||
matched: true,
|
||||
position: pos,
|
||||
value: acc1
|
||||
};
|
||||
};
|
||||
}
|
||||
function reduceLeft(acc, p,
|
||||
reducer) {
|
||||
return chainReduce(acc, (acc) => map(p, (v, data, i, j) => reducer(acc, v, data, i, j)));
|
||||
}
|
||||
function reduceRight(p, acc,
|
||||
reducer) {
|
||||
return map(many(p), (vs, data, i, j) => vs.reduceRight((acc, v) => reducer(v, acc, data, i, j), acc));
|
||||
}
|
||||
function leftAssoc1(pLeft, pOper) {
|
||||
return chain(pLeft, (v0) => reduceLeft(v0, pOper, (acc, f) => f(acc)));
|
||||
}
|
||||
function rightAssoc1(pOper, pRight) {
|
||||
return ab(reduceRight(pOper, (y) => y, (f, acc) => (y) => f(acc(y))), pRight, (f, v) => f(v));
|
||||
}
|
||||
function leftAssoc2(pLeft, pOper, pRight) {
|
||||
return chain(pLeft, (v0) => reduceLeft(v0, ab(pOper, pRight, (f, y) => [f, y]), (acc, [f, y]) => f(acc, y)));
|
||||
}
|
||||
function rightAssoc2(pLeft, pOper, pRight) {
|
||||
return ab(reduceRight(ab(pLeft, pOper, (x, f) => [x, f]), (y) => y, ([x, f], acc) => (y) => f(x, acc(y))), pRight, (f, v) => f(v));
|
||||
}
|
||||
function condition(cond, pTrue, pFalse) {
|
||||
return (data, i) => (cond(data, i))
|
||||
? pTrue(data, i)
|
||||
: pFalse(data, i);
|
||||
}
|
||||
function decide(p) {
|
||||
return (data, i) => mapOuter(p(data, i), (m1) => m1.value(data, m1.position));
|
||||
}
|
||||
function chain(p,
|
||||
f) {
|
||||
return (data, i) => mapOuter(p(data, i), (m1) => f(m1.value, data, i, m1.position)(data, m1.position));
|
||||
}
|
||||
function ahead(p) {
|
||||
return (data, i) => mapOuter(p(data, i), (m1) => ({
|
||||
matched: true,
|
||||
position: i,
|
||||
value: m1.value
|
||||
}));
|
||||
}
|
||||
function recursive(f) {
|
||||
return function (data, i) {
|
||||
return f()(data, i);
|
||||
};
|
||||
}
|
||||
function start(data, i) {
|
||||
return (i !== 0)
|
||||
? { matched: false }
|
||||
: {
|
||||
matched: true,
|
||||
position: i,
|
||||
value: true
|
||||
};
|
||||
}
|
||||
function end(data, i) {
|
||||
return (i < data.tokens.length)
|
||||
? { matched: false }
|
||||
: {
|
||||
matched: true,
|
||||
position: i,
|
||||
value: true
|
||||
};
|
||||
}
|
||||
function remainingTokensNumber(data, i) {
|
||||
return data.tokens.length - i;
|
||||
}
|
||||
function parserPosition(data, i, formatToken, contextTokens = 3) {
|
||||
const len = data.tokens.length;
|
||||
const lowIndex = util.clamp(0, i - contextTokens, len - contextTokens);
|
||||
const highIndex = util.clamp(contextTokens, i + 1 + contextTokens, len);
|
||||
const tokensSlice = data.tokens.slice(lowIndex, highIndex);
|
||||
const lines = [];
|
||||
const indexWidth = String(highIndex - 1).length + 1;
|
||||
if (i < 0) {
|
||||
lines.push(`${String(i).padStart(indexWidth)} >>`);
|
||||
}
|
||||
if (0 < lowIndex) {
|
||||
lines.push('...'.padStart(indexWidth + 6));
|
||||
}
|
||||
for (let j = 0; j < tokensSlice.length; j++) {
|
||||
const index = lowIndex + j;
|
||||
lines.push(`${String(index).padStart(indexWidth)} ${(index === i ? '>' : ' ')} ${util.escapeWhitespace(formatToken(tokensSlice[j]))}`);
|
||||
}
|
||||
if (highIndex < len) {
|
||||
lines.push('...'.padStart(indexWidth + 6));
|
||||
}
|
||||
if (len <= i) {
|
||||
lines.push(`${String(i).padStart(indexWidth)} >>`);
|
||||
}
|
||||
return lines.join('\n');
|
||||
}
|
||||
function parse(parser, tokens, options, formatToken = JSON.stringify) {
|
||||
const data = { tokens: tokens, options: options };
|
||||
const result = parser(data, 0);
|
||||
if (!result.matched) {
|
||||
throw new Error('No match');
|
||||
}
|
||||
if (result.position < data.tokens.length) {
|
||||
throw new Error(`Partial match. Parsing stopped at:\n${parserPosition(data, result.position, formatToken)}`);
|
||||
}
|
||||
return result.value;
|
||||
}
|
||||
function tryParse(parser, tokens, options) {
|
||||
const result = parser({ tokens: tokens, options: options }, 0);
|
||||
return (result.matched)
|
||||
? result.value
|
||||
: undefined;
|
||||
}
|
||||
function match(matcher, tokens, options) {
|
||||
const result = matcher({ tokens: tokens, options: options }, 0);
|
||||
return result.value;
|
||||
}
|
||||
|
||||
exports.ab = ab;
|
||||
exports.abc = abc;
|
||||
exports.action = action;
|
||||
exports.ahead = ahead;
|
||||
exports.all = all;
|
||||
exports.and = all;
|
||||
exports.any = any;
|
||||
exports.chain = chain;
|
||||
exports.chainReduce = chainReduce;
|
||||
exports.choice = choice;
|
||||
exports.condition = condition;
|
||||
exports.decide = decide;
|
||||
exports.discard = skip;
|
||||
exports.eitherOr = otherwise;
|
||||
exports.emit = emit;
|
||||
exports.end = end;
|
||||
exports.eof = end;
|
||||
exports.error = error;
|
||||
exports.fail = fail;
|
||||
exports.flatten = flatten;
|
||||
exports.flatten1 = flatten1;
|
||||
exports.left = left;
|
||||
exports.leftAssoc1 = leftAssoc1;
|
||||
exports.leftAssoc2 = leftAssoc2;
|
||||
exports.longest = longest;
|
||||
exports.lookAhead = ahead;
|
||||
exports.make = make;
|
||||
exports.many = many;
|
||||
exports.many1 = many1;
|
||||
exports.map = map;
|
||||
exports.map1 = map1;
|
||||
exports.match = match;
|
||||
exports.middle = middle;
|
||||
exports.not = not;
|
||||
exports.of = emit;
|
||||
exports.option = option;
|
||||
exports.or = choice;
|
||||
exports.otherwise = otherwise;
|
||||
exports.parse = parse;
|
||||
exports.parserPosition = parserPosition;
|
||||
exports.peek = peek;
|
||||
exports.recursive = recursive;
|
||||
exports.reduceLeft = reduceLeft;
|
||||
exports.reduceRight = reduceRight;
|
||||
exports.remainingTokensNumber = remainingTokensNumber;
|
||||
exports.right = right;
|
||||
exports.rightAssoc1 = rightAssoc1;
|
||||
exports.rightAssoc2 = rightAssoc2;
|
||||
exports.satisfy = satisfy;
|
||||
exports.sepBy = sepBy;
|
||||
exports.sepBy1 = sepBy1;
|
||||
exports.skip = skip;
|
||||
exports.some = many1;
|
||||
exports.start = start;
|
||||
exports.takeUntil = takeUntil;
|
||||
exports.takeUntilP = takeUntilP;
|
||||
exports.takeWhile = takeWhile;
|
||||
exports.takeWhileP = takeWhileP;
|
||||
exports.token = token;
|
||||
exports.tryParse = tryParse;
|
1051
node_modules/peberminta/lib/core.d.ts
generated
vendored
Normal file
1051
node_modules/peberminta/lib/core.d.ts
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
384
node_modules/peberminta/lib/core.mjs
generated
vendored
Normal file
384
node_modules/peberminta/lib/core.mjs
generated
vendored
Normal file
@@ -0,0 +1,384 @@
|
||||
import { clamp, escapeWhitespace } from './util.mjs';
|
||||
|
||||
function emit(value) {
|
||||
return (data, i) => ({
|
||||
matched: true,
|
||||
position: i,
|
||||
value: value
|
||||
});
|
||||
}
|
||||
function make(
|
||||
f) {
|
||||
return (data, i) => ({
|
||||
matched: true,
|
||||
position: i,
|
||||
value: f(data, i)
|
||||
});
|
||||
}
|
||||
function action(
|
||||
f) {
|
||||
return (data, i) => {
|
||||
f(data, i);
|
||||
return {
|
||||
matched: true,
|
||||
position: i,
|
||||
value: null
|
||||
};
|
||||
};
|
||||
}
|
||||
function fail(
|
||||
data, i) {
|
||||
return { matched: false };
|
||||
}
|
||||
function error(message) {
|
||||
return (data, i) => {
|
||||
throw new Error((message instanceof Function) ? message(data, i) : message);
|
||||
};
|
||||
}
|
||||
function token(
|
||||
onToken,
|
||||
onEnd) {
|
||||
return (data, i) => {
|
||||
let position = i;
|
||||
let value = undefined;
|
||||
if (i < data.tokens.length) {
|
||||
value = onToken(data.tokens[i], data, i);
|
||||
if (value !== undefined) {
|
||||
position++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
onEnd?.(data, i);
|
||||
}
|
||||
return (value === undefined)
|
||||
? { matched: false }
|
||||
: {
|
||||
matched: true,
|
||||
position: position,
|
||||
value: value
|
||||
};
|
||||
};
|
||||
}
|
||||
function any(data, i) {
|
||||
return (i < data.tokens.length)
|
||||
? {
|
||||
matched: true,
|
||||
position: i + 1,
|
||||
value: data.tokens[i]
|
||||
}
|
||||
: { matched: false };
|
||||
}
|
||||
function satisfy(
|
||||
test) {
|
||||
return (data, i) => (i < data.tokens.length && test(data.tokens[i], data, i))
|
||||
? {
|
||||
matched: true,
|
||||
position: i + 1,
|
||||
value: data.tokens[i]
|
||||
}
|
||||
: { matched: false };
|
||||
}
|
||||
function mapInner(r, f) {
|
||||
return (r.matched) ? ({
|
||||
matched: true,
|
||||
position: r.position,
|
||||
value: f(r.value, r.position)
|
||||
}) : r;
|
||||
}
|
||||
function mapOuter(r, f) {
|
||||
return (r.matched) ? f(r) : r;
|
||||
}
|
||||
function map(p, mapper) {
|
||||
return (data, i) => mapInner(p(data, i), (v, j) => mapper(v, data, i, j));
|
||||
}
|
||||
function map1(p,
|
||||
mapper) {
|
||||
return (data, i) => mapOuter(p(data, i), (m) => mapper(m, data, i));
|
||||
}
|
||||
function peek(p, f) {
|
||||
return (data, i) => {
|
||||
const r = p(data, i);
|
||||
f(r, data, i);
|
||||
return r;
|
||||
};
|
||||
}
|
||||
function option(p, def) {
|
||||
return (data, i) => {
|
||||
const r = p(data, i);
|
||||
return (r.matched)
|
||||
? r
|
||||
: {
|
||||
matched: true,
|
||||
position: i,
|
||||
value: def
|
||||
};
|
||||
};
|
||||
}
|
||||
function not(p) {
|
||||
return (data, i) => {
|
||||
const r = p(data, i);
|
||||
return (r.matched)
|
||||
? { matched: false }
|
||||
: {
|
||||
matched: true,
|
||||
position: i,
|
||||
value: true
|
||||
};
|
||||
};
|
||||
}
|
||||
function choice(...ps) {
|
||||
return (data, i) => {
|
||||
for (const p of ps) {
|
||||
const result = p(data, i);
|
||||
if (result.matched) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return { matched: false };
|
||||
};
|
||||
}
|
||||
function otherwise(pa, pb) {
|
||||
return (data, i) => {
|
||||
const r1 = pa(data, i);
|
||||
return (r1.matched)
|
||||
? r1
|
||||
: pb(data, i);
|
||||
};
|
||||
}
|
||||
function longest(...ps) {
|
||||
return (data, i) => {
|
||||
let match = undefined;
|
||||
for (const p of ps) {
|
||||
const result = p(data, i);
|
||||
if (result.matched && (!match || match.position < result.position)) {
|
||||
match = result;
|
||||
}
|
||||
}
|
||||
return match || { matched: false };
|
||||
};
|
||||
}
|
||||
function takeWhile(p,
|
||||
test) {
|
||||
return (data, i) => {
|
||||
const values = [];
|
||||
let success = true;
|
||||
do {
|
||||
const r = p(data, i);
|
||||
if (r.matched && test(r.value, values.length + 1, data, i, r.position)) {
|
||||
values.push(r.value);
|
||||
i = r.position;
|
||||
}
|
||||
else {
|
||||
success = false;
|
||||
}
|
||||
} while (success);
|
||||
return {
|
||||
matched: true,
|
||||
position: i,
|
||||
value: values
|
||||
};
|
||||
};
|
||||
}
|
||||
function takeUntil(p,
|
||||
test) {
|
||||
return takeWhile(p, (value, n, data, i, j) => !test(value, n, data, i, j));
|
||||
}
|
||||
function takeWhileP(pValue, pTest) {
|
||||
return takeWhile(pValue, (value, n, data, i) => pTest(data, i).matched);
|
||||
}
|
||||
function takeUntilP(pValue, pTest) {
|
||||
return takeWhile(pValue, (value, n, data, i) => !pTest(data, i).matched);
|
||||
}
|
||||
function many(p) {
|
||||
return takeWhile(p, () => true);
|
||||
}
|
||||
function many1(p) {
|
||||
return ab(p, many(p), (head, tail) => [head, ...tail]);
|
||||
}
|
||||
function ab(pa, pb, join) {
|
||||
return (data, i) => mapOuter(pa(data, i), (ma) => mapInner(pb(data, ma.position), (vb, j) => join(ma.value, vb, data, i, j)));
|
||||
}
|
||||
function left(pa, pb) {
|
||||
return ab(pa, pb, (va) => va);
|
||||
}
|
||||
function right(pa, pb) {
|
||||
return ab(pa, pb, (va, vb) => vb);
|
||||
}
|
||||
function abc(pa, pb, pc, join) {
|
||||
return (data, i) => mapOuter(pa(data, i), (ma) => mapOuter(pb(data, ma.position), (mb) => mapInner(pc(data, mb.position), (vc, j) => join(ma.value, mb.value, vc, data, i, j))));
|
||||
}
|
||||
function middle(pa, pb, pc) {
|
||||
return abc(pa, pb, pc, (ra, rb) => rb);
|
||||
}
|
||||
function all(...ps) {
|
||||
return (data, i) => {
|
||||
const result = [];
|
||||
let position = i;
|
||||
for (const p of ps) {
|
||||
const r1 = p(data, position);
|
||||
if (r1.matched) {
|
||||
result.push(r1.value);
|
||||
position = r1.position;
|
||||
}
|
||||
else {
|
||||
return { matched: false };
|
||||
}
|
||||
}
|
||||
return {
|
||||
matched: true,
|
||||
position: position,
|
||||
value: result
|
||||
};
|
||||
};
|
||||
}
|
||||
function skip(...ps) {
|
||||
return map(all(...ps), () => null);
|
||||
}
|
||||
function flatten(...ps) {
|
||||
return flatten1(all(...ps));
|
||||
}
|
||||
function flatten1(p) {
|
||||
return map(p, (vs) => vs.flatMap((v) => v));
|
||||
}
|
||||
function sepBy1(pValue, pSep) {
|
||||
return ab(pValue, many(right(pSep, pValue)), (head, tail) => [head, ...tail]);
|
||||
}
|
||||
function sepBy(pValue, pSep) {
|
||||
return otherwise(sepBy1(pValue, pSep), emit([]));
|
||||
}
|
||||
function chainReduce(acc,
|
||||
f) {
|
||||
return (data, i) => {
|
||||
let loop = true;
|
||||
let acc1 = acc;
|
||||
let pos = i;
|
||||
do {
|
||||
const r = f(acc1, data, pos)(data, pos);
|
||||
if (r.matched) {
|
||||
acc1 = r.value;
|
||||
pos = r.position;
|
||||
}
|
||||
else {
|
||||
loop = false;
|
||||
}
|
||||
} while (loop);
|
||||
return {
|
||||
matched: true,
|
||||
position: pos,
|
||||
value: acc1
|
||||
};
|
||||
};
|
||||
}
|
||||
function reduceLeft(acc, p,
|
||||
reducer) {
|
||||
return chainReduce(acc, (acc) => map(p, (v, data, i, j) => reducer(acc, v, data, i, j)));
|
||||
}
|
||||
function reduceRight(p, acc,
|
||||
reducer) {
|
||||
return map(many(p), (vs, data, i, j) => vs.reduceRight((acc, v) => reducer(v, acc, data, i, j), acc));
|
||||
}
|
||||
function leftAssoc1(pLeft, pOper) {
|
||||
return chain(pLeft, (v0) => reduceLeft(v0, pOper, (acc, f) => f(acc)));
|
||||
}
|
||||
function rightAssoc1(pOper, pRight) {
|
||||
return ab(reduceRight(pOper, (y) => y, (f, acc) => (y) => f(acc(y))), pRight, (f, v) => f(v));
|
||||
}
|
||||
function leftAssoc2(pLeft, pOper, pRight) {
|
||||
return chain(pLeft, (v0) => reduceLeft(v0, ab(pOper, pRight, (f, y) => [f, y]), (acc, [f, y]) => f(acc, y)));
|
||||
}
|
||||
function rightAssoc2(pLeft, pOper, pRight) {
|
||||
return ab(reduceRight(ab(pLeft, pOper, (x, f) => [x, f]), (y) => y, ([x, f], acc) => (y) => f(x, acc(y))), pRight, (f, v) => f(v));
|
||||
}
|
||||
function condition(cond, pTrue, pFalse) {
|
||||
return (data, i) => (cond(data, i))
|
||||
? pTrue(data, i)
|
||||
: pFalse(data, i);
|
||||
}
|
||||
function decide(p) {
|
||||
return (data, i) => mapOuter(p(data, i), (m1) => m1.value(data, m1.position));
|
||||
}
|
||||
function chain(p,
|
||||
f) {
|
||||
return (data, i) => mapOuter(p(data, i), (m1) => f(m1.value, data, i, m1.position)(data, m1.position));
|
||||
}
|
||||
function ahead(p) {
|
||||
return (data, i) => mapOuter(p(data, i), (m1) => ({
|
||||
matched: true,
|
||||
position: i,
|
||||
value: m1.value
|
||||
}));
|
||||
}
|
||||
function recursive(f) {
|
||||
return function (data, i) {
|
||||
return f()(data, i);
|
||||
};
|
||||
}
|
||||
function start(data, i) {
|
||||
return (i !== 0)
|
||||
? { matched: false }
|
||||
: {
|
||||
matched: true,
|
||||
position: i,
|
||||
value: true
|
||||
};
|
||||
}
|
||||
function end(data, i) {
|
||||
return (i < data.tokens.length)
|
||||
? { matched: false }
|
||||
: {
|
||||
matched: true,
|
||||
position: i,
|
||||
value: true
|
||||
};
|
||||
}
|
||||
function remainingTokensNumber(data, i) {
|
||||
return data.tokens.length - i;
|
||||
}
|
||||
function parserPosition(data, i, formatToken, contextTokens = 3) {
|
||||
const len = data.tokens.length;
|
||||
const lowIndex = clamp(0, i - contextTokens, len - contextTokens);
|
||||
const highIndex = clamp(contextTokens, i + 1 + contextTokens, len);
|
||||
const tokensSlice = data.tokens.slice(lowIndex, highIndex);
|
||||
const lines = [];
|
||||
const indexWidth = String(highIndex - 1).length + 1;
|
||||
if (i < 0) {
|
||||
lines.push(`${String(i).padStart(indexWidth)} >>`);
|
||||
}
|
||||
if (0 < lowIndex) {
|
||||
lines.push('...'.padStart(indexWidth + 6));
|
||||
}
|
||||
for (let j = 0; j < tokensSlice.length; j++) {
|
||||
const index = lowIndex + j;
|
||||
lines.push(`${String(index).padStart(indexWidth)} ${(index === i ? '>' : ' ')} ${escapeWhitespace(formatToken(tokensSlice[j]))}`);
|
||||
}
|
||||
if (highIndex < len) {
|
||||
lines.push('...'.padStart(indexWidth + 6));
|
||||
}
|
||||
if (len <= i) {
|
||||
lines.push(`${String(i).padStart(indexWidth)} >>`);
|
||||
}
|
||||
return lines.join('\n');
|
||||
}
|
||||
function parse(parser, tokens, options, formatToken = JSON.stringify) {
|
||||
const data = { tokens: tokens, options: options };
|
||||
const result = parser(data, 0);
|
||||
if (!result.matched) {
|
||||
throw new Error('No match');
|
||||
}
|
||||
if (result.position < data.tokens.length) {
|
||||
throw new Error(`Partial match. Parsing stopped at:\n${parserPosition(data, result.position, formatToken)}`);
|
||||
}
|
||||
return result.value;
|
||||
}
|
||||
function tryParse(parser, tokens, options) {
|
||||
const result = parser({ tokens: tokens, options: options }, 0);
|
||||
return (result.matched)
|
||||
? result.value
|
||||
: undefined;
|
||||
}
|
||||
function match(matcher, tokens, options) {
|
||||
const result = matcher({ tokens: tokens, options: options }, 0);
|
||||
return result.value;
|
||||
}
|
||||
|
||||
export { ab, abc, action, ahead, all, all as and, any, chain, chainReduce, choice, condition, decide, skip as discard, otherwise as eitherOr, emit, end, end as eof, error, fail, flatten, flatten1, left, leftAssoc1, leftAssoc2, longest, ahead as lookAhead, make, many, many1, map, map1, match, middle, not, emit as of, option, choice as or, otherwise, parse, parserPosition, peek, recursive, reduceLeft, reduceRight, remainingTokensNumber, right, rightAssoc1, rightAssoc2, satisfy, sepBy, sepBy1, skip, many1 as some, start, takeUntil, takeUntilP, takeWhile, takeWhileP, token, tryParse };
|
13
node_modules/peberminta/lib/util.cjs
generated
vendored
Normal file
13
node_modules/peberminta/lib/util.cjs
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
'use strict';
|
||||
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
|
||||
function clamp(left, x, right) {
|
||||
return Math.max(left, Math.min(x, right));
|
||||
}
|
||||
function escapeWhitespace(str) {
|
||||
return str.replace(/(\t)|(\r)|(\n)/g, (m, t, r) => t ? '\\t' : r ? '\\r' : '\\n');
|
||||
}
|
||||
|
||||
exports.clamp = clamp;
|
||||
exports.escapeWhitespace = escapeWhitespace;
|
8
node_modules/peberminta/lib/util.mjs
generated
vendored
Normal file
8
node_modules/peberminta/lib/util.mjs
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
function clamp(left, x, right) {
|
||||
return Math.max(left, Math.min(x, right));
|
||||
}
|
||||
function escapeWhitespace(str) {
|
||||
return str.replace(/(\t)|(\r)|(\n)/g, (m, t, r) => t ? '\\t' : r ? '\\r' : '\\n');
|
||||
}
|
||||
|
||||
export { clamp, escapeWhitespace };
|
115
node_modules/peberminta/package.json
generated
vendored
Normal file
115
node_modules/peberminta/package.json
generated
vendored
Normal file
@@ -0,0 +1,115 @@
|
||||
{
|
||||
"name": "peberminta",
|
||||
"version": "0.9.0",
|
||||
"description": "Simple, transparent parser combinators toolkit that supports any tokens",
|
||||
"keywords": [
|
||||
"parser",
|
||||
"parser-combinators",
|
||||
"parsec"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/mxxii/peberminta.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/mxxii/peberminta/issues"
|
||||
},
|
||||
"homepage": "https://github.com/mxxii/peberminta",
|
||||
"author": "KillyMXI",
|
||||
"funding": "https://ko-fi.com/killymxi",
|
||||
"license": "MIT",
|
||||
"exports": {
|
||||
".": {
|
||||
"import": "./lib/core.mjs",
|
||||
"require": "./lib/core.cjs"
|
||||
},
|
||||
"./char": {
|
||||
"import": "./lib/char.mjs",
|
||||
"require": "./lib/char.cjs"
|
||||
}
|
||||
},
|
||||
"type": "module",
|
||||
"main": "./lib/core.cjs",
|
||||
"module": "./lib/core.mjs",
|
||||
"types": "./lib/core.d.ts",
|
||||
"typesVersions": {
|
||||
"*": {
|
||||
"char": [
|
||||
"./lib/char.d.ts"
|
||||
],
|
||||
"*": [
|
||||
"./lib/core.d.ts"
|
||||
]
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"lib"
|
||||
],
|
||||
"sideEffects": false,
|
||||
"scripts": {
|
||||
"build:docs": "typedoc",
|
||||
"build:deno": "denoify",
|
||||
"build:rollup": "rollup -c",
|
||||
"build:types": "tsc --declaration --emitDeclarationOnly && rimraf lib/util.d.ts",
|
||||
"build": "npm run clean && concurrently npm:build:*",
|
||||
"checkAll": "npm run lint && npm test",
|
||||
"clean": "rimraf lib && rimraf docs && rimraf deno",
|
||||
"cover": "c8 --reporter=lcov --reporter=text-summary ava \"test/!(examples).ts\" --timeout=60s",
|
||||
"example:bf1": "npm run ts -- ./examples/bf1.ts",
|
||||
"example:bf2": "npm run ts -- ./examples/bf2.ts",
|
||||
"example:calc": "npm run ts -- ./examples/calc.ts",
|
||||
"example:csv": "npm run ts -- ./examples/csv.ts",
|
||||
"example:hexColor": "npm run ts -- ./examples/hexColor.ts",
|
||||
"example:json": "npm run ts -- ./examples/json.ts",
|
||||
"example:nonDec": "npm run ts -- ./examples/nonDec.ts",
|
||||
"lint:eslint": "eslint .",
|
||||
"lint:md": "markdownlint-cli2",
|
||||
"lint": "concurrently npm:lint:*",
|
||||
"prepublishOnly": "npm run build && npm run checkAll",
|
||||
"test:ava": "ava --timeout=20s",
|
||||
"test:tsc": "tsc --noEmit --project tsconfig.tsc.json",
|
||||
"test": "concurrently npm:test:*",
|
||||
"ts": "node --experimental-specifier-resolution=node --loader ts-node/esm"
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-typescript": "^11.0.0",
|
||||
"@tsconfig/node14": "^1.0.3",
|
||||
"@types/node": "14.18.36",
|
||||
"@typescript-eslint/eslint-plugin": "^5.48.2",
|
||||
"@typescript-eslint/parser": "^5.48.2",
|
||||
"ava": "^5.1.1",
|
||||
"c8": "^7.12.0",
|
||||
"concurrently": "^7.6.0",
|
||||
"denoify": "^1.4.5",
|
||||
"eslint": "^8.32.0",
|
||||
"eslint-plugin-jsonc": "^2.6.0",
|
||||
"eslint-plugin-tsdoc": "^0.2.17",
|
||||
"expect-type": "^0.15.0",
|
||||
"leac": "^0.6.0",
|
||||
"markdownlint-cli2": "^0.6.0",
|
||||
"rimraf": "^4.1.1",
|
||||
"rollup": "^2.79.1",
|
||||
"rollup-plugin-cleanup": "^3.2.1",
|
||||
"ts-node": "^10.9.1",
|
||||
"tslib": "^2.4.1",
|
||||
"typedoc": "~0.23.24",
|
||||
"typescript": "~4.9.4"
|
||||
},
|
||||
"ava": {
|
||||
"extensions": {
|
||||
"ts": "module"
|
||||
},
|
||||
"files": [
|
||||
"test/**/*"
|
||||
],
|
||||
"nodeArguments": [
|
||||
"--loader=ts-node/esm",
|
||||
"--experimental-specifier-resolution=node"
|
||||
],
|
||||
"verbose": true
|
||||
},
|
||||
"denoify": {
|
||||
"out": "./deno"
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user