Skip to content

Commit 1493395

Browse files
committed
until
1 parent 8ccf1a2 commit 1493395

File tree

4 files changed

+113
-230
lines changed

4 files changed

+113
-230
lines changed

example/index.ts

Lines changed: 1 addition & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -1,145 +1,6 @@
11
// deno-fmt-ignore-file
22

33
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'
74

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-
}`)
5+
//
226

23-
console.dir(Type, { depth: 100 })
24-
25-
// ------------------------------------------------------------------
26-
//
27-
// Example: Ebnf | Interpreted
28-
//
29-
// ------------------------------------------------------------------
30-
const Ebnf = ParseEbnf(`
31-
32-
Operand ::= Ident ;
33-
34-
Factor ::= "(" Expr ")"
35-
| Operand ;
36-
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)
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-
}

src/runtime/guard.ts

Lines changed: 9 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -28,75 +28,18 @@ THE SOFTWARE.
2828

2929
// deno-fmt-ignore-file
3030

31-
import { IArray, IConst, IContext, IIdent, INumber, IOptional, IRef, IString, ITuple, IUnion } from './types.ts'
32-
33-
// ------------------------------------------------------------------
34-
// Value Guard
35-
// ------------------------------------------------------------------
36-
function HasPropertyKey<Key extends PropertyKey>(value: Record<PropertyKey, unknown>, key: Key): value is Record<PropertyKey, unknown> & { [_ in Key]: unknown } {
31+
export function IsEqual(left: unknown, right: unknown): boolean {
32+
return left === right
33+
}
34+
export function HasPropertyKey<Key extends PropertyKey>(value: Record<PropertyKey, unknown>, key: Key): value is Record<PropertyKey, unknown> & { [_ in Key]: unknown } {
3735
return key in value
3836
}
39-
function IsObjectValue(value: unknown): value is Record<PropertyKey, unknown> {
37+
export function IsObject(value: unknown): value is Record<PropertyKey, unknown> {
4038
return typeof value === 'object' && value !== null
4139
}
42-
function IsArrayValue(value: unknown): value is unknown[] {
40+
export function IsArray(value: unknown): value is unknown[] {
4341
return globalThis.Array.isArray(value)
4442
}
45-
// ------------------------------------------------------------------
46-
// Parser Guard
47-
// ------------------------------------------------------------------
48-
/** Returns true if the value is a Array Parser */
49-
export function IsArray(value: unknown): value is IArray {
50-
return IsObjectValue(value) && HasPropertyKey(value, 'type') && value.type === 'Array' && HasPropertyKey(value, 'parser') && IsObjectValue(value.parser)
51-
}
52-
/** Returns true if the value is a Const Parser */
53-
export function IsConst(value: unknown): value is IConst {
54-
return IsObjectValue(value) && HasPropertyKey(value, 'type') && value.type === 'Const' && HasPropertyKey(value, 'value') && typeof value.value === 'string'
55-
}
56-
/** Returns true if the value is a Context Parser */
57-
export function IsContext(value: unknown): value is IContext {
58-
return IsObjectValue(value) && HasPropertyKey(value, 'type') && value.type === 'Context' && HasPropertyKey(value, 'left') && IsParser(value.left) && HasPropertyKey(value, 'right') && IsParser(value.right)
59-
}
60-
/** Returns true if the value is a Ident Parser */
61-
export function IsIdent(value: unknown): value is IIdent {
62-
return IsObjectValue(value) && HasPropertyKey(value, 'type') && value.type === 'Ident'
63-
}
64-
/** Returns true if the value is a Number Parser */
65-
export function IsNumber(value: unknown): value is INumber {
66-
return IsObjectValue(value) && HasPropertyKey(value, 'type') && value.type === 'Number'
67-
}
68-
/** Returns true if the value is a Optional Parser */
69-
export function IsOptional(value: unknown): value is IOptional {
70-
return IsObjectValue(value) && HasPropertyKey(value, 'type') && value.type === 'Optional' && HasPropertyKey(value, 'parser') && IsObjectValue(value.parser)
71-
}
72-
/** Returns true if the value is a Ref Parser */
73-
export function IsRef(value: unknown): value is IRef {
74-
return IsObjectValue(value) && HasPropertyKey(value, 'type') && value.type === 'Ref' && HasPropertyKey(value, 'ref') && typeof value.ref === 'string'
75-
}
76-
/** Returns true if the value is a String Parser */
77-
export function IsString(value: unknown): value is IString {
78-
return IsObjectValue(value) && HasPropertyKey(value, 'type') && value.type === 'String' && HasPropertyKey(value, 'options') && IsArrayValue(value.options)
79-
}
80-
/** Returns true if the value is a Tuple Parser */
81-
export function IsTuple(value: unknown): value is ITuple {
82-
return IsObjectValue(value) && HasPropertyKey(value, 'type') && value.type === 'Tuple' && HasPropertyKey(value, 'parsers') && IsArrayValue(value.parsers)
83-
}
84-
/** Returns true if the value is a Union Parser */
85-
export function IsUnion(value: unknown): value is IUnion {
86-
return IsObjectValue(value) && HasPropertyKey(value, 'type') && value.type === 'Union' && HasPropertyKey(value, 'parsers') && IsArrayValue(value.parsers)
87-
}
88-
/** Returns true if the value is a Parser */
89-
export function IsParser(value: unknown) {
90-
return (
91-
IsArray(value)
92-
|| IsConst(value)
93-
|| IsContext(value)
94-
|| IsIdent(value)
95-
|| IsNumber(value)
96-
|| IsOptional(value)
97-
|| IsRef(value)
98-
|| IsString(value)
99-
|| IsTuple(value)
100-
|| IsUnion(value)
101-
)
102-
}
43+
export function IsString(value: unknown): value is string {
44+
return typeof value === 'string'
45+
}

src/runtime/parse.ts

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ import * as Guard from './guard.ts'
3333
import * as Token from './token.ts'
3434
import * as Types from './types.ts'
3535

36+
export function Throw(message: string): never {
37+
throw new Error(message)
38+
}
39+
3640
// ------------------------------------------------------------------
3741
// Context
3842
// ------------------------------------------------------------------
@@ -85,8 +89,7 @@ function ParseOptional<ModuleProperties extends Types.IModuleProperties, Parser
8589
// Ref
8690
// ------------------------------------------------------------------
8791
function ParseRef<ModuleProperties extends Types.IModuleProperties, Ref extends string>(moduleProperties: ModuleProperties, ref: Ref, code: string, context: unknown): [] | [string, string] {
88-
const parser = moduleProperties[ref]
89-
if (!Guard.IsParser(parser)) throw Error(`Cannot dereference Parser '${ref}'`)
92+
const parser = ref in moduleProperties ? moduleProperties[ref] : Throw(`Cannot dereference Parser '${ref}'`)
9093
return ParseParser(moduleProperties, parser, code, context) as never
9194
}
9295
// ------------------------------------------------------------------
@@ -125,16 +128,16 @@ function ParseUnion<ModuleProperties extends Types.IModuleProperties, Parsers ex
125128
// ------------------------------------------------------------------
126129
function ParseParser<Parser extends Types.IParser>(moduleProperties: Types.IModuleProperties, parser: Parser, code: string, context: unknown): [] | [Types.StaticParser<Parser>, string] {
127130
const result = (
128-
Guard.IsContext(parser) ? ParseContext(moduleProperties, parser.left, parser.right, code, context) :
129-
Guard.IsArray(parser) ? ParseArray(moduleProperties, parser.parser, code, context) :
130-
Guard.IsConst(parser) ? ParseConst(parser.value, code, context) :
131-
Guard.IsIdent(parser) ? ParseIdent(code, context) :
132-
Guard.IsNumber(parser) ? ParseNumber(code, context) :
133-
Guard.IsOptional(parser) ? ParseOptional(moduleProperties, parser.parser, code, context) :
134-
Guard.IsRef(parser) ? ParseRef(moduleProperties, parser.ref, code, context) :
135-
Guard.IsString(parser) ? ParseString(parser.options, code, context) :
136-
Guard.IsTuple(parser) ? ParseTuple(moduleProperties, parser.parsers, code, context) :
137-
Guard.IsUnion(parser) ? ParseUnion(moduleProperties, parser.parsers, code, context) :
131+
Types.IsContext(parser) ? ParseContext(moduleProperties, parser.left, parser.right, code, context) :
132+
Types.IsArray(parser) ? ParseArray(moduleProperties, parser.parser, code, context) :
133+
Types.IsConst(parser) ? ParseConst(parser.value, code, context) :
134+
Types.IsIdent(parser) ? ParseIdent(code, context) :
135+
Types.IsNumber(parser) ? ParseNumber(code, context) :
136+
Types.IsOptional(parser) ? ParseOptional(moduleProperties, parser.parser, code, context) :
137+
Types.IsRef(parser) ? ParseRef(moduleProperties, parser.ref, code, context) :
138+
Types.IsString(parser) ? ParseString(parser.options, code, context) :
139+
Types.IsTuple(parser) ? ParseTuple(moduleProperties, parser.parsers, code, context) :
140+
Types.IsUnion(parser) ? ParseUnion(moduleProperties, parser.parsers, code, context) :
138141
[]
139142
)
140143
return (result.length === 2 ? [parser.mapping(result[0], context), result[1]] : result) as never

0 commit comments

Comments
 (0)