Skip to content

Commit 906cbf9

Browse files
authored
Revision 0.9.7 (#9)
1 parent 9599c21 commit 906cbf9

14 files changed

Lines changed: 519 additions & 149 deletions

File tree

readme.md

Lines changed: 55 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,11 @@ License: MIT
6969
- [Tuple](#Tuple)
7070
- [Union](#Union)
7171
- [Array](#Array)
72-
- [Until](#Until)
7372
- [Optional](#Optional)
7473
- [Epsilon](#Epsilon)
74+
- [Range](#Range)
75+
- [Until](#Until)
76+
- [UntilNonEmpty](#UntilNonEmpty)
7577
- [Terminals](#Terminals)
7678
- [Number](#Number)
7779
- [String](#String)
@@ -187,27 +189,6 @@ const R2 = Runtime.Parse(T, 'X X X Y Z') // const R2 = [['X', 'X', '
187189
const R3 = Runtime.Parse(T, 'Y Z') // const R3 = [[], 'Y Z']
188190
```
189191

190-
### Until
191-
192-
The Until combinator will parse characters up to (but not including) one of the specified sentinel string values. If a sentinel value is not found, parsing fails.
193-
194-
**BNF**
195-
196-
```bnf
197-
<T> ::= ? any character until ['Z'] ?
198-
```
199-
200-
**TypeScript**
201-
202-
```typescript
203-
const T = Runtime.Until(['Z']) // const T = {
204-
// type: 'Until',
205-
// values: ['Z']
206-
// }
207-
208-
const R = Runtime.Parse(T, 'X Y Z') // const R = ['X Y ', 'Z']
209-
```
210-
211192
### Optional
212193

213194
The Optional combinator parses zero or one occurrence of the interior parser, returning a tuple with one element or an empty tuple if there is no match.
@@ -256,7 +237,58 @@ const R1 = Runtime.Parse(T, 'X Y Z') // const R1 = [['X', 'Y'], '
256237
const R2 = Runtime.Parse(T, 'Y Z') // const R2 = [[], 'Y Z']
257238
```
258239

259-
## Terminals
240+
## Range Combinators
241+
242+
ParseBox range combinators match character sequences up to one or more terminating sentinel strings. These combinators are used to match arbituary Unicode (UTF-16) sequences.
243+
244+
245+
### Until
246+
247+
The Until combinator parses characters up to (but not including) one of the specified sentinel string values. It captures all characters encountered before the sentinel. If a sentinel value is not found in the input, parsing fails. Until succeeds even if it matches a zero-length string. This occurs if a sentinel is found immediately at the current parsing position.
248+
249+
**BNF**
250+
251+
```bnf
252+
<T> ::= ? any character sequence (0 or more) until 'Z' ?
253+
```
254+
255+
**TypeScript**
256+
257+
```typescript
258+
const T = Runtime.Until(['Z']) // const T = {
259+
// type: 'Until',
260+
// values: ['Z']
261+
// }
262+
263+
const R = Runtime.Parse(T, 'X Y Z') // const R = ['X Y ', 'Z']
264+
```
265+
266+
### UntilNonEmpty
267+
268+
The UntilNonEmpty combinator works the same as Until, but it fails if the parsed content yields a zero-length string.
269+
270+
**BNF**
271+
272+
```bnf
273+
<T> ::= ? any character sequence (1 or more) until 'Z'. fails on zero length ?
274+
```
275+
276+
**TypeScript**
277+
278+
```typescript
279+
const T = Runtime.UntilNonEmpty(['Z']) // const T = {
280+
// type: 'UntilNonEmpty',
281+
// values: ['Z']
282+
// }
283+
284+
const R1 = Runtime.Parse(T, 'X Y Z') // const R1 = ['X Y ', 'Z']
285+
286+
const R2 = Runtime.Parse(T, ' Z') // const R2 = [' ', 'Z']
287+
288+
const R3 = Runtime.Parse(T, 'Z') // const R3 = []
289+
```
290+
291+
## Terminal Combinators
260292

261293
ParseBox provides combinators for parsing common lexical tokens, such as numbers, identifiers, and strings, enabling static, optimized parsing of typical JavaScript constructs.
262294

src/compile/common/comment.ts

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -27,58 +27,62 @@ THE SOFTWARE.
2727
---------------------------------------------------------------------------*/
2828

2929
// deno-fmt-ignore-file
30-
// deno-lint-ignore-file no-unused-vars
30+
// deno-lint-ignore-file
3131

3232
import { Runtime } from '../../runtime/index.ts'
3333
import { Unreachable } from './unreachable.ts'
3434
import { Escape } from './escape.ts'
3535

36+
function FromArray(parser: Runtime.IArray): string {
37+
return `${FromParser(parser.parser)}[]`
38+
}
3639
function FromContext(parser: Runtime.IContext): string {
3740
return `${FromParser(parser.left)} -> ${FromParser(parser.right)}`
3841
}
39-
function FromTuple(parser: Runtime.ITuple): string {
40-
return `[${parser.parsers.map((parser) => `${FromParser(parser)}`).join(', ')}]`
42+
function FromConst(parser: Runtime.IConst): string {
43+
return `'${Escape(parser.value)}'`
4144
}
42-
function FromUnion(parser: Runtime.IUnion): string {
43-
return parser.parsers.map((parser) => `${FromParser(parser)}`).join(' | ')
45+
function FromIdent(parser: Runtime.IIdent): string {
46+
return `<Ident>`
4447
}
45-
function FromArray(parser: Runtime.IArray): string {
46-
return `${FromParser(parser.parser)}[]`
48+
function FromNumber(parser: Runtime.INumber): string {
49+
return `<Number>`
4750
}
4851
function FromOptional(parser: Runtime.IOptional): string {
4952
return `${FromParser(parser.parser)}?`
5053
}
5154
function FromRef(parser: Runtime.IRef): string {
5255
return `${parser.ref}`
5356
}
54-
function FromConst(parser: Runtime.IConst): string {
55-
return `'${Escape(parser.value)}'`
57+
function FromString(parser: Runtime.IString): string {
58+
return `<String>`
5659
}
57-
function FromUntil(parser: Runtime.IUntil): string {
58-
return `string`
60+
function FromTuple(parser: Runtime.ITuple): string {
61+
return `[${parser.parsers.map((parser) => `${FromParser(parser)}`).join(', ')}]`
5962
}
60-
function FromIdent(parser: Runtime.IIdent): string {
61-
return `<Ident>`
63+
function FromUnion(parser: Runtime.IUnion): string {
64+
return parser.parsers.map((parser) => `${FromParser(parser)}`).join(' | ')
6265
}
63-
function FromString(parser: Runtime.IString): string {
64-
return `<String>`
66+
function FromUntil(parser: Runtime.IUntil): string {
67+
return `string`
6568
}
66-
function FromNumber(parser: Runtime.INumber): string {
67-
return `<Number>`
69+
function FromUntilNonEmpty(parser: Runtime.IUntilNonEmpty): string {
70+
return `string`
6871
}
6972
function FromParser(parser: Runtime.IParser): string {
7073
return (
71-
Runtime.IsContext(parser) ? FromContext(parser) :
72-
Runtime.IsTuple(parser) ? FromTuple(parser) :
73-
Runtime.IsUnion(parser) ? FromUnion(parser) :
7474
Runtime.IsArray(parser) ? FromArray(parser) :
75+
Runtime.IsContext(parser) ? FromContext(parser) :
76+
Runtime.IsConst(parser) ? FromConst(parser) :
77+
Runtime.IsIdent(parser) ? FromIdent(parser) :
78+
Runtime.IsNumber(parser) ? FromNumber(parser) :
7579
Runtime.IsOptional(parser) ? FromOptional(parser) :
80+
Runtime.IsRef(parser) ? FromRef(parser) :
7681
Runtime.IsString(parser) ? FromString(parser) :
77-
Runtime.IsConst(parser) ? FromConst(parser) :
82+
Runtime.IsTuple(parser) ? FromTuple(parser) :
83+
Runtime.IsUnion(parser) ? FromUnion(parser) :
7884
Runtime.IsUntil(parser) ? FromUntil(parser) :
79-
Runtime.IsRef(parser) ? FromRef(parser) :
80-
Runtime.IsIdent(parser) ? FromIdent(parser) :
81-
Runtime.IsNumber(parser) ? FromNumber(parser) :
85+
Runtime.IsUntilNonEmpty(parser) ? FromUntilNonEmpty(parser) :
8286
Unreachable(parser)
8387
)
8488
}

src/compile/common/infer.ts

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -32,40 +32,58 @@ THE SOFTWARE.
3232
import { Runtime } from '../../runtime/index.ts'
3333
import { Unreachable } from './unreachable.ts'
3434

35-
function InferUnion(parsers: Runtime.IParser[]): string {
36-
return [...new Set(parsers.map((parser) => Infer(parser)))].join(' | ')
37-
}
38-
function InferTuple(parsers: Runtime.IParser[]): string {
39-
return `[${parsers.map(() => 'unknown').join(', ')}]`
40-
}
4135
function InferArray(parser: Runtime.IParser): string {
4236
return `(${Infer(parser)})[]`
4337
}
4438
function InferContext(left: Runtime.IParser, right: Runtime.IParser) {
4539
return Infer(right)
4640
}
41+
function InferConst(parser: Runtime.IConst) {
42+
return `'${parser.value}'`
43+
}
4744
function InferOptional(parser: Runtime.IParser) {
4845
return `([${Infer(parser)}] | [])`
4946
}
50-
function InferConst(parser: Runtime.IConst) {
51-
return `'${parser.value}'`
47+
48+
49+
function InferUnion(parsers: Runtime.IParser[]): string {
50+
return [...new Set(parsers.map((parser) => Infer(parser)))].join(' | ')
51+
}
52+
function InferString(parser: Runtime.IString) {
53+
return `string`
54+
}
55+
function InferRef(parser: Runtime.IRef) {
56+
return `unknown`
57+
}
58+
function InferIdent(parser: Runtime.IIdent) {
59+
return `string`
60+
}
61+
function InferNumber(parser: Runtime.INumber) {
62+
return `string`
63+
}
64+
function InferTuple(parsers: Runtime.IParser[]): string {
65+
return `[${parsers.map(() => 'unknown').join(', ')}]`
5266
}
5367
function InferUntil(parser: Runtime.IUntil) {
5468
return `string`
5569
}
70+
function InferUntilNonEmpty(parser: Runtime.IUntilNonEmpty) {
71+
return `string`
72+
}
5673
export function Infer(parser: Runtime.IParser): string {
5774
return (
75+
Runtime.IsArray(parser) ? InferArray(parser.parser) :
5876
Runtime.IsContext(parser) ? InferContext(parser.right, parser.right) :
77+
Runtime.IsConst(parser) ? InferConst(parser) :
78+
Runtime.IsIdent(parser) ? InferIdent(parser) :
79+
Runtime.IsNumber(parser) ? InferNumber(parser) :
80+
Runtime.IsOptional(parser) ? InferOptional(parser.parser) :
81+
Runtime.IsRef(parser) ? InferRef(parser) :
82+
Runtime.IsString(parser) ? InferString(parser) :
5983
Runtime.IsTuple(parser) ? InferTuple(parser.parsers) :
6084
Runtime.IsUnion(parser) ? InferUnion(parser.parsers) :
61-
Runtime.IsArray(parser) ? InferArray(parser.parser) :
62-
Runtime.IsOptional(parser) ? InferOptional(parser.parser) :
63-
Runtime.IsRef(parser) ? `unknown` :
64-
Runtime.IsConst(parser) ? InferConst(parser) :
6585
Runtime.IsUntil(parser) ? InferUntil(parser) :
66-
Runtime.IsString(parser) ? `string` :
67-
Runtime.IsIdent(parser) ? `string` :
68-
Runtime.IsNumber(parser) ? `string` :
86+
Runtime.IsUntilNonEmpty(parser) ? InferUntilNonEmpty(parser) :
6987
Unreachable(parser)
7088
)
7189
}

src/compile/func/func.ts

Lines changed: 46 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -44,20 +44,6 @@ function FromContext(options: Options, name: string, left: Runtime.IParser, righ
4444
return `If(${FromParser(options, name, left)}, ([_0, input]) => ${FromParser(options, name, right).replace('context', `_0 as ${options.contextType}`)}, () => [])`
4545
}
4646
// ------------------------------------------------------------------
47-
// Tuple
48-
// ------------------------------------------------------------------
49-
function FromTuple(options: Options, name: string, parsers: Runtime.IParser[]): string {
50-
const parameters = `[${parsers.map((_, index) => `_${index}`).join(', ')}]`
51-
const initial = `[${parameters}, input]`
52-
return parsers.reduceRight((result, right, index) => `If(${FromParser(options, name, right)}, ([_${index}, input]) => ${result})`, initial)
53-
}
54-
// ------------------------------------------------------------------
55-
// Union
56-
// ------------------------------------------------------------------
57-
function FromUnion(options: Options, name: string, parsers: Runtime.IParser[]): string {
58-
return parsers.length === 0 ? '[]' : parsers.reduceRight((result, right) => `If(${FromParser(options, name, right)}, ([_0, input]) => [_0, input], () => ${result})`, '[]')
59-
}
60-
// ------------------------------------------------------------------
6147
// Array
6248
// ------------------------------------------------------------------
6349
function FromArrayReducer(options: Options, name: string, parser: Runtime.IParser): string {
@@ -71,25 +57,12 @@ function FromArray(options: Options, name: string, parser: Runtime.IParser): str
7157
return `${reducer_name}(input, context)`
7258
}
7359
// ------------------------------------------------------------------
74-
// Optional
75-
// ------------------------------------------------------------------
76-
function FromOptional(options: Options, name: string, parser: Runtime.IOptional): string {
77-
return `If(${FromParser(options, name, parser.parser)}, ([_0, input]) => [[_0], input], () => [[], input])`
78-
}
79-
// ------------------------------------------------------------------
8060
// Const
8161
// ------------------------------------------------------------------
8262
function FromConst(options: Options, name: string, value: string): string {
8363
return `Runtime.Token.Const('${Escape(value)}', input)`
8464
}
8565
// ------------------------------------------------------------------
86-
// Const
87-
// ------------------------------------------------------------------
88-
function FromUntil(options: Options, name: string, values: string[]): string {
89-
const escaped = values.map(value => `'${Escape(value)}'`)
90-
return `Runtime.Token.Until([${escaped.join(', ')}], input)`
91-
}
92-
// ------------------------------------------------------------------
9366
// Ident
9467
// ------------------------------------------------------------------
9568
function FromIdent(options: Options, name: string): string {
@@ -102,34 +75,69 @@ function FromNumber(options: Options, name: string): string {
10275
return `Runtime.Token.Number(input)`
10376
}
10477
// ------------------------------------------------------------------
78+
// Optional
79+
// ------------------------------------------------------------------
80+
function FromOptional(options: Options, name: string, parser: Runtime.IOptional): string {
81+
return `If(${FromParser(options, name, parser.parser)}, ([_0, input]) => [[_0], input], () => [[], input])`
82+
}
83+
// ------------------------------------------------------------------
84+
// Ref
85+
// ------------------------------------------------------------------
86+
function FromRef(options: Options, name: string, ref: string): string {
87+
return `${ref}(input, context)`
88+
}
89+
// ------------------------------------------------------------------
10590
// String
10691
// ------------------------------------------------------------------
10792
function FromString(options: Options, name: string, string_options: string[]): string {
10893
const _options = string_options.map((option) => `'${Escape(option)}'`).join(', ')
10994
return `Runtime.Token.String([${_options}], input)`
11095
}
11196
// ------------------------------------------------------------------
112-
// Ref
97+
// Tuple
11398
// ------------------------------------------------------------------
114-
function FromRef(options: Options, name: string, ref: string): string {
115-
return `${ref}(input, context)`
99+
function FromTuple(options: Options, name: string, parsers: Runtime.IParser[]): string {
100+
const parameters = `[${parsers.map((_, index) => `_${index}`).join(', ')}]`
101+
const initial = `[${parameters}, input]`
102+
return parsers.reduceRight((result, right, index) => `If(${FromParser(options, name, right)}, ([_${index}, input]) => ${result})`, initial)
116103
}
117104
// ------------------------------------------------------------------
118-
// Ref
105+
// Union
106+
// ------------------------------------------------------------------
107+
function FromUnion(options: Options, name: string, parsers: Runtime.IParser[]): string {
108+
return parsers.length === 0 ? '[]' : parsers.reduceRight((result, right) => `If(${FromParser(options, name, right)}, ([_0, input]) => [_0, input], () => ${result})`, '[]')
109+
}
110+
// ------------------------------------------------------------------
111+
// Until
112+
// ------------------------------------------------------------------
113+
function FromUntil(options: Options, name: string, values: string[]): string {
114+
const escaped = values.map(value => `'${Escape(value)}'`)
115+
return `Runtime.Token.Until([${escaped.join(', ')}], input)`
116+
}
117+
// ------------------------------------------------------------------
118+
// UntilNonEmpty
119+
// ------------------------------------------------------------------
120+
function FromUntilNonEmpty(options: Options, name: string, values: string[]): string {
121+
const escaped = values.map(value => `'${Escape(value)}'`)
122+
return `Runtime.Token.UntilNonEmpty([${escaped.join(', ')}], input)`
123+
}
124+
// ------------------------------------------------------------------
125+
// Parser
119126
// ------------------------------------------------------------------
120127
function FromParser(options: Options, name: string, parser: Runtime.IParser): string {
121128
return (
122-
Runtime.IsContext(parser) ? FromContext(options, name, parser.left, parser.right) :
123-
Runtime.IsTuple(parser) ? FromTuple(options, name, parser.parsers) :
124-
Runtime.IsUnion(parser) ? FromUnion(options, name, parser.parsers) :
125129
Runtime.IsArray(parser) ? FromArray(options, name, parser.parser) :
126-
Runtime.IsOptional(parser) ? FromOptional(options, name, parser) :
127-
Runtime.IsString(parser) ? FromString(options, name, parser.options) :
130+
Runtime.IsContext(parser) ? FromContext(options, name, parser.left, parser.right) :
128131
Runtime.IsConst(parser) ? FromConst(options, name, parser.value) :
129-
Runtime.IsUntil(parser) ? FromUntil(options, name, parser.values) :
130-
Runtime.IsRef(parser) ? FromRef(options, name, parser.ref) :
131132
Runtime.IsIdent(parser) ? FromIdent(options, name) :
132133
Runtime.IsNumber(parser) ? FromNumber(options, name) :
134+
Runtime.IsOptional(parser) ? FromOptional(options, name, parser) :
135+
Runtime.IsRef(parser) ? FromRef(options, name, parser.ref) :
136+
Runtime.IsString(parser) ? FromString(options, name, parser.options) :
137+
Runtime.IsTuple(parser) ? FromTuple(options, name, parser.parsers) :
138+
Runtime.IsUnion(parser) ? FromUnion(options, name, parser.parsers) :
139+
Runtime.IsUntil(parser) ? FromUntil(options, name, parser.values) :
140+
Runtime.IsUntilNonEmpty(parser) ? FromUntilNonEmpty(options, name, parser.values) :
133141
Unreachable(parser)
134142
)
135143
}

0 commit comments

Comments
 (0)