zen-expression 0.55.0

Zen Expression Language
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
use zen_expression::lexer::{
    ArithmeticOperator, Bracket, ComparisonOperator, Identifier, Lexer, LogicalOperator, Operator,
    QuotationMark, Token, TokenKind,
};

struct LexerTest {
    test: &'static str,
    result: Vec<Token<'static>>,
}

#[test]
fn lexer_test() {
    let tests: Vec<LexerTest> = Vec::from([
        LexerTest {
            test: "'hello'",
            result: Vec::from([
                Token {
                    kind: TokenKind::QuotationMark(QuotationMark::SingleQuote),
                    span: (0, 1),
                    value: "'",
                },
                Token {
                    kind: TokenKind::Literal,
                    span: (1, 6),
                    value: "hello",
                },
                Token {
                    kind: TokenKind::QuotationMark(QuotationMark::SingleQuote),
                    span: (6, 7),
                    value: "'",
                },
            ]),
        },
        LexerTest {
            test: "null",
            result: Vec::from([Token {
                kind: TokenKind::Identifier(Identifier::Null),
                span: (0, 4),
                value: "null",
            }]),
        },
        LexerTest {
            test: "null ?? 'hello'",
            result: Vec::from([
                Token {
                    kind: TokenKind::Identifier(Identifier::Null),
                    span: (0, 4),
                    value: "null",
                },
                Token {
                    kind: TokenKind::Operator(Operator::Logical(
                        LogicalOperator::NullishCoalescing,
                    )),
                    span: (5, 7),
                    value: "??",
                },
                Token {
                    kind: TokenKind::QuotationMark(QuotationMark::SingleQuote),
                    span: (8, 9),
                    value: "'",
                },
                Token {
                    kind: TokenKind::Literal,
                    span: (9, 14),
                    value: "hello",
                },
                Token {
                    kind: TokenKind::QuotationMark(QuotationMark::SingleQuote),
                    span: (14, 15),
                    value: "'",
                },
            ]),
        },
        LexerTest {
            test: "'double' 'single' 'abc'",
            result: Vec::from([
                Token {
                    kind: TokenKind::QuotationMark(QuotationMark::SingleQuote),
                    span: (0, 1),
                    value: "'",
                },
                Token {
                    kind: TokenKind::Literal,
                    span: (1, 7),
                    value: "double",
                },
                Token {
                    kind: TokenKind::QuotationMark(QuotationMark::SingleQuote),
                    span: (7, 8),
                    value: "'",
                },
                Token {
                    kind: TokenKind::QuotationMark(QuotationMark::SingleQuote),
                    span: (9, 10),
                    value: "'",
                },
                Token {
                    kind: TokenKind::Literal,
                    span: (10, 16),
                    value: "single",
                },
                Token {
                    kind: TokenKind::QuotationMark(QuotationMark::SingleQuote),
                    span: (16, 17),
                    value: "'",
                },
                Token {
                    kind: TokenKind::QuotationMark(QuotationMark::SingleQuote),
                    span: (18, 19),
                    value: "'",
                },
                Token {
                    kind: TokenKind::Literal,
                    span: (19, 22),
                    value: "abc",
                },
                Token {
                    kind: TokenKind::QuotationMark(QuotationMark::SingleQuote),
                    span: (22, 23),
                    value: "'",
                },
            ]),
        },
        LexerTest {
            test: "0.5 0.025 1 02 1_000_000 _42 -0.5",
            result: Vec::from([
                Token {
                    kind: TokenKind::Number,
                    span: (0, 3),
                    value: "0.5",
                },
                Token {
                    kind: TokenKind::Number,
                    span: (4, 9),
                    value: "0.025",
                },
                Token {
                    kind: TokenKind::Number,
                    span: (10, 11),
                    value: "1",
                },
                Token {
                    kind: TokenKind::Number,
                    span: (12, 14),
                    value: "02",
                },
                Token {
                    kind: TokenKind::Number,
                    span: (15, 24),
                    value: "1_000_000",
                },
                Token {
                    kind: TokenKind::Literal,
                    span: (25, 28),
                    value: "_42",
                },
                Token {
                    kind: TokenKind::Operator(Operator::Arithmetic(ArithmeticOperator::Subtract)),
                    span: (29, 30),
                    value: "-",
                },
                Token {
                    kind: TokenKind::Number,
                    span: (30, 33),
                    value: "0.5",
                },
            ]),
        },
        LexerTest {
            test: "a and orb().val",
            result: Vec::from([
                Token {
                    kind: TokenKind::Literal,
                    span: (0, 1),
                    value: "a",
                },
                Token {
                    kind: TokenKind::Operator(Operator::Logical(LogicalOperator::And)),
                    span: (2, 5),
                    value: "and",
                },
                Token {
                    kind: TokenKind::Literal,
                    span: (6, 9),
                    value: "orb",
                },
                Token {
                    kind: TokenKind::Bracket(Bracket::LeftParenthesis),
                    span: (9, 10),
                    value: "(",
                },
                Token {
                    kind: TokenKind::Bracket(Bracket::RightParenthesis),
                    span: (10, 11),
                    value: ")",
                },
                Token {
                    kind: TokenKind::Operator(Operator::Dot),
                    span: (11, 12),
                    value: ".",
                },
                Token {
                    kind: TokenKind::Literal,
                    span: (12, 15),
                    value: "val",
                },
            ]),
        },
        LexerTest {
            test: "foo.bar",
            result: Vec::from([
                Token {
                    kind: TokenKind::Literal,
                    span: (0, 3),
                    value: "foo",
                },
                Token {
                    kind: TokenKind::Operator(Operator::Dot),
                    span: (3, 4),
                    value: ".",
                },
                Token {
                    kind: TokenKind::Literal,
                    span: (4, 7),
                    value: "bar",
                },
            ]),
        },
        LexerTest {
            test: "foo .bar == .baz",
            result: Vec::from([
                Token {
                    kind: TokenKind::Literal,
                    span: (0, 3),
                    value: "foo",
                },
                Token {
                    kind: TokenKind::Operator(Operator::Dot),
                    span: (4, 5),
                    value: ".",
                },
                Token {
                    kind: TokenKind::Literal,
                    span: (5, 8),
                    value: "bar",
                },
                Token {
                    kind: TokenKind::Operator(Operator::Comparison(ComparisonOperator::Equal)),
                    span: (9, 11),
                    value: "==",
                },
                Token {
                    kind: TokenKind::Operator(Operator::Dot),
                    span: (12, 13),
                    value: ".",
                },
                Token {
                    kind: TokenKind::Literal,
                    span: (13, 16),
                    value: "baz",
                },
            ]),
        },
        LexerTest {
            test: "func()",
            result: Vec::from([
                Token {
                    kind: TokenKind::Literal,
                    span: (0, 4),
                    value: "func",
                },
                Token {
                    kind: TokenKind::Bracket(Bracket::LeftParenthesis),
                    span: (4, 5),
                    value: "(",
                },
                Token {
                    kind: TokenKind::Bracket(Bracket::RightParenthesis),
                    span: (5, 6),
                    value: ")",
                },
            ]),
        },
        LexerTest {
            test: "not abc not in i not(false) not  ",
            result: Vec::from([
                Token {
                    kind: TokenKind::Operator(Operator::Logical(LogicalOperator::Not)),
                    span: (0, 3),
                    value: "not",
                },
                Token {
                    kind: TokenKind::Literal,
                    span: (4, 7),
                    value: "abc",
                },
                Token {
                    kind: TokenKind::Operator(Operator::Comparison(ComparisonOperator::NotIn)),
                    span: (8, 14),
                    value: "not in",
                },
                Token {
                    kind: TokenKind::Literal,
                    span: (15, 16),
                    value: "i",
                },
                Token {
                    kind: TokenKind::Operator(Operator::Logical(LogicalOperator::Not)),
                    span: (17, 20),
                    value: "not",
                },
                Token {
                    kind: TokenKind::Bracket(Bracket::LeftParenthesis),
                    span: (20, 21),
                    value: "(",
                },
                Token {
                    kind: TokenKind::Boolean(false),
                    span: (21, 26),
                    value: "false",
                },
                Token {
                    kind: TokenKind::Bracket(Bracket::RightParenthesis),
                    span: (26, 27),
                    value: ")",
                },
                Token {
                    kind: TokenKind::Operator(Operator::Logical(LogicalOperator::Not)),
                    span: (28, 31),
                    value: "not",
                },
            ]),
        },
        LexerTest {
            test: "not in_var",
            result: Vec::from([
                Token {
                    kind: TokenKind::Operator(Operator::Logical(LogicalOperator::Not)),
                    span: (0, 3),
                    value: "not",
                },
                Token {
                    kind: TokenKind::Literal,
                    span: (4, 10),
                    value: "in_var",
                },
            ]),
        },
        LexerTest {
            test: "[1..5)",
            result: Vec::from([
                Token {
                    kind: TokenKind::Bracket(Bracket::LeftSquareBracket),
                    span: (0, 1),
                    value: "[",
                },
                Token {
                    kind: TokenKind::Number,
                    span: (1, 2),
                    value: "1",
                },
                Token {
                    kind: TokenKind::Operator(Operator::Range),
                    span: (2, 4),
                    value: "..",
                },
                Token {
                    kind: TokenKind::Number,
                    span: (4, 5),
                    value: "5",
                },
                Token {
                    kind: TokenKind::Bracket(Bracket::RightParenthesis),
                    span: (5, 6),
                    value: ")",
                },
            ]),
        },
        LexerTest {
            test: "product.price > 500 ? 'hello'  :   'world'",
            result: Vec::from([
                Token {
                    kind: TokenKind::Literal,
                    span: (0, 7),
                    value: "product",
                },
                Token {
                    kind: TokenKind::Operator(Operator::Dot),
                    span: (7, 8),
                    value: ".",
                },
                Token {
                    kind: TokenKind::Literal,
                    span: (8, 13),
                    value: "price",
                },
                Token {
                    kind: TokenKind::Operator(Operator::Comparison(
                        ComparisonOperator::GreaterThan,
                    )),
                    span: (14, 15),
                    value: ">",
                },
                Token {
                    kind: TokenKind::Number,
                    span: (16, 19),
                    value: "500",
                },
                Token {
                    kind: TokenKind::Operator(Operator::QuestionMark),
                    span: (20, 21),
                    value: "?",
                },
                Token {
                    kind: TokenKind::QuotationMark(QuotationMark::SingleQuote),
                    span: (22, 23),
                    value: "'",
                },
                Token {
                    kind: TokenKind::Literal,
                    span: (23, 28),
                    value: "hello",
                },
                Token {
                    kind: TokenKind::QuotationMark(QuotationMark::SingleQuote),
                    span: (28, 29),
                    value: "'",
                },
                Token {
                    kind: TokenKind::Operator(Operator::Slice),
                    span: (31, 32),
                    value: ":",
                },
                Token {
                    kind: TokenKind::QuotationMark(QuotationMark::SingleQuote),
                    span: (35, 36),
                    value: "'",
                },
                Token {
                    kind: TokenKind::Literal,
                    span: (36, 41),
                    value: "world",
                },
                Token {
                    kind: TokenKind::QuotationMark(QuotationMark::SingleQuote),
                    span: (41, 42),
                    value: "'",
                },
            ]),
        },
    ]);

    let mut lexer = Lexer::new();

    for LexerTest { test, result } in tests {
        let tokens = lexer.tokenize(test);
        assert!(tokens.is_ok());

        assert_eq!(
            tokens.unwrap(),
            result.as_slice(),
            "Expression failed: {test}"
        );
    }
}