meow_meow_script/
transform.rs1use crate::ast::{
3 BinOpKind, BlockStatement, CallExpression, ElseBranch, Expression, Ident, IfStatement,
4 Statement,
5};
6
7pub struct EmitLiftTransform;
21
22impl EmitLiftTransform {
23 pub fn apply(stmts: &mut Vec<Statement>) {
24 for stmt in stmts.iter_mut() {
25 lift_stmt(stmt);
26 }
27 }
28}
29
30fn lift_stmt(stmt: &mut Statement) {
31 match stmt {
32 Statement::Expression(expr) => {
33 if let Expression::Component(_) = expr {
34 let inner = std::mem::replace(expr, Expression::Null);
36 *expr = Expression::Call(CallExpression {
37 callee: Box::new(Expression::Identifier(Ident("emit".into()))),
38 args: vec![inner],
39 });
40 } else if let Expression::Function { body, .. } = expr {
41 lift_block(body);
42 }
43 }
44 Statement::Assignment(a) => {
45 if let Expression::Function { body, .. } = &mut a.value {
46 lift_block(body);
47 }
48 }
49 Statement::Block(block) => lift_block(block),
50 Statement::If(if_stmt) => lift_if(if_stmt),
51 Statement::Return(_) => {}
52 Statement::ForIn { body, .. } => lift_block(body),
53 Statement::While { body, .. } => lift_block(body),
54 Statement::Break | Statement::Continue => {}
55 Statement::Import { .. } => {}
56 Statement::Reassign { .. } => {}
57 }
58}
59
60fn lift_block(block: &mut BlockStatement) {
61 for stmt in block.statements.iter_mut() {
62 lift_stmt(stmt);
63 }
64}
65
66fn lift_if(if_stmt: &mut IfStatement) {
67 lift_block(&mut if_stmt.then_branch);
68 if let Some(else_branch) = &mut if_stmt.else_branch {
69 lift_else_branch(else_branch);
70 }
71}
72
73fn lift_else_branch(else_branch: &mut ElseBranch) {
74 match else_branch {
75 ElseBranch::Block(block) => lift_block(block),
76 ElseBranch::If(if_stmt) => lift_if(if_stmt),
77 }
78}
79
80pub struct QueryDesugarTransform;
118
119impl QueryDesugarTransform {
120 pub fn apply(stmts: &mut Vec<Statement>) {
121 for stmt in stmts.iter_mut() {
122 qd_stmt(stmt);
123 }
124 }
125}
126
127fn selector_is_single(sel: &str) -> bool {
128 sel.starts_with('#') && !sel.contains(' ') && !sel.contains('>')
129}
130
131fn qd_stmt(stmt: &mut Statement) {
132 match stmt {
133 Statement::Expression(expr) => qd_expr(expr),
134 Statement::Assignment(a) => qd_expr(&mut a.value),
135 Statement::Reassign { value, .. } => qd_expr(value),
136 Statement::Return(ret) => {
137 if let Some(expr) = &mut ret.value {
138 qd_expr(expr);
139 }
140 }
141 Statement::If(if_stmt) => qd_if(if_stmt),
142 Statement::Block(block) => qd_block(block),
143 Statement::ForIn { iterable, body, .. } => {
144 qd_expr(iterable);
145 qd_block(body);
146 }
147 Statement::While { condition, body } => {
148 qd_expr(condition);
149 qd_block(body);
150 }
151 Statement::Break | Statement::Continue | Statement::Import { .. } => {}
152 }
153}
154
155fn qd_block(block: &mut BlockStatement) {
156 for stmt in block.statements.iter_mut() {
157 qd_stmt(stmt);
158 }
159}
160
161fn qd_if(if_stmt: &mut IfStatement) {
162 qd_expr(&mut if_stmt.condition);
163 qd_block(&mut if_stmt.then_branch);
164 if let Some(else_branch) = &mut if_stmt.else_branch {
165 qd_else_branch(else_branch);
166 }
167}
168
169fn qd_else_branch(else_branch: &mut ElseBranch) {
170 match else_branch {
171 ElseBranch::Block(block) => qd_block(block),
172 ElseBranch::If(if_stmt) => qd_if(if_stmt),
173 }
174}
175
176fn qd_expr(expr: &mut Expression) {
177 match expr {
179 Expression::BinaryOp { lhs, rhs, .. } => {
180 qd_expr(lhs);
181 qd_expr(rhs);
182 }
183 Expression::UnaryOp { operand, .. } => qd_expr(operand),
184 Expression::Index { base, index } => {
185 qd_expr(base);
186 qd_expr(index);
187 }
188 Expression::Call(call) => {
189 for arg in call.args.iter_mut() {
190 qd_expr(arg);
191 }
192 }
193 Expression::Array(items) => {
194 for item in items.iter_mut() {
195 qd_expr(item);
196 }
197 }
198 Expression::Table(fields) => {
199 for field in fields.iter_mut() {
200 qd_expr(&mut field.value);
201 }
202 }
203 Expression::Function { body, .. } => qd_block(body),
204 _ => {}
205 }
206
207 if let Expression::BinaryOp {
209 op: BinOpKind::Query,
210 lhs,
211 rhs,
212 } = expr
213 {
214 let callee = if let Expression::String(sel) = lhs.as_ref() {
215 if selector_is_single(sel) {
216 "query"
217 } else {
218 "query_all"
219 }
220 } else {
221 "query_all" };
223 let sel_expr = std::mem::replace(lhs.as_mut(), Expression::Null);
224 let handler_or_call = std::mem::replace(rhs.as_mut(), Expression::Null);
225 let handler = match handler_or_call {
231 Expression::Call(CallExpression { callee, args })
232 if matches!(callee.as_ref(), Expression::Identifier(_)) =>
233 {
234 let method = match *callee {
235 Expression::Identifier(id) => id,
236 _ => unreachable!(),
237 };
238 wrap_method_shorthand(method, args)
239 }
240 other => other,
241 };
242 *expr = Expression::Call(CallExpression {
243 callee: Box::new(Expression::Identifier(Ident(callee.into()))),
244 args: vec![sel_expr, handler],
245 });
246 }
247}
248
249fn wrap_method_shorthand(method: Ident, args: Vec<Expression>) -> Expression {
251 let receiver = Ident("__qr".into());
252 let receiver_ref = Expression::Identifier(receiver.clone());
253 let dot = Expression::BinaryOp {
254 op: BinOpKind::Dot,
255 lhs: Box::new(receiver_ref),
256 rhs: Box::new(Expression::Identifier(method)),
257 };
258 let call = Expression::Call(CallExpression {
259 callee: Box::new(dot),
260 args,
261 });
262 Expression::Function {
263 params: vec![receiver],
264 body: BlockStatement {
265 statements: vec![Statement::Expression(call)],
266 },
267 }
268}