vhdl_lang/syntax/
expression.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this file,
3// You can obtain one at http://mozilla.org/MPL/2.0/.
4//
5// Copyright (c) 2018, Olof Kraigher olof.kraigher@gmail.com
6
7use super::common::ParseResult;
8use super::names::{parse_name, parse_type_mark};
9use super::subtype_indication::parse_subtype_constraint;
10use super::tokens::{Kind, Kind::*};
11use crate::ast::token_range::{WithToken, WithTokenSpan};
12use crate::ast::{Literal, *};
13use crate::data::Diagnostic;
14use crate::syntax::TokenAccess;
15use crate::{ast, HasTokenSpan, TokenId, TokenSpan};
16use vhdl_lang::syntax::parser::ParsingContext;
17
18impl WithTokenSpan<Name> {
19    pub fn into_expression(self) -> WithTokenSpan<Expression> {
20        self.map_into(|name| Expression::Name(Box::new(name)))
21    }
22}
23
24impl Operator {
25    pub fn binary_precedence(&self) -> Option<usize> {
26        Some(match self {
27            Operator::And => 2,
28            Operator::Or => 2,
29            Operator::Nand => 2,
30            Operator::Nor => 2,
31            Operator::Xor => 2,
32            Operator::Xnor => 2,
33            Operator::EQ => 3,
34            Operator::NE => 3,
35            Operator::LT => 3,
36            Operator::LTE => 3,
37            Operator::GT => 3,
38            Operator::GTE => 3,
39            Operator::QueEQ => 3,
40            Operator::QueNE => 3,
41            Operator::QueLT => 3,
42            Operator::QueLTE => 3,
43            Operator::QueGT => 3,
44            Operator::QueGTE => 3,
45            Operator::SLL => 4,
46            Operator::SRL => 4,
47            Operator::SLA => 4,
48            Operator::SRA => 4,
49            Operator::ROL => 4,
50            Operator::ROR => 4,
51            Operator::Plus => 5,
52            Operator::Minus => 5,
53            Operator::Concat => 5,
54            Operator::Times => 7,
55            Operator::Div => 7,
56            Operator::Mod => 7,
57            Operator::Rem => 7,
58            Operator::Pow => 8,
59            _ => {
60                return None;
61            }
62        })
63    }
64
65    pub fn unary_precedence(&self) -> Option<usize> {
66        Some(match self {
67            Operator::Abs => 8,
68            Operator::Not => 8,
69            Operator::Plus => 6,
70            Operator::Minus => 6,
71            Operator::QueQue => 1,
72
73            // LRM: All of the binary logical operators belong to the
74            // class of operators with the lowest precedence. The unary
75            // logical operators belong to the class of operators with
76            // the highest precedence.
77            Operator::And => 8,
78            Operator::Or => 8,
79            Operator::Nand => 8,
80            Operator::Nor => 8,
81            Operator::Xor => 8,
82            Operator::Xnor => 8,
83
84            _ => {
85                return None;
86            }
87        })
88    }
89}
90
91fn kind_to_operator(kind: Kind) -> Option<Operator> {
92    Some(match kind {
93        And => Operator::And,
94        Or => Operator::Or,
95        Nand => Operator::Nand,
96        Nor => Operator::Nor,
97        Xor => Operator::Xor,
98        Xnor => Operator::Xnor,
99        EQ => Operator::EQ,
100        NE => Operator::NE,
101        LT => Operator::LT,
102        LTE => Operator::LTE,
103        GT => Operator::GT,
104        GTE => Operator::GTE,
105        QueEQ => Operator::QueEQ,
106        QueNE => Operator::QueNE,
107        QueLT => Operator::QueLT,
108        QueLTE => Operator::QueLTE,
109        QueGT => Operator::QueGT,
110        QueGTE => Operator::QueGTE,
111        SLL => Operator::SLL,
112        SRL => Operator::SRL,
113        SLA => Operator::SLA,
114        SRA => Operator::SRA,
115        ROL => Operator::ROL,
116        ROR => Operator::ROR,
117        Plus => Operator::Plus,
118        Minus => Operator::Minus,
119        Concat => Operator::Concat,
120        Times => Operator::Times,
121        Div => Operator::Div,
122        Mod => Operator::Mod,
123        Rem => Operator::Rem,
124        Pow => Operator::Pow,
125        Abs => Operator::Abs,
126        Not => Operator::Not,
127        QueQue => Operator::QueQue,
128        _ => {
129            return None;
130        }
131    })
132}
133
134fn kind_to_prefix_unary_op(kind: Kind) -> Option<(Operator, usize)> {
135    let op = kind_to_operator(kind)?;
136    let prec = op.unary_precedence()?;
137    Some((op, prec))
138}
139
140fn kind_to_binary_op(kind: Kind) -> Option<(Operator, usize)> {
141    let op = kind_to_operator(kind)?;
142    let prec = op.binary_precedence()?;
143    Some((op, prec))
144}
145
146pub fn parse_aggregate_initial_choices(
147    ctx: &mut ParsingContext<'_>,
148    start_token: TokenId,
149    choices: Vec<WithTokenSpan<Choice>>,
150) -> ParseResult<WithTokenSpan<Vec<WithTokenSpan<ElementAssociation>>>> {
151    let mut choices = choices;
152    let mut result = Vec::new();
153    loop {
154        expect_token!(
155            ctx.stream,
156            token,
157            token_id,
158            RightPar => {
159                if choices.len() == 1 {
160                    if let Some(WithTokenSpan{item: Choice::Expression(expr), span}) = choices.pop() {
161                        result.push(
162                            WithTokenSpan::new(
163                                ElementAssociation::Positional(WithTokenSpan::new(expr, span)),
164                                span,
165                            )
166                        );
167                        return Ok(WithTokenSpan::new(result, TokenSpan::new(start_token, token_id)))
168                    }
169                }
170
171                return Err(token.kinds_error(&[RightArrow]));
172            },
173            Comma => {
174                if choices.len() == 1 {
175                    if let Some(WithTokenSpan{item: Choice::Expression(expr), span}) = choices.pop() {
176                        result.push(
177                            WithTokenSpan::new(
178                                ElementAssociation::Positional(WithTokenSpan::new(expr, span)),
179                                span
180                            )
181                        );
182                        choices = parse_choices(ctx)?;
183                        continue;
184                    }
185                }
186
187                return Err(token.kinds_error(&[RightArrow]));
188            },
189            RightArrow => {
190                let rhs = parse_expression(ctx)?;
191                let span = TokenSpan::new(choices[0].get_start_token(), rhs.get_end_token());
192                result.push(
193                    WithTokenSpan::new(
194                        ElementAssociation::Named(choices, rhs),
195                        span,
196                    )
197                );
198
199                expect_token!(
200                    ctx.stream,
201                    token,
202                    token_id,
203                    RightPar => {
204                        return Ok(WithTokenSpan::new(result, TokenSpan::new(start_token, token_id)))
205                    },
206                    Comma => {
207                        choices = parse_choices(ctx)?;
208                    }
209                )
210            }
211        );
212    }
213}
214
215pub fn parse_aggregate(
216    ctx: &mut ParsingContext<'_>,
217) -> ParseResult<WithTokenSpan<Vec<WithTokenSpan<ElementAssociation>>>> {
218    let start_tok = ctx.stream.expect_kind(LeftPar)?;
219    if let Some(token) = ctx.stream.pop_if_kind(RightPar) {
220        return Ok(WithTokenSpan::from(
221            Vec::new(),
222            TokenSpan::new(start_tok, token),
223        ));
224    };
225    let choices = parse_choices(ctx)?;
226    parse_aggregate_initial_choices(ctx, start_tok, choices)
227}
228
229fn parse_half_range(
230    ctx: &mut ParsingContext<'_>,
231    left_expr: WithTokenSpan<Expression>,
232    direction: Direction,
233) -> ParseResult<WithTokenSpan<DiscreteRange>> {
234    let right_expr = parse_expression(ctx)?;
235    let pos = left_expr.span.combine(right_expr.span);
236
237    let range = DiscreteRange::Range(ast::Range::Range(RangeConstraint {
238        direction,
239        left_expr: Box::new(left_expr),
240        right_expr: Box::new(right_expr),
241    }));
242
243    Ok(WithTokenSpan::new(range, pos))
244}
245
246fn parse_choice(ctx: &mut ParsingContext<'_>) -> ParseResult<WithTokenSpan<Choice>> {
247    if let Some(token) = ctx.stream.pop_if_kind(Others) {
248        return Ok(WithTokenSpan::from(Choice::Others, token));
249    }
250    let left_expr = parse_expression(ctx)?;
251
252    if ctx.stream.skip_if_kind(To) {
253        let range = parse_half_range(ctx, left_expr, Direction::Ascending)?;
254        Ok(range.map_into(Choice::DiscreteRange))
255    } else if ctx.stream.skip_if_kind(Downto) {
256        let range = parse_half_range(ctx, left_expr, Direction::Descending)?;
257        Ok(range.map_into(Choice::DiscreteRange))
258    } else {
259        Ok(left_expr.map_into(Choice::Expression))
260    }
261}
262
263pub fn parse_choices(ctx: &mut ParsingContext<'_>) -> ParseResult<Vec<WithTokenSpan<Choice>>> {
264    let mut choices = Vec::new();
265    loop {
266        choices.push(parse_choice(ctx)?);
267
268        if !ctx.stream.skip_if_kind(Bar) {
269            break;
270        }
271    }
272    Ok(choices)
273}
274
275/// LRM 9.3.7 Allocators
276fn parse_allocator(ctx: &mut ParsingContext<'_>) -> ParseResult<WithTokenSpan<Allocator>> {
277    ctx.stream.expect_kind(New)?;
278    let type_mark = parse_type_mark(ctx)?;
279
280    if ctx.stream.skip_if_kind(Tick) {
281        let expr = parse_expression(ctx)?;
282        let span = type_mark.span.combine(expr.span);
283        Ok(WithTokenSpan {
284            item: Allocator::Qualified(QualifiedExpression { type_mark, expr }),
285            span,
286        })
287    } else {
288        let mut span = type_mark.span;
289
290        let constraint = {
291            if let Some(constraint) = parse_subtype_constraint(ctx)? {
292                span = span.combine(constraint.span);
293                Some(constraint)
294            } else {
295                None
296            }
297        };
298
299        let subtype = SubtypeIndication {
300            resolution: None,
301            type_mark,
302            constraint,
303        };
304
305        Ok(WithTokenSpan {
306            item: Allocator::Subtype(subtype),
307            span,
308        })
309    }
310}
311
312pub fn name_to_type_mark(
313    ctx: &mut ParsingContext<'_>,
314    name: WithTokenSpan<Name>,
315) -> ParseResult<WithTokenSpan<Name>> {
316    let pos = name.pos(ctx);
317    let type_mark = name
318        .try_map_into(|name| match name {
319            Name::Attribute(_) => Some(name),
320            _ => Some(name_to_selected_name(name)?),
321        })
322        .ok_or_else(|| Diagnostic::syntax_error(&pos, "Expected type mark"))?;
323
324    Ok(type_mark)
325}
326
327fn name_to_selected_name(name: Name) -> Option<Name> {
328    match name {
329        Name::Designator(d) => Some(Name::Designator(d)),
330        Name::Selected(p, d) => Some(Name::Selected(
331            Box::new(p.try_map_into(name_to_selected_name)?),
332            d,
333        )),
334        _ => None,
335    }
336}
337
338fn parse_expression_or_aggregate(
339    ctx: &mut ParsingContext<'_>,
340    start_token: TokenId,
341) -> ParseResult<WithTokenSpan<Expression>> {
342    let mut choices = parse_choices(ctx)?;
343
344    if choices.len() == 1
345        && matches!(
346            choices.first().unwrap(),
347            WithTokenSpan {
348                item: Choice::Expression(_),
349                ..
350            }
351        )
352    {
353        let WithTokenSpan {
354            item: Choice::Expression(expr),
355            span,
356        } = choices.pop().unwrap()
357        else {
358            unreachable!();
359        };
360
361        peek_token!(
362            ctx.stream, token, token_id,
363
364            // Was aggregate
365            Comma | RightArrow => {
366                Ok(parse_aggregate_initial_choices(
367                    ctx,
368                    start_token,
369                    vec![WithTokenSpan::new(Choice::Expression(expr), span)],
370                )?.map_into(Expression::Aggregate))
371            },
372
373            // Was expression with parenthesis
374            RightPar => {
375                ctx.stream.skip();
376                let expr = WithTokenSpan::new(Expression::Parenthesized(Box::new(WithTokenSpan::new(expr, span))), TokenSpan::new(start_token, token_id));
377                Ok(expr)
378            }
379        )
380    } else {
381        // Must be aggregate
382        Ok(parse_aggregate_initial_choices(ctx, start_token, choices)?
383            .map_into(Expression::Aggregate))
384    }
385}
386
387/// Parse a primary value which is:
388/// 1. CHARACTER_LITERAL|INTEGER_LITERAL|IDENTIFIER|BOOLEAN_LITERAL
389/// 2. (expression)
390/// 3. PREFIX_UNARY_OP expression
391fn parse_primary(ctx: &mut ParsingContext<'_>) -> ParseResult<WithTokenSpan<Expression>> {
392    let token = ctx.stream.peek_expect()?;
393    let token_id = ctx.stream.get_current_token_id();
394    match token.kind {
395        Identifier | LtLt => {
396            let name = parse_name(ctx)?;
397            if ctx.stream.skip_if_kind(Tick) {
398                let lpar = ctx.stream.expect_kind(LeftPar)?;
399                let expr = parse_expression_or_aggregate(ctx, lpar)?;
400                let span = name.span.combine(expr.span);
401                Ok(WithTokenSpan::new(
402                    Expression::Qualified(Box::new(QualifiedExpression {
403                        type_mark: name_to_type_mark(ctx, name)?,
404                        expr,
405                    })),
406                    span,
407                ))
408            } else {
409                Ok(name.into_expression())
410            }
411        }
412        BitString => {
413            ctx.stream.skip();
414            Ok(token
415                .to_bit_string(token_id)?
416                .map_into_span(|bs| Expression::Literal(Literal::BitString(bs))))
417        }
418        Character => {
419            ctx.stream.skip();
420            Ok(token
421                .to_character_value(token_id)?
422                .map_into_span(|chr| Expression::Literal(Literal::Character(chr))))
423        }
424        StringLiteral => {
425            if ctx.stream.next_kinds_are(&[StringLiteral, LeftPar]) {
426                // Probably a function call via operator symbol "foo"()
427                parse_name(ctx).map(|name| name.map_into(|name| Expression::Name(Box::new(name))))
428            } else {
429                ctx.stream.skip();
430                Ok(token
431                    .to_string_value(token_id)?
432                    .map_into_span(|string| Expression::Literal(Literal::String(string))))
433            }
434        }
435        Null => {
436            ctx.stream.skip();
437            Ok(WithTokenSpan::from(
438                Expression::Literal(Literal::Null),
439                token_id,
440            ))
441        }
442        New => {
443            let alloc = parse_allocator(ctx)?;
444
445            let new_pos = TokenSpan::new(token_id, alloc.span.end_token);
446            Ok(WithTokenSpan::new(
447                Expression::New(Box::new(alloc)),
448                new_pos,
449            ))
450        }
451        AbstractLiteral => {
452            ctx.stream.skip();
453            let value = token.to_abstract_literal(token_id)?;
454            // Physical unit
455            if let Some(unit_token) = ctx.stream.pop_if_kind(Identifier) {
456                let unit = ctx
457                    .stream
458                    .index(unit_token)
459                    .to_identifier_value(unit_token)?;
460                let span = TokenSpan::new(value.token, unit.token);
461                let physical = PhysicalLiteral {
462                    value: value.item,
463                    unit: WithRef::new(unit),
464                };
465                Ok(WithTokenSpan::new(
466                    Expression::Literal(Literal::Physical(physical)),
467                    span,
468                ))
469            } else {
470                Ok(value
471                    .map_into_span(|value| Expression::Literal(Literal::AbstractLiteral(value))))
472            }
473        }
474
475        LeftPar => {
476            let start_token = ctx.stream.get_current_token_id();
477            ctx.stream.skip();
478            parse_expression_or_aggregate(ctx, start_token)
479        }
480
481        kind => {
482            // Prefix unary operation
483            if let Some((unary_op, op_precedence)) = kind_to_prefix_unary_op(kind) {
484                ctx.stream.skip();
485
486                let expr = parse_expr(ctx, op_precedence)?;
487                let span = TokenSpan::new(token_id, expr.span.end_token);
488
489                Ok(WithTokenSpan::new(
490                    Expression::Unary(
491                        WithToken::new(WithRef::new(unary_op), token_id),
492                        Box::new(expr),
493                    ),
494                    span,
495                ))
496            } else {
497                Err(Diagnostic::syntax_error(
498                    ctx.stream.pos_before(token),
499                    "Expected {expression}",
500                ))
501            }
502        }
503    }
504}
505
506fn parse_expr(
507    ctx: &mut ParsingContext<'_>,
508    min_precedence: usize,
509) -> ParseResult<WithTokenSpan<Expression>> {
510    let mut lhs = parse_primary(ctx)?;
511    while let Some(token) = ctx.stream.peek() {
512        let token_id = ctx.stream.get_current_token_id();
513        if token.kind == RightPar {
514            return Ok(lhs);
515        };
516
517        if let Some((binary_op, op_precedence)) = kind_to_binary_op(token.kind) {
518            // Binary operation
519            if op_precedence > min_precedence {
520                ctx.stream.skip();
521                let rhs = parse_expr(ctx, op_precedence)?;
522                let pos = lhs.span.combine(rhs.span);
523                lhs = WithTokenSpan::new(
524                    Expression::Binary(
525                        WithToken::new(WithRef::new(binary_op), token_id),
526                        Box::new(lhs),
527                        Box::new(rhs),
528                    ),
529                    pos,
530                );
531            } else {
532                return Ok(lhs);
533            }
534        } else {
535            return Ok(lhs);
536        };
537    }
538
539    Ok(lhs)
540}
541
542/// Parse expressions using a [Pratt parser](https://en.wikipedia.org/wiki/Pratt_parser)
543///
544/// Use precedence from LRM 9.2 Operators
545/// All operators are left associative.
546/// Operator classes are listed in order of increasing precedence
547///   1. condition_operator: ??
548///   2. logical_operator: and | or | nand | nor | xor | xnor
549///   3. relational_operator: = | /= | < | <= | > | >= | ?= | ?/= | ?< | ?<= | ?> | ?>=
550///   4. shift_operator: sll | srl | sla | sra | rol | ror
551///   5. adding_operator: + | - | &
552///   6. sign: + | -
553///   7. multiplying_operator: * | / | mod | rem
554///   8. misc_operator: ** | abs | not
555pub fn parse_expression(ctx: &mut ParsingContext<'_>) -> ParseResult<WithTokenSpan<Expression>> {
556    let state = ctx.stream.state();
557    parse_expr(ctx, 0).inspect_err(|_| ctx.stream.set_state(state))
558}
559
560#[cfg(test)]
561mod tests {
562    use super::*;
563    use crate::ast::{AbstractLiteral, Name};
564    use crate::data::Latin1String;
565    use crate::syntax::test::Code;
566
567    #[test]
568    fn parses_character_literal() {
569        let code = Code::new("'a'");
570        assert_eq!(
571            code.with_stream(parse_expression),
572            WithTokenSpan {
573                item: Expression::Literal(Literal::Character(b'a')),
574                span: code.token_span()
575            }
576        );
577    }
578
579    #[test]
580    fn parses_abstract_literal_integer() {
581        let code = Code::new("71");
582        assert_eq!(
583            code.with_stream(parse_expression),
584            WithTokenSpan {
585                item: Expression::Literal(Literal::AbstractLiteral(AbstractLiteral::Integer(71))),
586                span: code.token_span()
587            }
588        );
589    }
590
591    #[test]
592    fn parses_abstract_literal_real() {
593        let code = Code::new("7.1");
594        assert_eq!(
595            code.with_stream(parse_expression),
596            WithTokenSpan {
597                item: Expression::Literal(Literal::AbstractLiteral(AbstractLiteral::Real(7.1))),
598                span: code.token_span()
599            }
600        );
601    }
602
603    #[test]
604    fn parses_string_literal() {
605        let code = Code::new("\"string\"");
606        assert_eq!(
607            code.with_stream(parse_expression),
608            WithTokenSpan {
609                item: Expression::Literal(Literal::String(Latin1String::from_utf8_unchecked(
610                    "string"
611                ))),
612                span: code.token_span()
613            }
614        );
615    }
616
617    #[test]
618    fn parses_operator_symbol() {
619        let code = Code::new("\"+\"(1, 2)");
620        assert_eq!(
621            code.with_stream(parse_expression),
622            code.s1("\"+\"(1, 2)")
623                .name()
624                .map_into(|name| Expression::Name(Box::new(name)))
625        );
626    }
627
628    #[test]
629    fn parses_exteral_name() {
630        let code = Code::new("<< signal dut.foo : boolean >>");
631        assert_eq!(
632            code.with_stream(parse_expression),
633            code.s1("<< signal dut.foo : boolean >>")
634                .name()
635                .map_into(|name| Expression::Name(Box::new(name)))
636        );
637    }
638
639    #[test]
640    fn parses_null_literal() {
641        let code = Code::new("null");
642        assert_eq!(
643            code.with_stream(parse_expression),
644            WithTokenSpan {
645                item: Expression::Literal(Literal::Null),
646                span: code.token_span()
647            }
648        );
649    }
650
651    fn int(value: u64) -> Literal {
652        Literal::AbstractLiteral(AbstractLiteral::Integer(value))
653    }
654
655    #[test]
656    fn parses_add_expression() {
657        let code = Code::new("1 + 2");
658
659        let lhs = WithTokenSpan {
660            item: Expression::Literal(int(1)),
661            span: code.s1("1").token_span(),
662        };
663
664        let rhs = WithTokenSpan {
665            item: Expression::Literal(int(2)),
666            span: code.s1("2").token_span(),
667        };
668
669        let expr_add = WithTokenSpan {
670            item: Expression::Binary(
671                WithToken::new(WithRef::new(Operator::Plus), code.s1("+").token()),
672                Box::new(lhs),
673                Box::new(rhs),
674            ),
675            span: code.token_span(),
676        };
677
678        assert_eq!(code.with_stream(parse_expression), expr_add);
679    }
680
681    #[test]
682    fn parses_sub_expression() {
683        let code = Code::new("1 - 2");
684        let lhs = WithTokenSpan {
685            item: Expression::Literal(int(1)),
686            span: code.s1("1").token_span(),
687        };
688
689        let rhs = WithTokenSpan {
690            item: Expression::Literal(int(2)),
691            span: code.s1("2").token_span(),
692        };
693
694        let expr_sub = WithTokenSpan {
695            item: Expression::Binary(
696                WithToken::new(WithRef::new(Operator::Minus), code.s1("-").token()),
697                Box::new(lhs),
698                Box::new(rhs),
699            ),
700            span: code.token_span(),
701        };
702
703        assert_eq!(code.with_stream(parse_expression), expr_sub);
704    }
705
706    #[test]
707    fn parses_abs_expression() {
708        let code = Code::new("abs 9");
709        let expr = WithTokenSpan {
710            item: Expression::Literal(int(9)),
711            span: code.s1("9").token_span(),
712        };
713
714        let expr_abs = WithTokenSpan {
715            item: Expression::Unary(
716                WithToken::new(WithRef::new(Operator::Abs), code.s1("abs").token()),
717                Box::new(expr),
718            ),
719            span: code.token_span(),
720        };
721
722        assert_eq!(code.with_stream(parse_expression), expr_abs);
723    }
724
725    #[test]
726    fn parses_condition_operator() {
727        let code = Code::new("?? 9");
728        let expr = WithTokenSpan {
729            item: Expression::Literal(int(9)),
730            span: code.s1("9").token_span(),
731        };
732
733        let expr_cond = WithTokenSpan {
734            item: Expression::Unary(
735                WithToken::new(WithRef::new(Operator::QueQue), code.s1("??").token()),
736                Box::new(expr),
737            ),
738            span: code.token_span(),
739        };
740
741        assert_eq!(code.with_stream(parse_expression), expr_cond);
742    }
743
744    #[test]
745    fn parses_not_expression() {
746        let code = Code::new("not false");
747        let name_false = WithTokenSpan {
748            item: Expression::Name(Box::new(Name::Designator(
749                Designator::Identifier(code.symbol("false")).into_ref(),
750            ))),
751            span: code.s1("false").token_span(),
752        };
753
754        let expr_not = WithTokenSpan {
755            item: Expression::Unary(
756                WithToken::new(WithRef::new(Operator::Not), code.s1("not").token()),
757                Box::new(name_false),
758            ),
759            span: code.token_span(),
760        };
761
762        assert_eq!(code.with_stream(parse_expression), expr_not);
763    }
764
765    #[test]
766    fn parses_new_allocator_qualified() {
767        let code = Code::new("new integer_vector'(0, 1)");
768        let type_mark = code.s1("integer_vector").type_mark();
769        let expr = code.s1("(0, 1)").expr();
770
771        let alloc = WithTokenSpan {
772            item: Allocator::Qualified(QualifiedExpression { type_mark, expr }),
773            span: code.s1("integer_vector'(0, 1)").token_span(),
774        };
775
776        let new_expr = WithTokenSpan {
777            item: Expression::New(Box::new(alloc)),
778            span: code.token_span(),
779        };
780
781        assert_eq!(code.with_stream(parse_expression), new_expr);
782    }
783
784    #[test]
785    fn parses_new_allocator_subtype() {
786        let code = Code::new("new integer_vector");
787
788        let alloc = WithTokenSpan {
789            item: Allocator::Subtype(code.s1("integer_vector").subtype_indication()),
790            span: code.s1("integer_vector").token_span(),
791        };
792
793        let new_expr = WithTokenSpan {
794            item: Expression::New(Box::new(alloc)),
795            span: code.token_span(),
796        };
797
798        assert_eq!(code.with_stream(parse_expression), new_expr);
799    }
800
801    #[test]
802    fn parses_new_allocator_subtype_constraint() {
803        let code = Code::new("new integer_vector(0 to 1)");
804
805        let alloc = WithTokenSpan {
806            item: Allocator::Subtype(code.s1("integer_vector(0 to 1)").subtype_indication()),
807            span: code.s1("integer_vector(0 to 1)").token_span(),
808        };
809
810        let new_expr = WithTokenSpan {
811            item: Expression::New(Box::new(alloc)),
812            span: code.token_span(),
813        };
814
815        assert_eq!(code.with_stream(parse_expression), new_expr);
816    }
817
818    #[test]
819    fn parses_new_allocator_subtype_constraint_range_attribute() {
820        let code = Code::new("new integer_vector(foo'range)");
821
822        let alloc = WithTokenSpan {
823            item: Allocator::Subtype(code.s1("integer_vector(foo'range)").subtype_indication()),
824            span: code.s1("integer_vector(foo'range)").token_span(),
825        };
826
827        let new_expr = WithTokenSpan {
828            item: Expression::New(Box::new(alloc)),
829            span: code.token_span(),
830        };
831
832        assert_eq!(code.with_stream(parse_expression), new_expr);
833    }
834
835    #[test]
836    fn parses_physical_unit_expression() {
837        let code = Code::new("1 ns");
838        let expr = WithTokenSpan {
839            item: Expression::Literal(Literal::Physical(PhysicalLiteral {
840                value: AbstractLiteral::Integer(1),
841                unit: code.s1("ns").ident().into_ref(),
842            })),
843            span: code.token_span(),
844        };
845
846        assert_eq!(code.with_stream(parse_expression), expr);
847    }
848
849    #[test]
850    fn parses_physical_unit_expression_real() {
851        let code = Code::new("1.0 ns");
852        let expr = WithTokenSpan {
853            item: Expression::Literal(Literal::Physical(PhysicalLiteral {
854                value: AbstractLiteral::Real(1.0),
855                unit: code.s1("ns").ident().into_ref(),
856            })),
857            span: code.token_span(),
858        };
859
860        assert_eq!(code.with_stream(parse_expression), expr);
861    }
862
863    #[test]
864    fn parses_physical_unit_expression_binary() {
865        let code = Code::new("2 * 1 ns");
866        let time_expr = WithTokenSpan {
867            item: Expression::Literal(Literal::Physical(PhysicalLiteral {
868                value: AbstractLiteral::Integer(1),
869                unit: code.s1("ns").ident().into_ref(),
870            })),
871            span: code.s1("1 ns").token_span(),
872        };
873        let two_expr = WithTokenSpan {
874            item: Expression::Literal(int(2)),
875            span: code.s1("2").token_span(),
876        };
877        let expr = WithTokenSpan {
878            item: Expression::Binary(
879                WithToken::new(WithRef::new(Operator::Times), code.s1("*").token()),
880                Box::new(two_expr),
881                Box::new(time_expr),
882            ),
883            span: code.token_span(),
884        };
885        assert_eq!(code.with_stream(parse_expression), expr);
886    }
887
888    #[test]
889    fn parses_physical_unit_expression_unary() {
890        let code = Code::new("- 1 ns");
891        let time_expr = WithTokenSpan {
892            item: Expression::Literal(Literal::Physical(PhysicalLiteral {
893                value: AbstractLiteral::Integer(1),
894                unit: code.s1("ns").ident().into_ref(),
895            })),
896            span: code.s1("1 ns").token_span(),
897        };
898        let expr = WithTokenSpan {
899            item: Expression::Unary(
900                WithToken::new(WithRef::new(Operator::Minus), code.s1("-").token()),
901                Box::new(time_expr),
902            ),
903            span: code.token_span(),
904        };
905
906        assert_eq!(code.with_stream(parse_expression), expr);
907    }
908
909    #[test]
910    fn parses_qualified_expression() {
911        let code = Code::new("foo'(1+2)");
912        let type_mark = code.s1("foo").type_mark();
913        let expr = code.s1("(1+2)").expr();
914
915        let qexpr = WithTokenSpan {
916            item: Expression::Qualified(Box::new(QualifiedExpression { type_mark, expr })),
917            span: code.token_span(),
918        };
919
920        assert_eq!(code.with_stream(parse_expression), qexpr);
921    }
922
923    #[test]
924    fn qualified_expression_precedence() {
925        let code = Code::new("mark0'(0) < mark1'(1)");
926        let expr = WithTokenSpan {
927            item: Expression::Binary(
928                WithToken::new(WithRef::new(Operator::LT), code.s1("<").token()),
929                Box::new(code.s1("mark0'(0)").expr()),
930                Box::new(code.s1("mark1'(1)").expr()),
931            ),
932            span: code.token_span(),
933        };
934
935        assert_eq!(code.expr(), expr);
936    }
937
938    #[test]
939    fn parses_qualified_aggregate() {
940        let code = Code::new("foo'(others => '1')");
941        let type_mark = code.s1("foo").type_mark();
942        let expr = code.s1("(others => '1')").expr();
943
944        let qexpr = WithTokenSpan {
945            item: Expression::Qualified(Box::new(QualifiedExpression { type_mark, expr })),
946            span: code.token_span(),
947        };
948
949        assert_eq!(code.with_stream(parse_expression), qexpr);
950    }
951
952    #[test]
953    fn parses_positional_aggregate() {
954        let code = Code::new("(1, 2)");
955        let one_expr = WithTokenSpan {
956            item: Expression::Literal(int(1)),
957            span: code.s1("1").token_span(),
958        };
959        let two_expr = WithTokenSpan {
960            item: Expression::Literal(int(2)),
961            span: code.s1("2").token_span(),
962        };
963
964        let assoc_list = vec![
965            WithTokenSpan::new(
966                ElementAssociation::Positional(one_expr),
967                code.s1("1").token_span(),
968            ),
969            WithTokenSpan::new(
970                ElementAssociation::Positional(two_expr),
971                code.s1("2").token_span(),
972            ),
973        ];
974        let expr = WithTokenSpan {
975            item: Expression::Aggregate(assoc_list),
976            span: code.token_span(),
977        };
978
979        assert_eq!(code.with_stream(parse_expression), expr);
980    }
981
982    #[test]
983    fn parses_named_aggregate() {
984        let code = Code::new("(1 => 2)");
985        let one_expr = WithTokenSpan {
986            item: Expression::Literal(int(1)),
987            span: code.s1("1").token_span(),
988        };
989        let two_expr = WithTokenSpan {
990            item: Expression::Literal(int(2)),
991            span: code.s1("2").token_span(),
992        };
993
994        let assoc_list = vec![WithTokenSpan::new(
995            ElementAssociation::Named(vec![one_expr.map_into(Choice::Expression)], two_expr),
996            code.s1("1 => 2").token_span(),
997        )];
998        let expr = WithTokenSpan {
999            item: Expression::Aggregate(assoc_list),
1000            span: code.token_span(),
1001        };
1002
1003        assert_eq!(code.with_stream(parse_expression), expr);
1004    }
1005
1006    #[test]
1007    fn parses_named_aggregate_many_choices() {
1008        let code = Code::new("(1 | 2 => 3)");
1009        let one_expr = WithTokenSpan {
1010            item: Expression::Literal(int(1)),
1011            span: code.s1("1").token_span(),
1012        };
1013
1014        let two_expr = WithTokenSpan {
1015            item: Expression::Literal(int(2)),
1016            span: code.s1("2").token_span(),
1017        };
1018
1019        let three_expr = WithTokenSpan {
1020            item: Expression::Literal(int(3)),
1021            span: code.s1("3").token_span(),
1022        };
1023
1024        let assoc_list = vec![WithTokenSpan::new(
1025            ElementAssociation::Named(
1026                vec![
1027                    one_expr.map_into(Choice::Expression),
1028                    two_expr.map_into(Choice::Expression),
1029                ],
1030                three_expr,
1031            ),
1032            code.s1("1 | 2 => 3").token_span(),
1033        )];
1034        let expr = WithTokenSpan {
1035            item: Expression::Aggregate(assoc_list),
1036            span: code.token_span(),
1037        };
1038
1039        assert_eq!(code.with_stream(parse_expression), expr);
1040    }
1041
1042    #[test]
1043    fn parses_others_aggregate() {
1044        let code = Code::new("(others => 1)");
1045        let one_expr = WithTokenSpan {
1046            item: Expression::Literal(int(1)),
1047            span: code.s1("1").token_span(),
1048        };
1049
1050        let assoc_list = vec![WithTokenSpan::new(
1051            ElementAssociation::Named(
1052                vec![WithTokenSpan::new(
1053                    Choice::Others,
1054                    code.s1("others").token_span(),
1055                )],
1056                one_expr,
1057            ),
1058            code.s1("others => 1").token_span(),
1059        )];
1060        let expr = WithTokenSpan {
1061            item: Expression::Aggregate(assoc_list),
1062            span: code.token_span(),
1063        };
1064
1065        assert_eq!(code.with_stream(parse_expression), expr);
1066    }
1067
1068    #[test]
1069    fn parses_aggregate_range() {
1070        for direction in [Direction::Descending, Direction::Ascending].iter() {
1071            let (pos, code) = {
1072                if *direction == Direction::Descending {
1073                    let code = Code::new("(1 downto 0 => 2)");
1074                    (code.s1("1 downto 0").token_span(), code)
1075                } else {
1076                    let code = Code::new("(1 to 0 => 2)");
1077                    (code.s1("1 to 0").token_span(), code)
1078                }
1079            };
1080
1081            let one_expr = WithTokenSpan {
1082                item: Expression::Literal(int(1)),
1083                span: code.s1("1").token_span(),
1084            };
1085
1086            let zero_expr = WithTokenSpan {
1087                item: Expression::Literal(int(0)),
1088                span: code.s1("0").token_span(),
1089            };
1090
1091            let two_expr = WithTokenSpan {
1092                item: Expression::Literal(int(2)),
1093                span: code.s1("2").token_span(),
1094            };
1095
1096            let range = DiscreteRange::Range(ast::Range::Range(RangeConstraint {
1097                direction: *direction,
1098                left_expr: Box::new(one_expr),
1099                right_expr: Box::new(zero_expr),
1100            }));
1101
1102            let assoc_list = vec![WithTokenSpan::new(
1103                ElementAssociation::Named(
1104                    vec![WithTokenSpan::new(Choice::DiscreteRange(range), pos)],
1105                    two_expr,
1106                ),
1107                if *direction == Direction::Descending {
1108                    code.s1("1 downto 0 => 2").token_span()
1109                } else {
1110                    code.s1("1 to 0 => 2").token_span()
1111                },
1112            )];
1113            let expr = WithTokenSpan {
1114                item: Expression::Aggregate(assoc_list),
1115                span: code.token_span(),
1116            };
1117
1118            assert_eq!(code.with_stream(parse_expression), expr);
1119        }
1120    }
1121
1122    #[test]
1123    fn parses_multiple_others_aggregate() {
1124        let code = Code::new("(others => 1, others => 2)");
1125        let one_expr = WithTokenSpan {
1126            item: Expression::Literal(int(1)),
1127            span: code.s1("1").token_span(),
1128        };
1129
1130        let two_expr = WithTokenSpan {
1131            item: Expression::Literal(int(2)),
1132            span: code.s1("2").token_span(),
1133        };
1134
1135        let assoc_list = vec![
1136            WithTokenSpan::new(
1137                ElementAssociation::Named(
1138                    vec![WithTokenSpan::new(
1139                        Choice::Others,
1140                        code.s("others", 1).token_span(),
1141                    )],
1142                    one_expr,
1143                ),
1144                code.s1("others => 1").token_span(),
1145            ),
1146            WithTokenSpan::new(
1147                ElementAssociation::Named(
1148                    vec![WithTokenSpan::new(
1149                        Choice::Others,
1150                        code.s("others", 2).token_span(),
1151                    )],
1152                    two_expr,
1153                ),
1154                code.s1("others => 2").token_span(),
1155            ),
1156        ];
1157        let expr = WithTokenSpan {
1158            item: Expression::Aggregate(assoc_list),
1159            span: code.token_span(),
1160        };
1161
1162        assert_eq!(code.with_stream(parse_expression), expr);
1163    }
1164
1165    #[test]
1166    fn parses_mixed_aggregate() {
1167        let code = Code::new("(1 => 2, 3)");
1168        let one_expr = WithTokenSpan {
1169            item: Expression::Literal(int(1)),
1170            span: code.s1("1").token_span(),
1171        };
1172        let two_expr = WithTokenSpan {
1173            item: Expression::Literal(int(2)),
1174            span: code.s1("2").token_span(),
1175        };
1176        let three_expr = WithTokenSpan {
1177            item: Expression::Literal(int(3)),
1178            span: code.s1("3").token_span(),
1179        };
1180
1181        let assoc_list = vec![
1182            WithTokenSpan::new(
1183                ElementAssociation::Named(vec![one_expr.map_into(Choice::Expression)], two_expr),
1184                code.s1("1 => 2").token_span(),
1185            ),
1186            WithTokenSpan::new(
1187                ElementAssociation::Positional(three_expr),
1188                code.s1("3").token_span(),
1189            ),
1190        ];
1191        let expr = WithTokenSpan {
1192            item: Expression::Aggregate(assoc_list),
1193            span: code.token_span(),
1194        };
1195
1196        assert_eq!(code.with_stream(parse_expression), expr);
1197    }
1198
1199    #[test]
1200    fn parses_huge_aggregate() {
1201        // Check that there is no stack overflow
1202        let mut code = "(".to_string();
1203        for _ in 0..(1 << 13) {
1204            code.push_str("11123, ");
1205        }
1206        code.push_str("11123)");
1207        let code = Code::new(&code);
1208        assert_eq!(code.with_stream(parse_expression).span, code.token_span());
1209    }
1210
1211    #[test]
1212    fn parses_nested_expression_par_second() {
1213        let code = Code::new("1 + (2 + 3)");
1214
1215        let one = WithTokenSpan {
1216            item: Expression::Literal(int(1)),
1217            span: code.s1("1").token_span(),
1218        };
1219
1220        let two = WithTokenSpan {
1221            item: Expression::Literal(int(2)),
1222            span: code.s1("2").token_span(),
1223        };
1224
1225        let three = WithTokenSpan {
1226            item: Expression::Literal(int(3)),
1227            span: code.s1("3").token_span(),
1228        };
1229
1230        let expr_add0 = WithTokenSpan {
1231            item: Expression::Binary(
1232                WithToken::new(WithRef::new(Operator::Plus), code.s("+", 2).token()),
1233                Box::new(two),
1234                Box::new(three),
1235            ),
1236            span: code.s1("2 + 3").token_span(),
1237        };
1238
1239        let expr_add0_paren = WithTokenSpan::new(
1240            Expression::Parenthesized(Box::new(expr_add0)),
1241            code.s1("(2 + 3)").token_span(),
1242        );
1243
1244        let expr_add1 = WithTokenSpan {
1245            item: Expression::Binary(
1246                WithToken::new(WithRef::new(Operator::Plus), code.s("+", 1).token()),
1247                Box::new(one),
1248                Box::new(expr_add0_paren),
1249            ),
1250            span: code.token_span(),
1251        };
1252
1253        assert_eq!(code.with_stream(parse_expression), expr_add1);
1254    }
1255
1256    #[test]
1257    fn parses_nested_expression_par_first() {
1258        let code = Code::new("(1 + 2) + 3");
1259
1260        let one = WithTokenSpan {
1261            item: Expression::Literal(int(1)),
1262            span: code.s1("1").token_span(),
1263        };
1264
1265        let two = WithTokenSpan {
1266            item: Expression::Literal(int(2)),
1267            span: code.s1("2").token_span(),
1268        };
1269
1270        let three = WithTokenSpan {
1271            item: Expression::Literal(int(3)),
1272            span: code.s1("3").token_span(),
1273        };
1274
1275        let expr_add0 = WithTokenSpan {
1276            item: Expression::Binary(
1277                WithToken::new(WithRef::new(Operator::Plus), code.s("+", 1).token()),
1278                Box::new(one),
1279                Box::new(two),
1280            ),
1281            span: code.s1("1 + 2").token_span(),
1282        };
1283
1284        let expr_add0_paren = WithTokenSpan::new(
1285            Expression::Parenthesized(Box::new(expr_add0)),
1286            code.s1("(1 + 2)").token_span(),
1287        );
1288
1289        let expr_add1 = WithTokenSpan {
1290            item: Expression::Binary(
1291                WithToken::new(WithRef::new(Operator::Plus), code.s("+", 2).token()),
1292                Box::new(expr_add0_paren),
1293                Box::new(three),
1294            ),
1295            span: code.token_span(),
1296        };
1297
1298        assert_eq!(code.with_stream(parse_expression), expr_add1);
1299    }
1300
1301    /// Format expression as a string to simplify testing of precedence.
1302    fn fmt(ctx: &dyn TokenAccess, expr: &WithTokenSpan<Expression>) -> String {
1303        match expr.item {
1304            Expression::Binary(ref op, ref lhs, ref rhs) => {
1305                format!("({} {:?} {})", fmt(ctx, lhs), op.item.item, fmt(ctx, rhs))
1306            }
1307            Expression::Unary(ref op, ref rhs) => format!("({:?} {})", op.item.item, fmt(ctx, rhs)),
1308            Expression::Literal(ref lit) => match lit {
1309                Literal::Null => "null".to_string(),
1310                // @TODO quote and escape
1311                Literal::String(val) => val.to_string(),
1312                Literal::AbstractLiteral(val) => match val {
1313                    AbstractLiteral::Integer(val) => format!("Integer({val})"),
1314                    AbstractLiteral::Real(val) => format!("Real({val})"),
1315                },
1316                Literal::Character(val) => format!("'{}'", Latin1String::new(&[*val])),
1317                Literal::Physical(ref physical) => match physical.value {
1318                    AbstractLiteral::Integer(val) => {
1319                        format!("Physical(Integer({}), {})", val, physical.unit.item.name())
1320                    }
1321                    AbstractLiteral::Real(val) => {
1322                        format!("Physical(Real({}), {})", val, physical.unit.item.name())
1323                    }
1324                },
1325                _ => {
1326                    println!("{}", expr.pos(ctx).code_context());
1327                    panic!("Cannot format {lit:?}");
1328                }
1329            },
1330            Expression::Parenthesized(ref expr) => {
1331                format!("({})", fmt(ctx, expr))
1332            }
1333            _ => {
1334                println!("{}", expr.pos(ctx).code_context());
1335                panic!("Cannot format {expr:?}");
1336            }
1337        }
1338    }
1339
1340    fn assert_expression_is(code: &str, expr_str: &str) {
1341        let code = Code::new(code);
1342        let ctx = code.tokenize();
1343        assert_eq!(fmt(&ctx, &code.with_stream(parse_expression)), expr_str);
1344    }
1345
1346    #[test]
1347    fn parses_function_errors() {
1348        let code = Code::new("fun(,)");
1349        assert_eq!(
1350            code.with_partial_stream(parse_expression),
1351            Err(Diagnostic::syntax_error(
1352                code.s1(",").pos(),
1353                "Expected {expression}"
1354            ))
1355        );
1356
1357        let code = Code::new("fun(arg0,)");
1358        assert_eq!(
1359            code.with_partial_stream(parse_expression),
1360            Err(Diagnostic::syntax_error(
1361                code.s1(")").pos(),
1362                "Expected {expression}"
1363            ))
1364        );
1365        let code = Code::new("fun(arg0,,)");
1366        assert_eq!(
1367            code.with_partial_stream(parse_expression),
1368            Err(Diagnostic::syntax_error(
1369                code.s(",", 2).pos(),
1370                "Expected {expression}"
1371            ))
1372        );
1373    }
1374
1375    #[test]
1376    fn parses_nested_expression_precedence() {
1377        assert_expression_is("1 + 1 ns", "(Integer(1) Plus Physical(Integer(1), ns))");
1378
1379        assert_expression_is(
1380            "1 * 1 ns * 2",
1381            "((Integer(1) Times Physical(Integer(1), ns)) Times Integer(2))",
1382        );
1383
1384        assert_expression_is("1+2+3", "((Integer(1) Plus Integer(2)) Plus Integer(3))");
1385
1386        assert_expression_is("1-2-3", "((Integer(1) Minus Integer(2)) Minus Integer(3))");
1387
1388        assert_expression_is("1+2*3", "(Integer(1) Plus (Integer(2) Times Integer(3)))");
1389
1390        // The extra parenthesis signify the user-supplied parenthesis
1391        assert_expression_is(
1392            "(1+2)*3",
1393            "(((Integer(1) Plus Integer(2))) Times Integer(3))",
1394        );
1395
1396        // Multiplication has precedence over negation.
1397        assert_expression_is("-1 * 2", "(Minus (Integer(1) Times Integer(2)))");
1398
1399        assert_expression_is("not 1 + 2", "((Not Integer(1)) Plus Integer(2))");
1400
1401        assert_expression_is("abs not 1 + 2", "((Abs (Not Integer(1))) Plus Integer(2))");
1402
1403        assert_expression_is("not - 1", "(Not (Minus Integer(1)))");
1404
1405        assert_expression_is("not + 1", "(Not (Plus Integer(1)))");
1406
1407        assert_expression_is(
1408            "not + ?? 1 ** ?? 2",
1409            "(Not (Plus (QueQue (Integer(1) Pow (QueQue Integer(2))))))",
1410        );
1411
1412        assert_expression_is(
1413            "abs 1 sll 2 + 3 and -1",
1414            "(((Abs Integer(1)) SLL (Integer(2) Plus Integer(3))) And (Minus Integer(1)))",
1415        );
1416
1417        assert_expression_is(
1418            "1 + 2 and 3 + 4",
1419            "((Integer(1) Plus Integer(2)) And (Integer(3) Plus Integer(4)))",
1420        );
1421
1422        assert_expression_is("and 1 + 2", "((And Integer(1)) Plus Integer(2))");
1423    }
1424}