1use 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 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}