Skip to content

Commit 6659d53

Browse files
committed
Until Combinator
1 parent 8ccf1a2 commit 6659d53

File tree

17 files changed

+612
-387
lines changed

17 files changed

+612
-387
lines changed

example/index.ts

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

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'
4+
import { Static, Runtime } from '@sinclair/parsebox'
5+
import { Type as T, Static as S } from 'npm:@sinclair/typebox'
76

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-
}`)
7+
import { Module } from './typebox/interpreted/runtime.ts'
8+
import { Type } from './typebox/compiled/parser.ts'
229

23-
console.dir(Type, { depth: 100 })
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]
2413

25-
// ------------------------------------------------------------------
26-
//
27-
// Example: Ebnf | Interpreted
28-
//
29-
// ------------------------------------------------------------------
30-
const Ebnf = ParseEbnf(`
14+
import { Syntax } from './typebox/interpreted/syntax.ts'
3115

32-
Operand ::= Ident ;
16+
const K = Syntax('`${0|1}${0|1}${0|1}${0|1}${0|1}`')
3317

34-
Factor ::= "(" Expr ")"
35-
| Operand ;
18+
const A = Syntax({ K }, `{ x: K }`)
3619

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-
`)
50-
51-
const Result = Ebnf.Parse('Expr', `X * (Y + Z)`)
52-
53-
console.dir(Result, { depth: 100 })
54-
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)
20+
function test(value: S<typeof A>) {
21+
22+
}
6723

68-
// ------------------------------------------------------------------
69-
//
70-
// Example: Expression | Interpreted
71-
//
72-
// ------------------------------------------------------------------
73-
{
74-
type Result = Static.Parse<Expr, 'x * (y + z)'> // hover
24+
console.log(A)
7525

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>
9826

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-
}

example/typebox/compiled/module.ts

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,11 +99,40 @@ const GenericReference = Runtime.Tuple([
9999
// Reference
100100
// ------------------------------------------------------------------
101101
const Reference = Runtime.Ident()
102-
102+
// ------------------------------------------------------------------
103+
// TemplateText
104+
// ------------------------------------------------------------------
105+
const TemplateText = Runtime.Union([
106+
Runtime.Until('${'),
107+
Runtime.Until('`'),
108+
])
109+
// ------------------------------------------------------------------
110+
// TemplateInterpolate
111+
// ------------------------------------------------------------------
112+
const TemplateInterpolate = Runtime.Tuple([
113+
Runtime.Const('${'),
114+
Runtime.Ref('Type'),
115+
Runtime.Const('}')
116+
])
117+
// ------------------------------------------------------------------
118+
// TemplateBody
119+
// ------------------------------------------------------------------
120+
const TemplateBody = Runtime.Union([
121+
Runtime.Tuple([Runtime.Ref('TemplateText'), Runtime.Ref('TemplateInterpolate'), Runtime.Ref('TemplateBody')]),
122+
Runtime.Tuple([Runtime.Ref('TemplateText')]),
123+
])
124+
// ------------------------------------------------------------------
125+
// TemplateLiteral
126+
// ------------------------------------------------------------------
127+
const TemplateLiteral = Runtime.Tuple([
128+
Runtime.Const('`'),
129+
Runtime.Ref('TemplateBody'),
130+
Runtime.Const('`'),
131+
])
103132
// ------------------------------------------------------------------
104133
// Literal
105134
// ------------------------------------------------------------------
106-
const LiteralString = Runtime.String([SingleQuote, DoubleQuote, Tilde])
135+
const LiteralString = Runtime.String([SingleQuote, DoubleQuote])
107136
const LiteralNumber = Runtime.Number()
108137
const LiteralBoolean = Runtime.Union([Runtime.Const('true'), Runtime.Const('false')])
109138
const Literal = Runtime.Union([
@@ -177,6 +206,7 @@ const Base = Runtime.Union([
177206
Runtime.Ref('Object'),
178207
Runtime.Ref('Tuple'),
179208
Runtime.Ref('Literal'),
209+
Runtime.Ref('TemplateLiteral'),
180210
Runtime.Ref('Constructor'),
181211
Runtime.Ref('Function'),
182212
Runtime.Ref('Mapped'),
@@ -589,6 +619,10 @@ export const SyntaxModule = new Runtime.Module({
589619
KeywordSymbol,
590620
KeywordVoid,
591621
Keyword,
622+
TemplateInterpolate,
623+
TemplateBody,
624+
TemplateText,
625+
TemplateLiteral,
592626
LiteralString,
593627
LiteralNumber,
594628
LiteralBoolean,

example/typebox/interpreted/runtime.ts

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,13 +133,60 @@ function ReferenceMapping(result: string, context: T.TProperties) {
133133
return target
134134
}
135135
const Reference = Runtime.Ident((result, context) => ReferenceMapping(result, context))
136+
// ------------------------------------------------------------------
137+
// TemplateText
138+
// ------------------------------------------------------------------
139+
function TemplateTextMapping(input: string) {
140+
return T.Literal(input)
141+
}
142+
const TemplateText = Runtime.Union([
143+
Runtime.Until('${'),
144+
Runtime.Until('`'),
145+
], TemplateTextMapping)
146+
// ------------------------------------------------------------------
147+
// TemplateInterpolate
148+
// ------------------------------------------------------------------
149+
function TemplateInterpolateMapping(input: [unknown, unknown, unknown]) {
150+
return input[1]
151+
}
152+
const TemplateInterpolate = Runtime.Tuple([
153+
Runtime.Const('${'),
154+
Runtime.Ref('Type'),
155+
Runtime.Const('}')
156+
], TemplateInterpolateMapping)
157+
// ------------------------------------------------------------------
158+
// TemplateBody
159+
// ------------------------------------------------------------------
160+
function TemplateBodyMapping(input: [unknown] | [unknown, unknown, unknown]) {
161+
return (
162+
input.length === 3
163+
? [input[0], input[1], ...input[2] as unknown[]]
164+
: [input[0]]
165+
)
166+
}
167+
const TemplateBody = Runtime.Union([
168+
Runtime.Tuple([Runtime.Ref('TemplateText'), Runtime.Ref('TemplateInterpolate'), Runtime.Ref('TemplateBody')]),
169+
Runtime.Tuple([Runtime.Ref('TemplateText')]),
170+
], TemplateBodyMapping)
171+
// ------------------------------------------------------------------
172+
// TemplateLiteral
173+
// ------------------------------------------------------------------
174+
function TemplateLiteralMapping(input: [unknown, unknown, unknown]) {
175+
return T.TemplateLiteral(input[1] as T.TTemplateLiteralKind[])
176+
}
177+
const TemplateLiteral = Runtime.Tuple([
178+
Runtime.Const('`'),
179+
Runtime.Ref('TemplateBody'),
180+
Runtime.Const('`'),
181+
], TemplateLiteralMapping)
182+
136183
// ------------------------------------------------------------------
137184
// Literal
138185
// ------------------------------------------------------------------
139186
const Literal = Runtime.Union([
140187
Runtime.Union([Runtime.Const('true'), Runtime.Const('false')], value => T.Literal(value === 'true')),
141188
Runtime.Number(value => T.Literal(parseFloat(value))),
142-
Runtime.String([SingleQuote, DoubleQuote, Tilde], value => T.Literal(value))
189+
Runtime.String([SingleQuote, DoubleQuote], value => T.Literal(value))
143190
])
144191
// ------------------------------------------------------------------
145192
// Keyword
@@ -208,6 +255,7 @@ const Base = Runtime.Union([
208255
Runtime.Ref('Object'),
209256
Runtime.Ref('Tuple'),
210257
Runtime.Ref('Literal'),
258+
Runtime.Ref('TemplateLiteral'),
211259
Runtime.Ref('Constructor'),
212260
Runtime.Ref('Function'),
213261
Runtime.Ref('Mapped'),
@@ -630,12 +678,17 @@ const Date = Runtime.Const('Date', Runtime.As(T.Date()))
630678
// Uint8Array
631679
// ------------------------------------------------------------------
632680
const Uint8Array = Runtime.Const('Uint8Array', Runtime.As(T.Uint8Array()))
681+
633682
// ------------------------------------------------------------------
634683
// Module
635684
// ------------------------------------------------------------------
636685
export const Module = new Runtime.Module({
637686
GenericArgumentsList,
638687
GenericArguments,
688+
TemplateInterpolate,
689+
TemplateBody,
690+
TemplateText,
691+
TemplateLiteral,
639692
Literal,
640693
Keyword,
641694
KeyOf,

example/typebox/interpreted/static.ts

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,56 @@ type Dereference<Context extends T.TProperties, Ref extends string> = (
9191
Ref extends keyof Context ? Context[Ref] : T.TRef<Ref>
9292
)
9393
// ------------------------------------------------------------------
94+
// TemplateText
95+
// ------------------------------------------------------------------
96+
interface TemplateTextMapping extends Static.IMapping {
97+
output: this['input'] extends string ? T.TLiteral<this['input']> : never
98+
}
99+
type TemplateText = Static.Union<[
100+
Static.Until<'${'>,
101+
Static.Until<'`'>,
102+
], TemplateTextMapping>
103+
// ------------------------------------------------------------------
104+
// TemplateInterpolate
105+
// ------------------------------------------------------------------
106+
interface TemplateInterpolateMapping extends Static.IMapping {
107+
output: this['input'] extends ['${', infer Type extends T.TSchema, '}']
108+
? Type
109+
: never
110+
}
111+
type TemplateInterpolate = Static.Tuple<[
112+
Static.Const<'${'>,
113+
Type,
114+
Static.Const<'}'>
115+
], TemplateInterpolateMapping>
116+
// ------------------------------------------------------------------
117+
// TemplateBody
118+
// ------------------------------------------------------------------
119+
interface TemplateBodyMapping extends Static.IMapping {
120+
output: (
121+
this['input'] extends [infer Text extends T.TSchema, infer Type extends T.TSchema, infer Rest extends T.TSchema[]] ? [Text, Type, ...Rest] :
122+
this['input'] extends [infer Text extends T.TSchema] ? [Text] :
123+
[]
124+
)
125+
}
126+
type TemplateBody = Static.Union<[
127+
Static.Tuple<[TemplateText, TemplateInterpolate, TemplateBody]>,
128+
Static.Tuple<[TemplateText]>,
129+
], TemplateBodyMapping>
130+
// ------------------------------------------------------------------
131+
// TemplateLiteral
132+
// ------------------------------------------------------------------
133+
interface TemplateLiteralMapping extends Static.IMapping {
134+
output: this['input'] extends ['`', infer Types extends T.TTemplateLiteralKind[], '`']
135+
? T.TTemplateLiteral<Types>
136+
: never
137+
}
138+
type TemplateLiteral = Static.Tuple<[
139+
Static.Const<'`'>,
140+
TemplateBody,
141+
Static.Const<'`'>,
142+
], TemplateLiteralMapping>
143+
// ------------------------------------------------------------------
94144
// GenericArguments
95145
// ------------------------------------------------------------------
96146
type GenericArgumentsContext<Args extends string[], Context extends T.TProperties, Result extends T.TProperties = {}> = (
@@ -154,7 +204,7 @@ interface LiteralStringMapping extends Static.IMapping {
154204
type Literal = Static.Union<[
155205
Static.Union<[Static.Const<'true'>, Static.Const<'false'>], LiteralBooleanMapping>,
156206
Static.Number<LiteralNumberMapping>,
157-
Static.String<[DoubleQuote, SingleQuote, Tilde], LiteralStringMapping>,
207+
Static.String<[DoubleQuote, SingleQuote], LiteralStringMapping>,
158208
]>
159209
// ------------------------------------------------------------------
160210
// Keyword
@@ -230,6 +280,7 @@ type Base = Static.Union<[
230280
Object,
231281
Tuple,
232282
Literal,
283+
TemplateLiteral,
233284
Function,
234285
Constructor,
235286
Mapped,

0 commit comments

Comments
 (0)