spex-parser 0.6.2 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +428 -226
- package/dist/ast.d.ts +22 -36
- package/dist/ast.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/lexer.d.ts +3 -8
- package/dist/lexer.d.ts.map +1 -1
- package/dist/lexer.js +21 -46
- package/dist/lexer.js.map +1 -1
- package/dist/parser.d.ts +0 -4
- package/dist/parser.d.ts.map +1 -1
- package/dist/parser.js +7 -49
- package/dist/parser.js.map +1 -1
- package/dist/visitor.d.ts +1 -5
- package/dist/visitor.d.ts.map +1 -1
- package/dist/visitor.js +48 -83
- package/dist/visitor.js.map +1 -1
- package/package.json +1 -1
- package/src/ast.ts +38 -44
- package/src/index.ts +3 -7
- package/src/lexer.ts +21 -44
- package/src/parser.ts +7 -58
- package/src/visitor.ts +50 -89
- package/tests/constants.test.ts +0 -4
- package/tests/e2e.test.ts +9 -9
- package/tests/lexer.test.ts +10 -31
- package/tests/parser.test.ts +31 -181
- package/tests/props/express_todo_web.spex +1 -2
- package/tests/props/express_web_env.spex +0 -2
- package/tests/props/flask_todo_web.spex +1 -2
- package/tests/props/flask_web_env.spex +0 -2
- package/tests/props/python_cli_env.spex +0 -2
- package/tests/props/python_todo_cli.spex +1 -2
- package/tests/props/todo.spex +0 -17
- package/tests/props/typescript_cli_env.spex +0 -2
- package/tests/props/typescript_todo_cli.spex +1 -2
- package/tests/visitor.test.ts +99 -265
package/src/parser.ts
CHANGED
|
@@ -7,18 +7,12 @@ import {
|
|
|
7
7
|
SelectTok,
|
|
8
8
|
GenerateTok,
|
|
9
9
|
ImportTok,
|
|
10
|
-
ExportTok,
|
|
11
|
-
PackageTok,
|
|
12
|
-
ExecutableTok,
|
|
13
|
-
ModuleTok,
|
|
14
|
-
EnumTok,
|
|
15
10
|
UnionTok,
|
|
16
11
|
IntersectTok,
|
|
17
12
|
ExceptTok,
|
|
18
13
|
RealizeTok,
|
|
19
14
|
InTok,
|
|
20
15
|
IncludeTok,
|
|
21
|
-
LambdaTok,
|
|
22
16
|
ArrowTok,
|
|
23
17
|
PipeTok,
|
|
24
18
|
SelectBlock,
|
|
@@ -41,6 +35,7 @@ import {
|
|
|
41
35
|
NumberTok,
|
|
42
36
|
BoolTok,
|
|
43
37
|
UnitTok,
|
|
38
|
+
ArtifactTok,
|
|
44
39
|
ConceptTok,
|
|
45
40
|
EnvironmentTok,
|
|
46
41
|
} from './lexer.js'
|
|
@@ -63,10 +58,6 @@ export class SpexParser extends CstParser {
|
|
|
63
58
|
GATE: this.BACKTRACK(this.realizeDeclaration),
|
|
64
59
|
ALT: () => this.SUBRULE(this.realizeDeclaration),
|
|
65
60
|
},
|
|
66
|
-
{
|
|
67
|
-
GATE: this.BACKTRACK(this.packageDeclaration),
|
|
68
|
-
ALT: () => this.SUBRULE(this.packageDeclaration),
|
|
69
|
-
},
|
|
70
61
|
{
|
|
71
62
|
GATE: this.BACKTRACK(this.objectDeclaration),
|
|
72
63
|
ALT: () => this.SUBRULE(this.objectDeclaration),
|
|
@@ -75,10 +66,6 @@ export class SpexParser extends CstParser {
|
|
|
75
66
|
GATE: this.BACKTRACK(this.importDeclaration),
|
|
76
67
|
ALT: () => this.SUBRULE(this.importDeclaration),
|
|
77
68
|
},
|
|
78
|
-
{
|
|
79
|
-
GATE: this.BACKTRACK(this.exportDeclaration),
|
|
80
|
-
ALT: () => this.SUBRULE(this.exportDeclaration),
|
|
81
|
-
},
|
|
82
69
|
{
|
|
83
70
|
GATE: this.BACKTRACK(this.includeDeclaration),
|
|
84
71
|
ALT: () => this.SUBRULE(this.includeDeclaration),
|
|
@@ -117,17 +104,6 @@ export class SpexParser extends CstParser {
|
|
|
117
104
|
})
|
|
118
105
|
})
|
|
119
106
|
|
|
120
|
-
private enumObject = this.RULE('enumObject', () => {
|
|
121
|
-
this.CONSUME(EnumTok)
|
|
122
|
-
this.CONSUME(LParen)
|
|
123
|
-
this.CONSUME(StringLiteral)
|
|
124
|
-
this.MANY(() => {
|
|
125
|
-
this.CONSUME(Comma)
|
|
126
|
-
this.CONSUME2(StringLiteral)
|
|
127
|
-
})
|
|
128
|
-
this.CONSUME(RParen)
|
|
129
|
-
})
|
|
130
|
-
|
|
131
107
|
private literalObject = this.RULE('literalObject', () => {
|
|
132
108
|
this.OR([
|
|
133
109
|
{ ALT: () => this.CONSUME(StringLiteral) },
|
|
@@ -150,16 +126,9 @@ export class SpexParser extends CstParser {
|
|
|
150
126
|
{
|
|
151
127
|
ALT: () => this.SUBRULE(this.literalObject),
|
|
152
128
|
},
|
|
153
|
-
{
|
|
154
|
-
ALT: () => this.SUBRULE(this.enumObject),
|
|
155
|
-
},
|
|
156
129
|
{
|
|
157
130
|
ALT: () => this.SUBRULE(this.patternObject),
|
|
158
131
|
},
|
|
159
|
-
{
|
|
160
|
-
GATE: this.BACKTRACK(this.lambdaObject),
|
|
161
|
-
ALT: () => this.SUBRULE(this.lambdaObject),
|
|
162
|
-
},
|
|
163
132
|
{
|
|
164
133
|
GATE: this.BACKTRACK(this.subObject),
|
|
165
134
|
ALT: () => this.SUBRULE(this.subObject),
|
|
@@ -199,6 +168,7 @@ export class SpexParser extends CstParser {
|
|
|
199
168
|
{ ALT: () => this.CONSUME(NumberTok) },
|
|
200
169
|
{ ALT: () => this.CONSUME(BoolTok) },
|
|
201
170
|
{ ALT: () => this.CONSUME(UnitTok) },
|
|
171
|
+
{ ALT: () => this.CONSUME(ArtifactTok) },
|
|
202
172
|
{ ALT: () => this.CONSUME(ConceptTok) },
|
|
203
173
|
{ ALT: () => this.CONSUME(EnvironmentTok) },
|
|
204
174
|
])
|
|
@@ -223,7 +193,7 @@ export class SpexParser extends CstParser {
|
|
|
223
193
|
this.CONSUME(FromTok)
|
|
224
194
|
this.SUBRULE(this.setObject, { LABEL: 'base' })
|
|
225
195
|
this.CONSUME(SelectTok)
|
|
226
|
-
this.CONSUME(SelectBlock)
|
|
196
|
+
this.OR([{ ALT: () => this.CONSUME(SelectBlock) }, { ALT: () => this.CONSUME(CodeBlock) }])
|
|
227
197
|
})
|
|
228
198
|
|
|
229
199
|
private importDeclaration = this.RULE('importDeclaration', () => {
|
|
@@ -256,26 +226,13 @@ export class SpexParser extends CstParser {
|
|
|
256
226
|
this.CONSUME(Identifier)
|
|
257
227
|
})
|
|
258
228
|
|
|
259
|
-
private exportDeclaration = this.RULE('exportDeclaration', () => {
|
|
260
|
-
this.CONSUME(ExportTok)
|
|
261
|
-
this.CONSUME(Identifier)
|
|
262
|
-
this.CONSUME(Semicolon)
|
|
263
|
-
})
|
|
264
|
-
|
|
265
229
|
private generateDeclaration = this.RULE('generateDeclaration', () => {
|
|
266
230
|
this.CONSUME(GenerateTok)
|
|
267
231
|
this.CONSUME(Identifier)
|
|
268
|
-
this.
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
this.CONSUME(PackageTok)
|
|
273
|
-
this.OR([{ ALT: () => this.CONSUME(ExecutableTok) }, { ALT: () => this.CONSUME(ModuleTok) }])
|
|
274
|
-
this.CONSUME(Identifier)
|
|
275
|
-
this.CONSUME(AsTok)
|
|
276
|
-
this.SUBRULE(this.setObject)
|
|
277
|
-
this.CONSUME(InTok)
|
|
278
|
-
this.SUBRULE2(this.setObject, { LABEL: 'environment' })
|
|
232
|
+
this.OPTION(() => {
|
|
233
|
+
this.CONSUME(InTok)
|
|
234
|
+
this.SUBRULE(this.setObject, { LABEL: 'environment' })
|
|
235
|
+
})
|
|
279
236
|
this.CONSUME(Semicolon)
|
|
280
237
|
})
|
|
281
238
|
|
|
@@ -298,12 +255,4 @@ export class SpexParser extends CstParser {
|
|
|
298
255
|
this.CONSUME(Identifier)
|
|
299
256
|
this.CONSUME(Semicolon)
|
|
300
257
|
})
|
|
301
|
-
|
|
302
|
-
private lambdaObject = this.RULE('lambdaObject', () => {
|
|
303
|
-
this.CONSUME(LambdaTok)
|
|
304
|
-
this.SUBRULE(this.objectOperand, { LABEL: 'base' })
|
|
305
|
-
this.CONSUME(ArrowTok)
|
|
306
|
-
this.SUBRULE(this.setObject, { LABEL: 'exponent' })
|
|
307
|
-
this.CONSUME(CodeBlock)
|
|
308
|
-
})
|
|
309
258
|
}
|
package/src/visitor.ts
CHANGED
|
@@ -4,21 +4,17 @@ import type {
|
|
|
4
4
|
Declaration,
|
|
5
5
|
ObjectDeclaration,
|
|
6
6
|
ImportDeclaration,
|
|
7
|
-
ExportDeclaration,
|
|
8
7
|
GenerateDeclaration,
|
|
9
|
-
PackageDeclaration,
|
|
10
8
|
RealizeDeclaration,
|
|
11
9
|
IncludeDeclaration,
|
|
12
|
-
EnumObject,
|
|
13
10
|
LiteralObject,
|
|
14
11
|
SetObject,
|
|
15
12
|
CoproductObject,
|
|
16
13
|
PatternLiteralObject,
|
|
17
|
-
ExponentialPattern,
|
|
18
|
-
PatternBlock,
|
|
19
14
|
ObjectExpression,
|
|
20
15
|
NamedObject,
|
|
21
16
|
SubObject,
|
|
17
|
+
SubObjectConstraint,
|
|
22
18
|
ArrayObject,
|
|
23
19
|
Constraint,
|
|
24
20
|
ConstraintPart,
|
|
@@ -49,7 +45,7 @@ export function parseConstraint(raw: string): Constraint {
|
|
|
49
45
|
if (match.index > lastIndex) {
|
|
50
46
|
parts.push({ kind: 'ConstraintText', text: raw.slice(lastIndex, match.index) })
|
|
51
47
|
}
|
|
52
|
-
parts.push({ kind: '
|
|
48
|
+
parts.push({ kind: 'ReferenceDirective', name: match[1]! })
|
|
53
49
|
lastIndex = match.index + match[0].length
|
|
54
50
|
}
|
|
55
51
|
|
|
@@ -60,6 +56,35 @@ export function parseConstraint(raw: string): Constraint {
|
|
|
60
56
|
return { raw, parts }
|
|
61
57
|
}
|
|
62
58
|
|
|
59
|
+
function extractCodeLanguage(image: string): string {
|
|
60
|
+
const langEnd = image.indexOf('\n')
|
|
61
|
+
if (langEnd === -1) return ''
|
|
62
|
+
return image.slice(3, langEnd).trim()
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function extractCodeBody(image: string): string {
|
|
66
|
+
const firstNewline = image.indexOf('\n')
|
|
67
|
+
return image.slice(firstNewline + 1, -3).trimEnd()
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function codeConstraint(image: string): SubObjectConstraint {
|
|
71
|
+
const language = extractCodeLanguage(image)
|
|
72
|
+
const body = extractCodeBody(image)
|
|
73
|
+
if (language === '') {
|
|
74
|
+
return {
|
|
75
|
+
type: 'Structured',
|
|
76
|
+
raw: body,
|
|
77
|
+
parts: parseConstraint(body).parts,
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return {
|
|
81
|
+
type: 'Code',
|
|
82
|
+
language,
|
|
83
|
+
body,
|
|
84
|
+
parts: parseConstraint(body).parts,
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
63
88
|
export class SpexParserVisitor extends BaseSpexVisitor implements ICstVisitor<any, any> {
|
|
64
89
|
constructor() {
|
|
65
90
|
super()
|
|
@@ -75,31 +100,18 @@ export class SpexParserVisitor extends BaseSpexVisitor implements ICstVisitor<an
|
|
|
75
100
|
if (ctx.realizeDeclaration) {
|
|
76
101
|
return this.visit(ctx.realizeDeclaration)
|
|
77
102
|
}
|
|
78
|
-
if (ctx.packageDeclaration) {
|
|
79
|
-
return this.visit(ctx.packageDeclaration)
|
|
80
|
-
}
|
|
81
103
|
if (ctx.objectDeclaration) {
|
|
82
104
|
return this.visit(ctx.objectDeclaration)
|
|
83
105
|
}
|
|
84
106
|
if (ctx.importDeclaration) {
|
|
85
107
|
return this.visit(ctx.importDeclaration)
|
|
86
108
|
}
|
|
87
|
-
if (ctx.exportDeclaration) {
|
|
88
|
-
return this.visit(ctx.exportDeclaration)
|
|
89
|
-
}
|
|
90
109
|
if (ctx.includeDeclaration) {
|
|
91
110
|
return this.visit(ctx.includeDeclaration)
|
|
92
111
|
}
|
|
93
112
|
return this.visit(ctx.generateDeclaration)
|
|
94
113
|
}
|
|
95
114
|
|
|
96
|
-
enumObject(ctx: any): EnumObject {
|
|
97
|
-
return {
|
|
98
|
-
kind: 'EnumObject',
|
|
99
|
-
values: ctx.StringLiteral.map((s: any) => stringLiteralValue(s.image)),
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
115
|
literalObject(ctx: any): LiteralObject {
|
|
104
116
|
if (ctx.StringLiteral) {
|
|
105
117
|
return {
|
|
@@ -169,12 +181,8 @@ export class SpexParserVisitor extends BaseSpexVisitor implements ICstVisitor<an
|
|
|
169
181
|
expr = this.visit(ctx.parenthesizedObject)
|
|
170
182
|
} else if (ctx.productObject) {
|
|
171
183
|
expr = this.visit(ctx.productObject)
|
|
172
|
-
} else if (ctx.enumObject) {
|
|
173
|
-
expr = this.visit(ctx.enumObject)
|
|
174
184
|
} else if (ctx.patternObject) {
|
|
175
185
|
expr = this.visit(ctx.patternObject)
|
|
176
|
-
} else if (ctx.lambdaObject) {
|
|
177
|
-
expr = this.visit(ctx.lambdaObject)
|
|
178
186
|
} else if (ctx.literalObject) {
|
|
179
187
|
expr = this.visit(ctx.literalObject)
|
|
180
188
|
} else {
|
|
@@ -212,6 +220,8 @@ export class SpexParserVisitor extends BaseSpexVisitor implements ICstVisitor<an
|
|
|
212
220
|
parts = [ctx.BoolTok[0].image, ...(ctx.Identifier ?? []).map((id: any) => id.image)]
|
|
213
221
|
} else if (ctx.UnitTok) {
|
|
214
222
|
parts = [ctx.UnitTok[0].image, ...(ctx.Identifier ?? []).map((id: any) => id.image)]
|
|
223
|
+
} else if (ctx.ArtifactTok) {
|
|
224
|
+
parts = [ctx.ArtifactTok[0].image, ...(ctx.Identifier ?? []).map((id: any) => id.image)]
|
|
215
225
|
} else if (ctx.ConceptTok) {
|
|
216
226
|
parts = [ctx.ConceptTok[0].image, ...(ctx.Identifier ?? []).map((id: any) => id.image)]
|
|
217
227
|
} else if (ctx.EnvironmentTok) {
|
|
@@ -243,12 +253,24 @@ export class SpexParserVisitor extends BaseSpexVisitor implements ICstVisitor<an
|
|
|
243
253
|
}
|
|
244
254
|
|
|
245
255
|
subObject(ctx: any): SubObject {
|
|
256
|
+
const base = this.visit(ctx.base)
|
|
257
|
+
if (ctx.CodeBlock) {
|
|
258
|
+
return {
|
|
259
|
+
kind: 'SubObject',
|
|
260
|
+
base,
|
|
261
|
+
constraint: codeConstraint(ctx.CodeBlock[0].image),
|
|
262
|
+
}
|
|
263
|
+
}
|
|
246
264
|
const rawText: string = ctx.SelectBlock[0].image
|
|
247
265
|
const rawConstraint = unescapeConstraint(rawText.slice(1, -1).trim())
|
|
248
266
|
return {
|
|
249
267
|
kind: 'SubObject',
|
|
250
|
-
base
|
|
251
|
-
constraint:
|
|
268
|
+
base,
|
|
269
|
+
constraint: {
|
|
270
|
+
type: 'NaturalLanguage',
|
|
271
|
+
raw: rawConstraint,
|
|
272
|
+
parts: parseConstraint(rawConstraint).parts,
|
|
273
|
+
},
|
|
252
274
|
}
|
|
253
275
|
}
|
|
254
276
|
|
|
@@ -282,28 +304,13 @@ export class SpexParserVisitor extends BaseSpexVisitor implements ICstVisitor<an
|
|
|
282
304
|
}
|
|
283
305
|
}
|
|
284
306
|
|
|
285
|
-
exportDeclaration(ctx: any): ExportDeclaration {
|
|
286
|
-
return {
|
|
287
|
-
kind: 'ExportDeclaration',
|
|
288
|
-
name: ctx.Identifier[0].image,
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
packageDeclaration(ctx: any): PackageDeclaration {
|
|
293
|
-
const packageType = ctx.ExecutableTok ? ('EXECUTABLE' as const) : ('MODULE' as const)
|
|
294
|
-
return {
|
|
295
|
-
kind: 'PackageDeclaration',
|
|
296
|
-
packageType,
|
|
297
|
-
name: ctx.Identifier[0].image,
|
|
298
|
-
objectName: this.visit(ctx.setObject),
|
|
299
|
-
environment: this.visit(ctx.environment),
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
|
|
303
307
|
generateDeclaration(ctx: any): GenerateDeclaration {
|
|
304
308
|
return {
|
|
305
309
|
kind: 'GenerateDeclaration',
|
|
306
310
|
name: ctx.Identifier[0].image,
|
|
311
|
+
environment: ctx.environment
|
|
312
|
+
? this.visit(ctx.environment)
|
|
313
|
+
: { kind: 'NamedObject', name: 'environment' },
|
|
307
314
|
}
|
|
308
315
|
}
|
|
309
316
|
|
|
@@ -327,52 +334,6 @@ export class SpexParserVisitor extends BaseSpexVisitor implements ICstVisitor<an
|
|
|
327
334
|
address,
|
|
328
335
|
}
|
|
329
336
|
}
|
|
330
|
-
|
|
331
|
-
lambdaObject(ctx: any): ExponentialPattern {
|
|
332
|
-
const image: string = ctx.CodeBlock[0].image
|
|
333
|
-
const firstNewline = image.indexOf('\n')
|
|
334
|
-
const langEnd = image.indexOf('\n')
|
|
335
|
-
const language = image.slice(3, langEnd)
|
|
336
|
-
const body = image.slice(firstNewline + 1, -3).trimEnd()
|
|
337
|
-
|
|
338
|
-
const patterns: PatternBlock[] = []
|
|
339
|
-
let i = 0
|
|
340
|
-
while (i < body.length) {
|
|
341
|
-
if (body[i] === '@' && body[i + 1] === '{') {
|
|
342
|
-
const start = i
|
|
343
|
-
let depth = 1
|
|
344
|
-
i += 2
|
|
345
|
-
while (i < body.length && depth > 0) {
|
|
346
|
-
if (body[i] === '\\') {
|
|
347
|
-
i += 2
|
|
348
|
-
continue
|
|
349
|
-
}
|
|
350
|
-
if (body[i] === '{') depth++
|
|
351
|
-
if (body[i] === '}') depth--
|
|
352
|
-
i++
|
|
353
|
-
}
|
|
354
|
-
const end = i
|
|
355
|
-
const raw = body.slice(start + 2, end - 1).trim()
|
|
356
|
-
patterns.push({
|
|
357
|
-
raw,
|
|
358
|
-
parts: parseConstraint(raw).parts,
|
|
359
|
-
start,
|
|
360
|
-
end,
|
|
361
|
-
})
|
|
362
|
-
} else {
|
|
363
|
-
i++
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
return {
|
|
368
|
-
kind: 'ExponentialPattern',
|
|
369
|
-
base: this.visit(ctx.exponent),
|
|
370
|
-
exponent: this.visit(ctx.base),
|
|
371
|
-
language,
|
|
372
|
-
body,
|
|
373
|
-
patterns,
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
337
|
}
|
|
377
338
|
|
|
378
339
|
export function parseToAst(text: string): SpexFile {
|
package/tests/constants.test.ts
CHANGED
|
@@ -74,10 +74,6 @@ describe('constantOf', () => {
|
|
|
74
74
|
expect(constantOf(firstObject('create K as from string select { are positive };'))).toBeNull()
|
|
75
75
|
})
|
|
76
76
|
|
|
77
|
-
it('should reject enums', () => {
|
|
78
|
-
expect(constantOf(firstObject("create K as enum ('a', 'b');"))).toBeNull()
|
|
79
|
-
})
|
|
80
|
-
|
|
81
77
|
it('should reject arrays', () => {
|
|
82
78
|
expect(constantOf(firstObject('create K as string[];'))).toBeNull()
|
|
83
79
|
})
|
package/tests/e2e.test.ts
CHANGED
|
@@ -8,15 +8,15 @@ const __filename = fileURLToPath(import.meta.url)
|
|
|
8
8
|
const __dirname = dirname(__filename)
|
|
9
9
|
|
|
10
10
|
const fixtures: [string, number][] = [
|
|
11
|
-
['todo.spex',
|
|
12
|
-
['python_cli_env.spex',
|
|
13
|
-
['typescript_cli_env.spex',
|
|
14
|
-
['flask_web_env.spex',
|
|
15
|
-
['express_web_env.spex',
|
|
16
|
-
['python_todo_cli.spex',
|
|
17
|
-
['typescript_todo_cli.spex',
|
|
18
|
-
['flask_todo_web.spex',
|
|
19
|
-
['express_todo_web.spex',
|
|
11
|
+
['todo.spex', 17],
|
|
12
|
+
['python_cli_env.spex', 3],
|
|
13
|
+
['typescript_cli_env.spex', 3],
|
|
14
|
+
['flask_web_env.spex', 3],
|
|
15
|
+
['express_web_env.spex', 3],
|
|
16
|
+
['python_todo_cli.spex', 15],
|
|
17
|
+
['typescript_todo_cli.spex', 15],
|
|
18
|
+
['flask_todo_web.spex', 21],
|
|
19
|
+
['express_todo_web.spex', 21],
|
|
20
20
|
]
|
|
21
21
|
|
|
22
22
|
describe('end-to-end', () => {
|
package/tests/lexer.test.ts
CHANGED
|
@@ -5,7 +5,7 @@ describe('SpexLexer', () => {
|
|
|
5
5
|
describe('tokenization', () => {
|
|
6
6
|
it('should tokenize keywords', () => {
|
|
7
7
|
const result = SpexLexer.tokenize(
|
|
8
|
-
'create as from select generate import
|
|
8
|
+
'create as from select generate import realize in'
|
|
9
9
|
)
|
|
10
10
|
expect(result.errors).toHaveLength(0)
|
|
11
11
|
expect(result.tokens.map((t) => t.tokenType.name)).toEqual([
|
|
@@ -15,11 +15,6 @@ describe('SpexLexer', () => {
|
|
|
15
15
|
'SelectTok',
|
|
16
16
|
'GenerateTok',
|
|
17
17
|
'ImportTok',
|
|
18
|
-
'ExportTok',
|
|
19
|
-
'PackageTok',
|
|
20
|
-
'ExecutableTok',
|
|
21
|
-
'ModuleTok',
|
|
22
|
-
'EnumTok',
|
|
23
18
|
'RealizeTok',
|
|
24
19
|
'InTok',
|
|
25
20
|
])
|
|
@@ -27,7 +22,7 @@ describe('SpexLexer', () => {
|
|
|
27
22
|
|
|
28
23
|
it('should tokenize keywords case-insensitively', () => {
|
|
29
24
|
const result = SpexLexer.tokenize(
|
|
30
|
-
'CREATE AS FROM SELECT GENERATE IMPORT
|
|
25
|
+
'CREATE AS FROM SELECT GENERATE IMPORT UNION INTERSECT EXCEPT REALIZE IN'
|
|
31
26
|
)
|
|
32
27
|
expect(result.errors).toHaveLength(0)
|
|
33
28
|
expect(result.tokens.map((t) => t.tokenType.name)).toEqual([
|
|
@@ -37,11 +32,6 @@ describe('SpexLexer', () => {
|
|
|
37
32
|
'SelectTok',
|
|
38
33
|
'GenerateTok',
|
|
39
34
|
'ImportTok',
|
|
40
|
-
'ExportTok',
|
|
41
|
-
'PackageTok',
|
|
42
|
-
'ExecutableTok',
|
|
43
|
-
'ModuleTok',
|
|
44
|
-
'EnumTok',
|
|
45
35
|
'UnionTok',
|
|
46
36
|
'IntersectTok',
|
|
47
37
|
'ExceptTok',
|
|
@@ -50,23 +40,6 @@ describe('SpexLexer', () => {
|
|
|
50
40
|
])
|
|
51
41
|
})
|
|
52
42
|
|
|
53
|
-
it('should tokenize enum object declarations', () => {
|
|
54
|
-
const result = SpexLexer.tokenize("create myEnum as enum ('v1', 'v2');")
|
|
55
|
-
expect(result.errors).toHaveLength(0)
|
|
56
|
-
expect(result.tokens.map((t) => t.tokenType.name)).toEqual([
|
|
57
|
-
'CreateTok',
|
|
58
|
-
'Identifier',
|
|
59
|
-
'AsTok',
|
|
60
|
-
'EnumTok',
|
|
61
|
-
'LParen',
|
|
62
|
-
'StringLiteral',
|
|
63
|
-
'Comma',
|
|
64
|
-
'StringLiteral',
|
|
65
|
-
'RParen',
|
|
66
|
-
'Semicolon',
|
|
67
|
-
])
|
|
68
|
-
})
|
|
69
|
-
|
|
70
43
|
it('should tokenize symbols', () => {
|
|
71
44
|
const result = SpexLexer.tokenize('->[]():;,.|')
|
|
72
45
|
expect(result.errors).toHaveLength(0)
|
|
@@ -120,10 +93,10 @@ describe('SpexLexer', () => {
|
|
|
120
93
|
|
|
121
94
|
it('should handle keywords with word boundary', () => {
|
|
122
95
|
const result = SpexLexer.tokenize(
|
|
123
|
-
'createfoo foocreate asfoo fooas fooselect selectfoo foofrom fromfoo generatefoo foogenerate importfoo fooimport
|
|
96
|
+
'createfoo foocreate asfoo fooas fooselect selectfoo foofrom fromfoo generatefoo foogenerate importfoo fooimport artifactfoo fooartifact conceptfoo fooconcept environmentfoo fooenvironment realizefoo foorealize info fooin'
|
|
124
97
|
)
|
|
125
98
|
expect(result.errors).toHaveLength(0)
|
|
126
|
-
expect(result.tokens.map((t) => t.tokenType.name)).toEqual(Array(
|
|
99
|
+
expect(result.tokens.map((t) => t.tokenType.name)).toEqual(Array(22).fill('Identifier'))
|
|
127
100
|
})
|
|
128
101
|
|
|
129
102
|
it('should tokenize the concept and environment base types', () => {
|
|
@@ -135,6 +108,12 @@ describe('SpexLexer', () => {
|
|
|
135
108
|
])
|
|
136
109
|
})
|
|
137
110
|
|
|
111
|
+
it('should tokenize the artifact base type', () => {
|
|
112
|
+
const result = SpexLexer.tokenize('artifact')
|
|
113
|
+
expect(result.errors).toHaveLength(0)
|
|
114
|
+
expect(result.tokens.map((t) => t.tokenType.name)).toEqual(['ArtifactTok'])
|
|
115
|
+
})
|
|
116
|
+
|
|
138
117
|
it('should tokenize the text between braces', () => {
|
|
139
118
|
const result = SpexLexer.tokenize('{hello\nworld}')
|
|
140
119
|
expect(result.errors).toHaveLength(0)
|