Skip to content

Commit 510ef34

Browse files
committed
Tests
1 parent 6659d53 commit 510ef34

File tree

8 files changed

+383
-64
lines changed

8 files changed

+383
-64
lines changed

example/index.ts

Lines changed: 134 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,145 @@
11
// deno-fmt-ignore-file
2-
// deno-lint-ignore-file
32

4-
import { Static, Runtime } from '@sinclair/parsebox'
5-
import { Type as T, Static as S } from 'npm:@sinclair/typebox'
3+
import { Static, Runtime, Compile } from '@sinclair/parsebox'
4+
import { Syntax } from './typebox/compiled/index.ts'
5+
import { ParseJson } from './json/index.ts'
6+
import { ParseEbnf } from './ebnf/index.ts'
67

7-
import { Module } from './typebox/interpreted/runtime.ts'
8-
import { Type } from './typebox/compiled/parser.ts'
8+
// ------------------------------------------------------------------
9+
//
10+
// Example: TypeBox | Compiled
11+
//
12+
// ParseBox is the working project for developing the TypeBox syntax
13+
// parsers. You can test TypeBox inference here. Check the TypeBox
14+
// directory for Compiled and Interpreted variants.
15+
//
16+
// ------------------------------------------------------------------
17+
const Type = Syntax(`{
18+
x: number,
19+
y: number,
20+
z: number
21+
}`)
922

10-
// const Result = Module.Parse('Type',
11-
// 'Record<`${0|1}${0|1}${0|1}${0|1}${0|1}${0|1}${0|1}${0|1}`, { x: `hello${1|2}` }>'
12-
// )[0]
23+
console.dir(Type, { depth: 100 })
1324

14-
import { Syntax } from './typebox/interpreted/syntax.ts'
25+
// ------------------------------------------------------------------
26+
//
27+
// Example: Ebnf | Interpreted
28+
//
29+
// ------------------------------------------------------------------
30+
const Ebnf = ParseEbnf(`
1531
16-
const K = Syntax('`${0|1}${0|1}${0|1}${0|1}${0|1}`')
32+
Operand ::= Ident ;
1733
18-
const A = Syntax({ K }, `{ x: K }`)
34+
Factor ::= "(" Expr ")"
35+
| Operand ;
1936
20-
function test(value: S<typeof A>) {
21-
22-
}
37+
TermTail ::= ("*" Factor TermTail)
38+
| ("/" Factor TermTail)
39+
| e ;
40+
41+
ExprTail ::= ("+" Term ExprTail)
42+
| ("-" Term ExprTail)
43+
| e ;
44+
45+
Term ::= Factor TermTail ;
46+
47+
Expr ::= Term ExprTail ;
48+
49+
`)
2350

24-
console.log(A)
51+
const Result = Ebnf.Parse('Expr', `X * (Y + Z)`)
2552

53+
console.dir(Result, { depth: 100 })
2654

55+
// ------------------------------------------------------------------
56+
//
57+
// Example: Json | Interpreted
58+
//
59+
// ------------------------------------------------------------------
60+
const Json = ParseJson(`{
61+
"x": 1,
62+
"y": 2,
63+
"z": 3
64+
}`)
65+
66+
console.log(Json)
67+
68+
// ------------------------------------------------------------------
69+
//
70+
// Example: Expression | Interpreted
71+
//
72+
// ------------------------------------------------------------------
73+
{
74+
type Result = Static.Parse<Expr, 'x * (y + z)'> // hover
75+
76+
type BinaryReduce<Left extends unknown, Right extends unknown[]> = (
77+
Right extends [infer Operator, infer Right, infer Rest extends unknown[]]
78+
? { left: Left; operator: Operator; right: BinaryReduce<Right, Rest> }
79+
: Left
80+
)
81+
interface BinaryMapping extends Static.IMapping {
82+
output: this['input'] extends [infer Left, infer Right extends unknown[]]
83+
? BinaryReduce<Left, Right>
84+
: never
85+
}
86+
interface FactorMapping extends Static.IMapping {
87+
output: (
88+
this['input'] extends ['(', infer Expr, ')'] ? Expr :
89+
this['input'] extends [infer Operand] ? Operand :
90+
never
91+
)
92+
}
93+
type Operand = Static.Ident
94+
type Factor = Static.Union<[
95+
Static.Tuple<[Static.Const<'('>, Expr, Static.Const<')'>]>,
96+
Static.Tuple<[Operand]>
97+
], FactorMapping>
98+
99+
type TermTail = Static.Union<[
100+
Static.Tuple<[Static.Const<'*'>, Factor, TermTail]>,
101+
Static.Tuple<[Static.Const<'/'>, Factor, TermTail]>,
102+
Static.Tuple<[]>
103+
]>
104+
type ExprTail = Static.Union<[
105+
Static.Tuple<[Static.Const<'+'>, Term, ExprTail]>,
106+
Static.Tuple<[Static.Const<'-'>, Term, ExprTail]>,
107+
Static.Tuple<[]>
108+
]>
109+
type Term = Static.Tuple<[Factor, TermTail], BinaryMapping>
110+
type Expr = Static.Tuple<[Term, ExprTail], BinaryMapping>
111+
}
112+
// ------------------------------------------------------------------
113+
//
114+
// Example: Compiled Parser
115+
//
116+
// ParseBox supports module compilation, generating optimized parsers
117+
// for JavaScript and TypeScript. The compilation process produces
118+
// two files:
119+
//
120+
// 1. A parser file derived from the grammar.
121+
// 2. A semantic mapping file.
122+
//
123+
// While compilation ensures valid code and a functional parser,
124+
// semantic actions must be implemented manually.
125+
//
126+
// ------------------------------------------------------------------
127+
{
128+
const ListModule = new Runtime.Module({
129+
List: Runtime.Union([
130+
Runtime.Tuple([Runtime.Ident(), Runtime.Const(','), Runtime.Ref('List')]),
131+
Runtime.Tuple([Runtime.Ident(), Runtime.Const(',')]),
132+
Runtime.Tuple([Runtime.Ident()]),
133+
Runtime.Tuple([]),
134+
])
135+
})
136+
const project = Compile.Project(ListModule, {
137+
contextDefault: '{}',
138+
contextType: 'unknown',
139+
mappingPath: './mapping',
140+
mappingImports: [],
141+
parserImports: []
142+
})
143+
console.log(project.parser) // parser file content
144+
console.log(project.mapping) // semantic mapping file content
145+
}

readme.md

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,10 @@ License: MIT
6666
6767
- [Combinators](#Combinators)
6868
- [Const](#Const)
69-
- [Until](#Until)
7069
- [Tuple](#Tuple)
7170
- [Union](#Union)
7271
- [Array](#Array)
72+
- [Until](#Until)
7373
- [Optional](#Optional)
7474
- [Epsilon](#Epsilon)
7575
- [Terminals](#Terminals)
@@ -107,28 +107,6 @@ const T = Runtime.Const('X') // const T = {
107107
const R = Runtime.Parse(T, 'X Y Z') // const R = ['X', ' Y Z']
108108
```
109109

110-
111-
### Until
112-
113-
The Until combinator parses all characters up unto the specified string. This parser parser will leave the specified string unconsumed. If the specified string is not found, this parser will fail.
114-
115-
**BNF**
116-
117-
```bnf
118-
<T> ::= ? any character until 'Z' ?
119-
```
120-
121-
**TypeScript**
122-
123-
```typescript
124-
const T = Runtime.Until('Z') // const T = {
125-
// type: 'Until',
126-
// value: 'X'
127-
// }
128-
129-
const R = Runtime.Parse(T, 'X Y Z') // const R = ['X Y ', 'Z']
130-
```
131-
132110
### Tuple
133111

134112
The Tuple parser matches a sequence of parsers, with an empty tuple representing Epsilon (the empty production).
@@ -209,6 +187,27 @@ const R2 = Runtime.Parse(T, 'X X X Y Z') // const R2 = [['X', 'X', '
209187
const R3 = Runtime.Parse(T, 'Y Z') // const R3 = [[], 'Y Z']
210188
```
211189

190+
### Until
191+
192+
The Until combinator parses all characters up to (but not including) the specified string. The specified string remains unconsumed in the input. If the string 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+
// value: 'X'
206+
// }
207+
208+
const R = Runtime.Parse(T, 'X Y Z') // const R = ['X Y ', 'Z']
209+
```
210+
212211
### Optional
213212

214213
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.

src/compile/common/comment.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ function FromRef(parser: Runtime.IRef): string {
5353
function FromConst(parser: Runtime.IConst): string {
5454
return `'${Escape(parser.value)}'`
5555
}
56+
function FromUntil(parser: Runtime.IUntil): string {
57+
return `string`
58+
}
5659
function FromIdent(parser: Runtime.IIdent): string {
5760
return `<Ident>`
5861
}
@@ -71,6 +74,7 @@ function FromParser(parser: Runtime.IParser): string {
7174
Runtime.IsOptional(parser) ? FromOptional(parser) :
7275
Runtime.IsString(parser) ? FromString(parser) :
7376
Runtime.IsConst(parser) ? FromConst(parser) :
77+
Runtime.IsUntil(parser) ? FromUntil(parser) :
7478
Runtime.IsRef(parser) ? FromRef(parser) :
7579
Runtime.IsIdent(parser) ? FromIdent(parser) :
7680
Runtime.IsNumber(parser) ? FromNumber(parser) :

src/compile/common/infer.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ function InferOptional(parser: Runtime.IParser) {
4949
function InferConst(parser: Runtime.IConst) {
5050
return `'${parser.value}'`
5151
}
52+
function InferUntil(parser: Runtime.IUntil) {
53+
return `string`
54+
}
5255
export function Infer(parser: Runtime.IParser): string {
5356
return (
5457
Runtime.IsContext(parser) ? InferContext(parser.right, parser.right) :
@@ -58,6 +61,7 @@ export function Infer(parser: Runtime.IParser): string {
5861
Runtime.IsOptional(parser) ? InferOptional(parser.parser) :
5962
Runtime.IsRef(parser) ? `unknown` :
6063
Runtime.IsConst(parser) ? InferConst(parser) :
64+
Runtime.IsUntil(parser) ? InferUntil(parser) :
6165
Runtime.IsString(parser) ? `string` :
6266
Runtime.IsIdent(parser) ? `string` :
6367
Runtime.IsNumber(parser) ? `string` :

src/static/token.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,6 @@ type NextConst<Value extends string, Code extends string> = (
113113
: []
114114
)
115115
/** Scans for the next constant value */
116-
117116
export type Const<Value extends string, Code extends string> = (
118117
Value extends '' ? ['', Code] :
119118
Value extends `${infer First extends string}${string}`
@@ -126,19 +125,16 @@ export type Const<Value extends string, Code extends string> = (
126125
// ------------------------------------------------------------------
127126
// Number
128127
// ------------------------------------------------------------------
129-
130128
type NextNumberNegate<Code extends string> = (
131129
Code extends `${Chars.Hyphen}${infer Rest extends string}`
132130
? [Chars.Hyphen, Rest]
133131
: [Chars.Empty, Code]
134132
)
135-
136133
type NextNumberZeroCheck<Code extends string> = (
137134
Code extends `0${infer Rest}`
138135
? NextUnion<Chars.Digit, Rest> extends [string, string] ? false : true
139136
: true
140137
)
141-
142138
type NextNumberScan<Code extends string, HasDecimal extends boolean = false, Result extends string = Chars.Empty> = (
143139
NextUnion<[...Chars.Digit, Chars.Dot], Code> extends [infer Char extends string, infer Rest extends string]
144140
? Char extends Chars.Dot
@@ -148,7 +144,6 @@ type NextNumberScan<Code extends string, HasDecimal extends boolean = false, Res
148144
: NextNumberScan<Rest, HasDecimal, `${Result}${Char}`>
149145
: [Result, Code]
150146
)
151-
152147
export type NextNumber<Code extends string> = (
153148
NextNumberNegate<Code> extends [infer Negate extends string, infer Rest extends string]
154149
? NextNumberZeroCheck<Rest> extends true

tasks.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ Task.run('start', async () => {
2222
// Test
2323
// ------------------------------------------------------------------
2424
Task.run('test', async () => {
25-
await Task.shell('deno test -A test')
25+
await Task.shell('deno test -A --watch test')
2626
})
2727
// ------------------------------------------------------------------
2828
// Build

0 commit comments

Comments
 (0)