1
use crate::diagnostics::diagnostics_api::SymbolKind;
2
use crate::errors::{FatalParseError, RecoverableParseError};
3
use crate::parser::ParseContext;
4
use crate::parser::atom::parse_atom;
5
use crate::parser::comprehension::parse_quantifier_or_aggregate_expr;
6
use crate::util::TypecheckingContext;
7
use crate::util::named_children;
8
use crate::{child, field, named_child};
9
use conjure_cp_core::ast::{Atom, DeclarationKind, ReturnType, Typeable};
10
use conjure_cp_core::ast::{Expression, Metadata, Moo};
11
use conjure_cp_core::into_matrix_expr;
12
use conjure_cp_core::{domain_int, matrix_expr, range};
13
use tree_sitter::Node;
14
use uniplate::Uniplate;
15

            
16
395737
pub fn parse_expression(
17
395737
    ctx: &mut ParseContext,
18
395737
    node: Node,
19
395737
) -> Result<Option<Expression>, FatalParseError> {
20
395737
    match node.kind() {
21
395737
        "atom" => parse_atom(ctx, &node),
22
217097
        "bool_expr" => parse_boolean_expression(ctx, &node),
23
45662
        "arithmetic_expr" => parse_arithmetic_expression(ctx, &node),
24
28663
        "comparison_expr" => parse_comparison_expression(ctx, &node),
25
5866
        "dominance_relation" => parse_dominance_relation(ctx, &node),
26
169
        "all_diff_comparison" => parse_all_diff_comparison(ctx, &node),
27
        _ => {
28
39
            ctx.record_error(RecoverableParseError::new(
29
39
                format!("Unexpected expression type: '{}'", node.kind()),
30
39
                Some(node.range()),
31
            ));
32
39
            Ok(None)
33
        }
34
    }
35
395737
}
36

            
37
5697
fn parse_dominance_relation(
38
5697
    ctx: &mut ParseContext,
39
5697
    node: &Node,
40
5697
) -> Result<Option<Expression>, FatalParseError> {
41
5697
    if ctx.root.kind() == "dominance_relation" {
42
        ctx.record_error(RecoverableParseError::new(
43
            "Nested dominance relations are not allowed".to_string(),
44
            Some(node.range()),
45
        ));
46
        return Ok(None);
47
5697
    }
48

            
49
5697
    let Some(inner_node) = field!(recover, ctx, node, "expression") else {
50
        return Ok(None);
51
    };
52

            
53
    // NB: In all other cases, we keep the root the same;
54
    // However, here we create a new context with the new root so downstream functions
55
    // know we are inside a dominance relation
56
5697
    let mut inner_ctx = ParseContext {
57
5697
        source_code: ctx.source_code,
58
5697
        root: node,
59
5697
        symbols: ctx.symbols.clone(),
60
5697
        errors: ctx.errors,
61
5697
        source_map: &mut *ctx.source_map,
62
5697
        decl_spans: ctx.decl_spans,
63
5697
        typechecking_context: ctx.typechecking_context,
64
5697
    };
65

            
66
5697
    let Some(inner) = parse_expression(&mut inner_ctx, inner_node)? else {
67
        return Ok(None);
68
    };
69

            
70
5697
    Ok(Some(Expression::DominanceRelation(
71
5697
        Metadata::new(),
72
5697
        Moo::new(inner),
73
5697
    )))
74
5697
}
75

            
76
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
77
enum ParetoDirection {
78
    Minimising,
79
    Maximising,
80
}
81

            
82
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
83
enum ReferenceRewriteAction {
84
    LeaveAsIs,
85
    ExpandValueLetting,
86
    WrapInFromSolution,
87
}
88

            
89
1095
pub fn parse_pareto_expression(
90
1095
    ctx: &mut ParseContext,
91
1095
    node: &Node,
92
1095
) -> Result<Option<Expression>, FatalParseError> {
93
1095
    if ctx.root.kind() != "dominance_relation" {
94
        ctx.record_error(RecoverableParseError::new(
95
            "pareto(...) only allowed inside dominance relations".to_string(),
96
            Some(node.range()),
97
        ));
98
        return Ok(None);
99
1095
    }
100

            
101
1095
    let mut non_worsening = Vec::new();
102
1095
    let mut strict_improvements = Vec::new();
103
1095
    let components = field!(node, "components");
104

            
105
1095
    if components.kind() != "pareto_items" {
106
        return Err(FatalParseError::internal_error(
107
            format!("Unexpected pareto component list: '{}'", components.kind()),
108
            Some(components.range()),
109
        ));
110
1095
    }
111

            
112
2188
    for item_node in named_children(&components) {
113
2188
        let direction_node = field!(item_node, "direction");
114
2188
        let direction_str =
115
2188
            &ctx.source_code[direction_node.start_byte()..direction_node.end_byte()];
116
2188
        let direction = match direction_str {
117
2188
            "minimising" => ParetoDirection::Minimising,
118
1
            "maximising" => ParetoDirection::Maximising,
119
            _ => {
120
                return Err(FatalParseError::internal_error(
121
                    format!("Unexpected pareto direction: '{direction_str}'"),
122
                    Some(direction_node.range()),
123
                ));
124
            }
125
        };
126

            
127
2188
        let component_node = field!(item_node, "expression");
128
2188
        let Some(component_expr) = parse_pareto_component(ctx, &component_node)? else {
129
            return Ok(None);
130
        };
131
2188
        let Some((non_worse, strict)) =
132
2188
            build_pareto_constraints(ctx, &component_node, component_expr, direction)
133
        else {
134
            return Ok(None);
135
        };
136
2188
        non_worsening.push(non_worse);
137
2188
        strict_improvements.push(strict);
138
    }
139

            
140
1095
    let mut conjuncts = non_worsening;
141
1095
    conjuncts.push(combine_with_and_or(strict_improvements, true));
142

            
143
1095
    Ok(Some(combine_with_and_or(conjuncts, false)))
144
1095
}
145

            
146
2188
fn parse_pareto_component(
147
2188
    ctx: &mut ParseContext,
148
2188
    node: &Node,
149
2188
) -> Result<Option<Expression>, FatalParseError> {
150
2188
    let saved_context = ctx.typechecking_context;
151
2188
    ctx.typechecking_context = TypecheckingContext::Unknown;
152
2188
    let parsed = parse_expression(ctx, *node)?;
153
2188
    ctx.typechecking_context = saved_context;
154
2188
    Ok(parsed)
155
2188
}
156

            
157
2188
fn build_pareto_constraints(
158
2188
    ctx: &mut ParseContext,
159
2188
    node: &Node,
160
2188
    component: Expression,
161
2188
    direction: ParetoDirection,
162
2188
) -> Option<(Expression, Expression)> {
163
2188
    if component
164
2188
        .universe()
165
2188
        .iter()
166
3829
        .any(|expr| matches!(expr, Expression::FromSolution(_, _)))
167
    {
168
        ctx.record_error(RecoverableParseError::new(
169
            "pareto(...) components cannot contain fromSolution(...) explicitly".to_string(),
170
            Some(node.range()),
171
        ));
172
        return None;
173
2188
    }
174

            
175
2188
    let current = expand_value_lettings(&component);
176
2188
    let previous = lift_to_previous_solution(&current);
177

            
178
2188
    match current.return_type() {
179
2188
        ReturnType::Int => Some(match direction {
180
2187
            ParetoDirection::Minimising => (
181
2187
                Expression::Leq(
182
2187
                    Metadata::new(),
183
2187
                    Moo::new(current.clone()),
184
2187
                    Moo::new(previous.clone()),
185
2187
                ),
186
2187
                Expression::Lt(Metadata::new(), Moo::new(current), Moo::new(previous)),
187
2187
            ),
188
1
            ParetoDirection::Maximising => (
189
1
                Expression::Geq(
190
1
                    Metadata::new(),
191
1
                    Moo::new(current.clone()),
192
1
                    Moo::new(previous.clone()),
193
1
                ),
194
1
                Expression::Gt(Metadata::new(), Moo::new(current), Moo::new(previous)),
195
1
            ),
196
        }),
197
        ReturnType::Bool => Some(match direction {
198
            ParetoDirection::Minimising => (
199
                Expression::Imply(
200
                    Metadata::new(),
201
                    Moo::new(current.clone()),
202
                    Moo::new(previous.clone()),
203
                ),
204
                combine_with_and_or(
205
                    vec![
206
                        Expression::Not(Metadata::new(), Moo::new(current)),
207
                        previous,
208
                    ],
209
                    false,
210
                ),
211
            ),
212
            ParetoDirection::Maximising => (
213
                Expression::Imply(
214
                    Metadata::new(),
215
                    Moo::new(previous.clone()),
216
                    Moo::new(current.clone()),
217
                ),
218
                combine_with_and_or(
219
                    vec![
220
                        current,
221
                        Expression::Not(Metadata::new(), Moo::new(previous)),
222
                    ],
223
                    false,
224
                ),
225
            ),
226
        }),
227
        found => {
228
            ctx.record_error(RecoverableParseError::new(
229
                format!(
230
                    "pareto(...) only supports int or bool components, found '{}'",
231
                    found
232
                ),
233
                Some(node.range()),
234
            ));
235
            None
236
        }
237
    }
238
2188
}
239

            
240
2188
fn expand_value_lettings(expr: &Expression) -> Expression {
241
2188
    rewrite_references(expr, false)
242
2188
}
243

            
244
2188
fn lift_to_previous_solution(expr: &Expression) -> Expression {
245
2188
    rewrite_references(expr, true)
246
2188
}
247

            
248
4376
fn rewrite_references(expr: &Expression, to_previous_solution: bool) -> Expression {
249
4376
    let mut lifted = expr.clone();
250

            
251
    loop {
252
6564
        let next = lifted.rewrite(&|subexpr| match subexpr {
253
4376
            Expression::Atomic(_, Atom::Reference(ref reference)) => {
254
4376
                let action = {
255
4376
                    let kind = reference.ptr.kind();
256
4376
                    match &*kind {
257
2188
                        DeclarationKind::Find(_) if to_previous_solution => {
258
2188
                            ReferenceRewriteAction::WrapInFromSolution
259
                        }
260
2188
                        DeclarationKind::Find(_) => ReferenceRewriteAction::LeaveAsIs,
261
                        DeclarationKind::ValueLetting(_, _)
262
                        | DeclarationKind::TemporaryValueLetting(_) => {
263
                            ReferenceRewriteAction::ExpandValueLetting
264
                        }
265
                        DeclarationKind::Given(_)
266
                        | DeclarationKind::Quantified(_)
267
                        | DeclarationKind::QuantifiedExpr(_)
268
                        | DeclarationKind::DomainLetting(_)
269
                        | DeclarationKind::RecordField(_)
270
                        | _ => ReferenceRewriteAction::LeaveAsIs,
271
                    }
272
                };
273

            
274
4376
                match action {
275
2188
                    ReferenceRewriteAction::LeaveAsIs => Some(subexpr),
276
                    ReferenceRewriteAction::ExpandValueLetting => reference.resolve_expression(),
277
2188
                    ReferenceRewriteAction::WrapInFromSolution => Some(Expression::FromSolution(
278
2188
                        Metadata::new(),
279
2188
                        Moo::new(Atom::Reference(reference.clone())),
280
2188
                    )),
281
                }
282
            }
283
7111
            _ => Some(subexpr),
284
11487
        });
285

            
286
6564
        if next == lifted {
287
4376
            return lifted;
288
2188
        }
289

            
290
2188
        lifted = next;
291
    }
292
4376
}
293

            
294
2190
fn combine_with_and_or(exprs: Vec<Expression>, is_or: bool) -> Expression {
295
2190
    match exprs.len() {
296
        0 => {
297
            if is_or {
298
                Expression::Or(Metadata::new(), Moo::new(into_matrix_expr![exprs]))
299
            } else {
300
                Expression::And(Metadata::new(), Moo::new(into_matrix_expr![exprs]))
301
            }
302
        }
303
2
        1 => match exprs.into_iter().next() {
304
2
            Some(expr) => expr,
305
            None => unreachable!("vector length already checked"),
306
        },
307
        _ => {
308
2188
            if is_or {
309
1093
                Expression::Or(Metadata::new(), Moo::new(into_matrix_expr![exprs]))
310
            } else {
311
1095
                Expression::And(Metadata::new(), Moo::new(into_matrix_expr![exprs]))
312
            }
313
        }
314
    }
315
2190
}
316

            
317
16999
fn parse_arithmetic_expression(
318
16999
    ctx: &mut ParseContext,
319
16999
    node: &Node,
320
16999
) -> Result<Option<Expression>, FatalParseError> {
321
16999
    ctx.typechecking_context = TypecheckingContext::Arithmetic;
322
16999
    let Some(inner) = named_child!(recover, ctx, node) else {
323
        return Ok(None);
324
    };
325
16999
    match inner.kind() {
326
16999
        "atom" => parse_atom(ctx, &inner),
327
16999
        "negative_expr" | "abs_value" | "sub_arith_expr" | "factorial_expr" => {
328
3704
            parse_unary_expression(ctx, &inner)
329
        }
330
13295
        "toInt_expr" => {
331
            // add special handling for toInt, as it is arithmetic but takes a non-arithmetic operand
332
140
            ctx.typechecking_context = TypecheckingContext::Unknown;
333
140
            parse_unary_expression(ctx, &inner)
334
        }
335
13155
        "exponent" | "product_expr" | "sum_expr" => parse_binary_expression(ctx, &inner),
336
1877
        "list_combining_expr_arith" => parse_list_combining_expression(ctx, &inner),
337
234
        "aggregate_expr" => parse_quantifier_or_aggregate_expr(ctx, &inner),
338
        _ => {
339
            ctx.record_error(RecoverableParseError::new(
340
                format!("Expected arithmetic expression, found: {}", inner.kind()),
341
                Some(inner.range()),
342
            ));
343
            Ok(None)
344
        }
345
    }
346
16999
}
347

            
348
22797
fn parse_comparison_expression(
349
22797
    ctx: &mut ParseContext,
350
22797
    node: &Node,
351
22797
) -> Result<Option<Expression>, FatalParseError> {
352
22797
    let Some(inner) = named_child!(recover, ctx, node) else {
353
        return Ok(None);
354
    };
355
22797
    match inner.kind() {
356
22797
        "arithmetic_comparison" => {
357
            // Arithmetic comparisons require arithmetic operands
358
10148
            ctx.typechecking_context = TypecheckingContext::Arithmetic;
359
10148
            parse_binary_expression(ctx, &inner)
360
        }
361
12649
        "lex_comparison" => {
362
            // TODO: check that both operands are comparable collections.
363
494
            ctx.typechecking_context = TypecheckingContext::Unknown;
364
494
            parse_binary_expression(ctx, &inner)
365
        }
366
12155
        "equality_comparison" => {
367
            // Equality works on any type
368
            // TODO: add type checking to ensure both sides have the same type
369
10320
            ctx.typechecking_context = TypecheckingContext::Unknown;
370
10320
            parse_binary_expression(ctx, &inner)
371
        }
372
1835
        "set_comparison" => {
373
            // Set comparisons require set operands (except 'in', which is hadled later)
374
677
            ctx.typechecking_context = TypecheckingContext::Set;
375
677
            parse_binary_expression(ctx, &inner)
376
        }
377
1158
        "all_diff_comparison" => {
378
            // TODO: check that operand is a collection with compatible element type.
379
1158
            ctx.typechecking_context = TypecheckingContext::Unknown;
380
1158
            parse_all_diff_comparison(ctx, &inner)
381
        }
382
        _ => {
383
            ctx.record_error(RecoverableParseError::new(
384
                format!("Expected comparison expression, found '{}'", inner.kind()),
385
                Some(inner.range()),
386
            ));
387
            Ok(None)
388
        }
389
    }
390
22797
}
391

            
392
171435
fn parse_boolean_expression(
393
171435
    ctx: &mut ParseContext,
394
171435
    node: &Node,
395
171435
) -> Result<Option<Expression>, FatalParseError> {
396
171435
    ctx.typechecking_context = TypecheckingContext::Boolean;
397
171435
    let Some(inner) = named_child!(recover, ctx, node) else {
398
        return Ok(None);
399
    };
400
171435
    match inner.kind() {
401
171435
        "atom" => parse_atom(ctx, &inner),
402
171435
        "not_expr" | "sub_bool_expr" => parse_unary_expression(ctx, &inner),
403
84751
        "and_expr" | "or_expr" | "implication" | "iff_expr" => parse_binary_expression(ctx, &inner),
404
2506
        "list_combining_expr_bool" => parse_list_combining_expression(ctx, &inner),
405
1846
        "quantifier_expr" => parse_quantifier_or_aggregate_expr(ctx, &inner),
406
        _ => {
407
            ctx.record_error(RecoverableParseError::new(
408
                format!("Expected boolean expression, found '{}'", inner.kind()),
409
                Some(inner.range()),
410
            ));
411
            Ok(None)
412
        }
413
    }
414
171435
}
415

            
416
2303
fn parse_list_combining_expression(
417
2303
    ctx: &mut ParseContext,
418
2303
    node: &Node,
419
2303
) -> Result<Option<Expression>, FatalParseError> {
420
2303
    let Some(operator_node) = field!(recover, ctx, node, "operator") else {
421
        return Ok(None);
422
    };
423
2303
    let operator_str = &ctx.source_code[operator_node.start_byte()..operator_node.end_byte()];
424

            
425
2303
    let Some(arg_node) = field!(recover, ctx, node, "arg") else {
426
        return Ok(None);
427
    };
428
2303
    let Some(inner) = parse_atom(ctx, &arg_node)? else {
429
39
        return Ok(None);
430
    };
431

            
432
2264
    let expr = match operator_str {
433
2264
        "and" => Ok(Some(Expression::And(Metadata::new(), Moo::new(inner)))),
434
1716
        "or" => Ok(Some(Expression::Or(Metadata::new(), Moo::new(inner)))),
435
1630
        "sum" => Ok(Some(Expression::Sum(Metadata::new(), Moo::new(inner)))),
436
1388
        "product" => Ok(Some(Expression::Product(Metadata::new(), Moo::new(inner)))),
437
1388
        "min" => Ok(Some(Expression::Min(Metadata::new(), Moo::new(inner)))),
438
660
        "max" => Ok(Some(Expression::Max(Metadata::new(), Moo::new(inner)))),
439
        _ => {
440
            ctx.record_error(RecoverableParseError::new(
441
                format!("Invalid operator: '{operator_str}'"),
442
                Some(operator_node.range()),
443
            ));
444
            Ok(None)
445
        }
446
    };
447

            
448
2264
    if expr.is_ok() {
449
2264
        ctx.add_span_and_doc_hover(
450
2264
            &operator_node,
451
2264
            operator_str,
452
2264
            SymbolKind::Function,
453
2264
            None,
454
2264
            None,
455
2264
        );
456
2264
    }
457

            
458
2264
    expr
459
2303
}
460

            
461
1288
fn parse_all_diff_comparison(
462
1288
    ctx: &mut ParseContext,
463
1288
    node: &Node,
464
1288
) -> Result<Option<Expression>, FatalParseError> {
465
1288
    let Some(arg_node) = field!(recover, ctx, node, "arg") else {
466
        return Ok(None);
467
    };
468
1288
    let Some(inner) = parse_expression(ctx, arg_node)? else {
469
        return Ok(None);
470
    };
471

            
472
1288
    let all_diff_keyword_node = child!(node, 0, "allDiff");
473
1288
    ctx.add_span_and_doc_hover(
474
1288
        &all_diff_keyword_node,
475
1288
        "allDiff",
476
1288
        SymbolKind::Function,
477
1288
        None,
478
1288
        None,
479
    );
480
1288
    Ok(Some(Expression::AllDiff(Metadata::new(), Moo::new(inner))))
481
1288
}
482

            
483
90528
fn parse_unary_expression(
484
90528
    ctx: &mut ParseContext,
485
90528
    node: &Node,
486
90528
) -> Result<Option<Expression>, FatalParseError> {
487
90528
    let Some(expr_node) = field!(recover, ctx, node, "expression") else {
488
        return Ok(None);
489
    };
490
90528
    let Some(inner) = parse_expression(ctx, expr_node)? else {
491
        return Ok(None);
492
    };
493

            
494
90528
    match node.kind() {
495
90528
        "negative_expr" => Ok(Some(Expression::Neg(Metadata::new(), Moo::new(inner)))),
496
89530
        "abs_value" => Ok(Some(Expression::Abs(Metadata::new(), Moo::new(inner)))),
497
89192
        "not_expr" => Ok(Some(Expression::Not(Metadata::new(), Moo::new(inner)))),
498
66581
        "toInt_expr" => {
499
140
            let to_int_keyword_node = child!(node, 0, "toInt");
500
140
            ctx.add_span_and_doc_hover(
501
140
                &to_int_keyword_node,
502
140
                "toInt",
503
140
                SymbolKind::Function,
504
140
                None,
505
140
                None,
506
            );
507
140
            Ok(Some(Expression::ToInt(Metadata::new(), Moo::new(inner))))
508
        }
509
66441
        "factorial_expr" => {
510
            // looking for the operator node (either '!' at the end or 'factorial' at the start) to add hover info
511
            if let Some(op_node) = (0..node.child_count())
512
                .filter_map(|i| node.child(i.try_into().unwrap()))
513
                .find(|c| matches!(c.kind(), "!" | "factorial"))
514
            {
515
                ctx.add_span_and_doc_hover(
516
                    &op_node,
517
                    "post_factorial",
518
                    SymbolKind::Function,
519
                    None,
520
                    None,
521
                );
522
            }
523

            
524
            Ok(Some(Expression::Factorial(
525
                Metadata::new(),
526
                Moo::new(inner),
527
            )))
528
        }
529
66441
        "sub_bool_expr" | "sub_arith_expr" => Ok(Some(inner)),
530
        _ => {
531
            ctx.record_error(RecoverableParseError::new(
532
                format!("Unrecognised unary operation: '{}'", node.kind()),
533
                Some(node.range()),
534
            ));
535
            Ok(None)
536
        }
537
    }
538
90528
}
539

            
540
115318
pub fn parse_binary_expression(
541
115318
    ctx: &mut ParseContext,
542
115318
    node: &Node,
543
115318
) -> Result<Option<Expression>, FatalParseError> {
544
115318
    let Some(op_node) = field!(recover, ctx, node, "operator") else {
545
        return Ok(None);
546
    };
547
115318
    let op_str = &ctx.source_code[op_node.start_byte()..op_node.end_byte()];
548

            
549
115318
    let saved_ctx = ctx.typechecking_context;
550

            
551
    // Special handling for 'in' operator, as the left operand doesn't have to be a set
552
115318
    if op_str == "in" {
553
196
        ctx.typechecking_context = TypecheckingContext::Unknown
554
115122
    }
555

            
556
    // parse left operand
557
115318
    let Some(left_node) = field!(recover, ctx, node, "left") else {
558
        return Ok(None);
559
    };
560
115318
    let Some(left) = parse_expression(ctx, left_node)? else {
561
260
        return Ok(None);
562
    };
563

            
564
    // reset context, if needed
565
115058
    ctx.typechecking_context = saved_ctx;
566

            
567
    // parse right operand
568
115058
    let Some(right_node) = field!(recover, ctx, node, "right") else {
569
        return Ok(None);
570
    };
571
115058
    let Some(right) = parse_expression(ctx, right_node)? else {
572
143
        return Ok(None);
573
    };
574

            
575
114915
    let Some(op_node) = field!(recover, ctx, node, "operator") else {
576
        return Ok(None);
577
    };
578
114915
    let op_str = &ctx.source_code[op_node.start_byte()..op_node.end_byte()];
579

            
580
114915
    let mut doc_name = "";
581
114915
    let expr = match op_str {
582
        // NB: We are deliberately setting the index domain to 1.., not 1..2.
583
        // Semantically, this means "a list that can grow/shrink arbitrarily".
584
        // This is expected by rules which will modify the terms of the sum expression
585
        // (e.g. by partially evaluating them).
586
114915
        "+" => {
587
6154
            doc_name = "L_Plus";
588
6154
            Ok(Some(Expression::Sum(
589
6154
                Metadata::new(),
590
6154
                Moo::new(matrix_expr![left, right; domain_int!(1..)]),
591
6154
            )))
592
        }
593
108761
        "-" => {
594
1169
            doc_name = "L_Minus";
595
1169
            Ok(Some(Expression::Minus(
596
1169
                Metadata::new(),
597
1169
                Moo::new(left),
598
1169
                Moo::new(right),
599
1169
            )))
600
        }
601
107592
        "*" => {
602
951
            doc_name = "L_Times";
603
951
            Ok(Some(Expression::Product(
604
951
                Metadata::new(),
605
951
                Moo::new(matrix_expr![left, right; domain_int!(1..)]),
606
951
            )))
607
        }
608
106641
        "/\\" => {
609
39577
            doc_name = "and";
610
39577
            Ok(Some(Expression::And(
611
39577
                Metadata::new(),
612
39577
                Moo::new(matrix_expr![left, right; domain_int!(1..)]),
613
39577
            )))
614
        }
615
67064
        "\\/" => {
616
            // No documentation for or in Bits yet
617
24931
            doc_name = "or";
618
24931
            Ok(Some(Expression::Or(
619
24931
                Metadata::new(),
620
24931
                Moo::new(matrix_expr![left, right; domain_int!(1..)]),
621
24931
            )))
622
        }
623
42133
        "**" => {
624
806
            doc_name = "L_Pow";
625
806
            Ok(Some(Expression::UnsafePow(
626
806
                Metadata::new(),
627
806
                Moo::new(left),
628
806
                Moo::new(right),
629
806
            )))
630
        }
631
41327
        "/" => {
632
            //TODO: add checks for if division is safe or not
633
1483
            doc_name = "L_Div";
634
1483
            Ok(Some(Expression::UnsafeDiv(
635
1483
                Metadata::new(),
636
1483
                Moo::new(left),
637
1483
                Moo::new(right),
638
1483
            )))
639
        }
640
39844
        "%" => {
641
            //TODO: add checks for if mod is safe or not
642
650
            doc_name = "L_Mod";
643
650
            Ok(Some(Expression::UnsafeMod(
644
650
                Metadata::new(),
645
650
                Moo::new(left),
646
650
                Moo::new(right),
647
650
            )))
648
        }
649

            
650
39194
        "=" => {
651
8463
            doc_name = "L_Eq"; //no docs yet
652
8463
            Ok(Some(Expression::Eq(
653
8463
                Metadata::new(),
654
8463
                Moo::new(left),
655
8463
                Moo::new(right),
656
8463
            )))
657
        }
658
30731
        "!=" => {
659
1662
            doc_name = "L_Neq"; //no docs yet
660
1662
            Ok(Some(Expression::Neq(
661
1662
                Metadata::new(),
662
1662
                Moo::new(left),
663
1662
                Moo::new(right),
664
1662
            )))
665
        }
666
29069
        "<=" => {
667
3638
            doc_name = "L_Leq"; //no docs yet
668
3638
            Ok(Some(Expression::Leq(
669
3638
                Metadata::new(),
670
3638
                Moo::new(left),
671
3638
                Moo::new(right),
672
3638
            )))
673
        }
674
25431
        ">=" => {
675
2955
            doc_name = "L_Geq"; //no docs yet
676
2955
            Ok(Some(Expression::Geq(
677
2955
                Metadata::new(),
678
2955
                Moo::new(left),
679
2955
                Moo::new(right),
680
2955
            )))
681
        }
682
22476
        "<" => {
683
2567
            doc_name = "L_Lt"; //no docs yet
684
2567
            Ok(Some(Expression::Lt(
685
2567
                Metadata::new(),
686
2567
                Moo::new(left),
687
2567
                Moo::new(right),
688
2567
            )))
689
        }
690
19909
        ">" => {
691
936
            doc_name = "L_Gt"; //no docs yet
692
936
            Ok(Some(Expression::Gt(
693
936
                Metadata::new(),
694
936
                Moo::new(left),
695
936
                Moo::new(right),
696
936
            )))
697
        }
698

            
699
18973
        "->" => {
700
17534
            doc_name = "L_Imply"; //no docs yet
701
17534
            Ok(Some(Expression::Imply(
702
17534
                Metadata::new(),
703
17534
                Moo::new(left),
704
17534
                Moo::new(right),
705
17534
            )))
706
        }
707
1439
        "<->" => {
708
151
            doc_name = "L_Iff"; //no docs yet
709
151
            Ok(Some(Expression::Iff(
710
151
                Metadata::new(),
711
151
                Moo::new(left),
712
151
                Moo::new(right),
713
151
            )))
714
        }
715
1288
        "<lex" => {
716
156
            doc_name = "L_LexLt"; //no docs yet
717
156
            Ok(Some(Expression::LexLt(
718
156
                Metadata::new(),
719
156
                Moo::new(left),
720
156
                Moo::new(right),
721
156
            )))
722
        }
723
1132
        ">lex" => {
724
52
            doc_name = "L_LexGt"; //no docs yet
725
52
            Ok(Some(Expression::LexGt(
726
52
                Metadata::new(),
727
52
                Moo::new(left),
728
52
                Moo::new(right),
729
52
            )))
730
        }
731
1080
        "<=lex" => {
732
208
            doc_name = "L_LexLeq"; //no docs yet
733
208
            Ok(Some(Expression::LexLeq(
734
208
                Metadata::new(),
735
208
                Moo::new(left),
736
208
                Moo::new(right),
737
208
            )))
738
        }
739
872
        ">=lex" => {
740
78
            doc_name = "L_LexGeq"; //no docs yet
741
78
            Ok(Some(Expression::LexGeq(
742
78
                Metadata::new(),
743
78
                Moo::new(left),
744
78
                Moo::new(right),
745
78
            )))
746
        }
747
794
        "in" => {
748
196
            doc_name = "L_in";
749
196
            Ok(Some(Expression::In(
750
196
                Metadata::new(),
751
196
                Moo::new(left),
752
196
                Moo::new(right),
753
196
            )))
754
        }
755
598
        "subset" => {
756
130
            doc_name = "L_subset";
757
130
            Ok(Some(Expression::Subset(
758
130
                Metadata::new(),
759
130
                Moo::new(left),
760
130
                Moo::new(right),
761
130
            )))
762
        }
763
468
        "subsetEq" => {
764
104
            doc_name = "L_subsetEq";
765
104
            Ok(Some(Expression::SubsetEq(
766
104
                Metadata::new(),
767
104
                Moo::new(left),
768
104
                Moo::new(right),
769
104
            )))
770
        }
771
364
        "supset" => {
772
104
            doc_name = "L_supset";
773
104
            Ok(Some(Expression::Supset(
774
104
                Metadata::new(),
775
104
                Moo::new(left),
776
104
                Moo::new(right),
777
104
            )))
778
        }
779
260
        "supsetEq" => {
780
104
            doc_name = "L_supsetEq";
781
104
            Ok(Some(Expression::SupsetEq(
782
104
                Metadata::new(),
783
104
                Moo::new(left),
784
104
                Moo::new(right),
785
104
            )))
786
        }
787
156
        "union" => {
788
78
            doc_name = "L_union";
789
78
            Ok(Some(Expression::Union(
790
78
                Metadata::new(),
791
78
                Moo::new(left),
792
78
                Moo::new(right),
793
78
            )))
794
        }
795
78
        "intersect" => {
796
78
            doc_name = "L_intersect";
797
78
            Ok(Some(Expression::Intersect(
798
78
                Metadata::new(),
799
78
                Moo::new(left),
800
78
                Moo::new(right),
801
78
            )))
802
        }
803
        _ => {
804
            ctx.record_error(RecoverableParseError::new(
805
                format!("Invalid operator: '{op_str}'"),
806
                Some(op_node.range()),
807
            ));
808
            Ok(None)
809
        }
810
    };
811

            
812
114915
    if expr.is_ok() {
813
114915
        ctx.add_span_and_doc_hover(&op_node, doc_name, SymbolKind::Function, None, None);
814
114915
    }
815

            
816
114915
    expr
817
115318
}