lunir/ast/
expression.rs

1// MIT License
2
3// Copyright (c) 2023 lunir-project
4
5// Permission is hereby granted, free of charge, to any person obtaining a copy
6// of this software and associated documentation files (the "Software"), to deal
7// in the Software without restriction, including without limitation the rights
8// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9// copies of the Software, and to permit persons to whom the Software is
10// furnished to do so, subject to the following conditions:
11
12// The above copyright notice and this permission notice shall be included in all
13// copies or substantial portions of the Software.
14
15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21// SOFTWARE.
22
23use crate::ast::statement::*;
24use crate::il::UnaryOpKind;
25
26use itertools::Itertools;
27use std::rc::Rc;
28
29pub trait IdentifierString {
30    fn can_identify(&self) -> bool;
31    fn sanitize_identifier(&self) -> String;
32    fn sanitize_special(&self) -> String;
33}
34
35impl IdentifierString for String {
36    fn can_identify(&self) -> bool {
37        !(self.is_empty()
38            || self.chars().next().unwrap().is_ascii_digit()
39            || self.chars().any(|c| !c.is_alphanumeric() && c != '_'))
40    }
41
42    fn sanitize_identifier(&self) -> String {
43        let mut result = self
44            .chars()
45            .filter_map(|c| match c {
46                '-' | ' ' | '\t' | '\n' => Some('_'),
47                _ if c.is_alphanumeric() || c == '_' => Some(c),
48                _ => None,
49            })
50            .collect::<String>();
51
52        result = if !result.is_empty() {
53            result
54        } else {
55            format!("_{result}")
56        };
57
58        let result = result
59            .chars()
60            .dedup_by(|&a, &b| a == '_' && a == b)
61            .collect::<String>();
62
63        result
64    }
65
66    fn sanitize_special(&self) -> String {
67        self.chars()
68            .map(|c| match c {
69                '\n' => r#"\n"#.to_string(),
70                '\r' => r#"\r"#.to_string(),
71                '\t' => r#"\t"#.to_string(),
72                '\"' => r#"\""#.to_string(),
73                '\\' => r#"\\"#.to_string(),
74                c if (' '..='~').contains(&c) => c.to_string(),
75                _ => format!(r#"\{}"#, c as u32),
76            })
77            .collect()
78    }
79}
80
81#[derive(Debug, Clone, PartialEq)]
82pub struct Nil;
83
84#[derive(Debug, Clone, PartialEq)]
85pub struct Number(pub f64);
86
87#[derive(Debug, Clone, PartialEq)]
88pub struct Boolean(pub bool);
89
90#[derive(Debug, Clone, PartialEq)]
91pub struct Str(pub String);
92
93#[derive(Debug, Clone, PartialEq)]
94pub struct GlobalSymbol(pub String);
95
96#[derive(Debug, Clone, PartialEq)]
97pub struct Identifier(pub String);
98
99#[derive(Debug, Clone, PartialEq)]
100pub enum BinaryExpressionKind {
101    Add,
102    Sub,
103    Mul,
104    Div,
105    Mod,
106    Pow,
107    Concat,
108
109    AddAssign,
110    SubAssign,
111    MulAssign,
112    DivAssign,
113    ModAssign,
114    PowAssign,
115    ConcatAssign,
116}
117
118#[derive(Debug, Clone, PartialEq)]
119pub struct BinaryExpression {
120    pub kind: BinaryExpressionKind,
121
122    pub left: Expression,
123    pub right: Expression,
124}
125
126impl BinaryExpressionKind {
127    pub fn to_compound(&self) -> Self {
128        match self {
129            Self::Add => Self::AddAssign,
130            Self::Sub => Self::SubAssign,
131            Self::Mul => Self::MulAssign,
132            Self::Div => Self::DivAssign,
133            Self::Mod => Self::ModAssign,
134            Self::Pow => Self::PowAssign,
135            Self::Concat => Self::ConcatAssign,
136            other => other.clone(),
137        }
138    }
139}
140
141impl std::fmt::Display for BinaryExpressionKind {
142    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
143        write!(
144            f,
145            "{}",
146            match self {
147                Self::Add => "+",
148                Self::Sub => "-",
149                Self::Mul => "*",
150                Self::Div => "/",
151                Self::Mod => "%",
152                Self::Pow => "^",
153                Self::Concat => "..",
154
155                Self::AddAssign => "+=",
156                Self::SubAssign => "-=",
157                Self::MulAssign => "*=",
158                Self::DivAssign => "/=",
159                Self::ModAssign => "%=",
160                Self::PowAssign => "^=",
161                Self::ConcatAssign => "..=",
162            }
163        )
164    }
165}
166
167#[derive(Debug, Clone, PartialEq)]
168pub struct UnaryExpression {
169    pub kind: UnaryOpKind,
170    pub value: Expression,
171}
172
173impl std::fmt::Display for UnaryOpKind {
174    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
175        write!(
176            f,
177            "{}",
178            match self {
179                Self::Len => "#",
180                Self::Neg => "-",
181
182                // space necessary
183                Self::Not => "not ",
184            }
185        )
186    }
187}
188
189#[derive(Debug, Clone, PartialEq)]
190pub enum TableExpression {
191    HashMap(Vec<(Expression, Expression)>),
192    Array(Vec<Expression>),
193}
194
195#[derive(Debug, Clone, PartialEq)]
196pub struct ShadowExpression {
197    pub is_shadowed: bool,
198    pub value: Expression,
199}
200
201impl ShadowExpression {
202    pub fn new(value: Expression) -> Self {
203        Self {
204            value,
205            is_shadowed: false,
206        }
207    }
208
209    pub fn shadow(mut self, value: bool) -> Self {
210        self.is_shadowed = value;
211
212        self
213    }
214}
215
216#[derive(Debug, Clone, PartialEq)]
217pub struct IndexOp {
218    pub key: Expression,
219    pub table: Expression,
220}
221
222#[derive(Debug, Clone, PartialEq)]
223pub struct CallExpression {
224    pub arguments: Vec<Expression>,
225    pub function: Expression,
226
227    pub is_self: bool,
228}
229
230#[derive(Debug, Clone, PartialEq)]
231pub struct FunctionExpression {
232    pub body: Box<StatBlock>,
233    pub has_vararg: bool,
234
235    pub parameters: Vec<Expression>,
236    pub self_arg: Option<Expression>,
237}
238
239#[derive(Debug, Clone, PartialEq)]
240pub enum Expression {
241    Boolean(Rc<Boolean>),
242    BinaryOp(Rc<BinaryExpression>),
243    UnaryOp(Rc<UnaryExpression>),
244    String(Rc<Str>),
245    Number(Rc<Number>),
246    Nil(Rc<Nil>),
247    IndexOp(Rc<IndexOp>),
248    Call(Rc<CallExpression>),
249    Function(Rc<FunctionExpression>),
250    GlobalSymbol(Rc<GlobalSymbol>),
251    Identifier(Rc<Identifier>),
252    Table(Rc<TableExpression>),
253    Shadow(Rc<ShadowExpression>),
254}
255
256impl Expression {
257    pub fn to_statement(self) -> Statement {
258        Statement::StatExpr(Box::new(StatExpr { value: self }))
259    }
260}
261
262impl Into<Statement> for Expression {
263    fn into(self) -> Statement {
264        self.to_statement()
265    }
266}