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
//! This module contains the AST representation for expressions in the SAP language.
//!
//! An expression is a combination of one or more values, variables, operators, and
//! functions that evaluates to a single value. The AST nodes in this module represent the
//! different types of expressions that are supported in the SAP language.
//!
//! Expressions are used in the language to perform calculations, make decisions, and
//! manipulate data. They can be used as standalone statements, or as part of larger
//! expressions or statements.
//!
//! Note: The `Box` type is used to indicate that the data enclosed is stored on the heap,
//! rather than on the stack. This is necessary because otherwise the compiler needs to
//! know the size of the expression at compile time, which is not possible for recursive
//! data structures like the AST.
use lexer::token::TokenKind;
use serde::Serialize;
use shared::span::{GetSpan, Span};

use crate::literal::Literal;
use crate::StatementList;

/// Represents a single expression in the SAP language.
#[derive(Debug, Serialize, PartialEq, Clone)]
// Tell serde not to include this enum in the JSON output, since it only adds clutter and doesn't
// provide any useful information.
#[serde(untagged)]
pub enum Expression {
    Identifier(Identifier),
    Unary(Unary),
    Binary(Binary),
    Selection(Selection),
    FunctionCall(FunctionCall),
    Array(Array),
    Index(Index),
    Literal(Literal),
}

impl GetSpan for Expression {
    fn span(&self) -> &Span {
        match self {
            Expression::Identifier(identifier) => &identifier.span,
            Expression::Unary(unary) => &unary.span,
            Expression::Binary(binary) => &binary.span,
            Expression::Selection(selection) => &selection.span,
            Expression::FunctionCall(function_call) => &function_call.span,
            Expression::Array(array) => &array.span,
            Expression::Index(index) => &index.span,
            Expression::Literal(literal) => literal.span(),
        }
    }
}

/// Represents an identifier in the SAP language.
/// For example: `x`
#[derive(Debug, Serialize, PartialEq, Clone)]
#[serde(tag = "type")]
pub struct Identifier {
    pub name: String,
    pub span: Span,
}

/// Represents a unary expression in the SAP language.
/// For example: `-x`
#[derive(Debug, Serialize, PartialEq, Clone)]
#[serde(tag = "type")]
pub struct Unary {
    pub operator: TokenKind,
    pub operand: Box<Expression>,
    pub span: Span,
}

/// Represents a binary expression in the SAP language.
/// For example: `x + 5`
#[derive(Debug, Serialize, PartialEq, Clone)]
#[serde(tag = "type")]
pub struct Binary {
    pub operator: TokenKind,
    pub left: Box<Expression>,
    pub right: Box<Expression>,
    pub span: Span,
}

/// Represents a selection expression in the SAP language.
/// For example:
/// ```sap
/// if x > 5 then
///     display "x is greater than 5"
/// otherwise
///     display "x is less than or equal to 5"
/// end
/// ```
#[derive(Debug, Serialize, PartialEq, Clone)]
#[serde(tag = "type")]
pub struct Selection {
    pub condition: Box<Expression>,
    pub conditional: StatementList,
    pub else_conditional: Option<StatementList>,
    pub span: Span,
}

/// Represents a function call expression in the SAP language.
/// For example: `add(5, 10)`
#[derive(Debug, Serialize, PartialEq, Clone)]
#[serde(tag = "type")]
pub struct FunctionCall {
    /// The function being called. This can be an identifier or an expression which
    /// evaluates to a function.
    pub callee: Box<Expression>,
    pub arguments: Vec<Expression>,
    pub span: Span,
}

/// Represents an array expression in the SAP language.
/// For example: `[1, 2, 3, 4, 5]`
#[derive(Debug, Serialize, PartialEq, Clone)]
#[serde(tag = "type")]
pub struct Array {
    pub elements: Vec<Expression>,
    pub span: Span,
}

/// Represents an index expression in the SAP language.
/// For example: `arr[0]`
#[derive(Debug, Serialize, PartialEq, Clone)]
#[serde(tag = "type")]
pub struct Index {
    pub object: Box<Expression>,
    pub index: Box<Expression>,
    pub span: Span,
}