rukalang/meta/
quote_expand.rs

1use super::meta_types_builder::expand_builder_expr;
2use super::quote_match::{kind_name, match_quote_pattern_expr, match_quote_pattern_type};
3use super::runtime_eval::eval_meta_expr;
4use super::*;
5
6pub(super) fn expand_builder_call_arg(
7    program: &Program,
8    arg: &CallArg,
9    env: &mut BTreeMap<String, MetaValue>,
10    function_table: &BTreeMap<String, &MetaFunctionDecl>,
11    runtime_scope: &RuntimeScope,
12    builder_env_cursor: Option<&mut BuilderEnvCursor>,
13) -> Result<CallArg, MetaEvalError> {
14    match arg {
15        CallArg::Expr(expr) => Ok(CallArg::Expr(expand_builder_expr(
16            program,
17            expr,
18            env,
19            function_table,
20            runtime_scope,
21            builder_env_cursor,
22        )?)),
23        CallArg::Spread(expr) => Ok(CallArg::Spread(expand_builder_expr(
24            program,
25            expr,
26            env,
27            function_table,
28            runtime_scope,
29            builder_env_cursor,
30        )?)),
31        CallArg::Type(ty) => Ok(CallArg::Type(ty.clone())),
32    }
33}
34
35pub(super) fn expand_quoted_expr(
36    program: &Program,
37    expr: &Expr,
38    env: &mut BTreeMap<String, MetaValue>,
39    function_table: &BTreeMap<String, &MetaFunctionDecl>,
40    runtime_scope: &RuntimeScope,
41    mut builder_env_cursor: Option<&mut BuilderEnvCursor>,
42) -> Result<Expr, MetaEvalError> {
43    match expr {
44        Expr::Ident { name, span } => Ok(Expr::Ident {
45            name: name.clone(),
46            span: *span,
47        }),
48        Expr::Int(value) => Ok(Expr::Int(*value)),
49        Expr::Number(value) => Ok(Expr::Number(value.clone())),
50        Expr::String(value) => Ok(Expr::String(value.clone())),
51        Expr::Bool(value) => Ok(Expr::Bool(*value)),
52        Expr::Array { items, span } => {
53            let mut expanded = Vec::with_capacity(items.len());
54            for item in items {
55                expanded.push(expand_quoted_expr(
56                    program,
57                    item,
58                    env,
59                    function_table,
60                    runtime_scope,
61                    builder_env_cursor.as_deref_mut(),
62                )?);
63            }
64            Ok(Expr::Array {
65                items: expanded,
66                span: *span,
67            })
68        }
69        Expr::Tuple { items, span } => {
70            let mut expanded = Vec::with_capacity(items.len());
71            for item in items {
72                expanded.push(expand_quoted_expr(
73                    program,
74                    item,
75                    env,
76                    function_table,
77                    runtime_scope,
78                    builder_env_cursor.as_deref_mut(),
79                )?);
80            }
81            Ok(Expr::Tuple {
82                items: expanded,
83                span: *span,
84            })
85        }
86        Expr::StructLit { name, fields, span } => {
87            let mut expanded_fields = Vec::with_capacity(fields.len());
88            for field in fields {
89                expanded_fields.push(crate::syntax::ast::NamedExprField {
90                    name: field.name.clone(),
91                    value: expand_quoted_expr(
92                        program,
93                        &field.value,
94                        env,
95                        function_table,
96                        runtime_scope,
97                        builder_env_cursor.as_deref_mut(),
98                    )?,
99                });
100            }
101            Ok(Expr::StructLit {
102                name: name.clone(),
103                fields: expanded_fields,
104                span: *span,
105            })
106        }
107        Expr::Call { callee, args, span } => {
108            let callee = Box::new(expand_quoted_expr(
109                program,
110                callee,
111                env,
112                function_table,
113                runtime_scope,
114                builder_env_cursor.as_deref_mut(),
115            )?);
116            let mut expanded_args = Vec::with_capacity(args.len());
117            for arg in args {
118                expanded_args.push(expand_quoted_call_arg(
119                    program,
120                    arg,
121                    env,
122                    function_table,
123                    runtime_scope,
124                    builder_env_cursor.as_deref_mut(),
125                )?);
126            }
127            Ok(Expr::Call {
128                callee,
129                args: expanded_args,
130                span: *span,
131            })
132        }
133        Expr::IntrinsicCall { name, args, span } => {
134            let mut expanded_args = Vec::with_capacity(args.len());
135            for arg in args {
136                expanded_args.push(expand_quoted_call_arg(
137                    program,
138                    arg,
139                    env,
140                    function_table,
141                    runtime_scope,
142                    builder_env_cursor.as_deref_mut(),
143                )?);
144            }
145            Ok(Expr::IntrinsicCall {
146                name: name.clone(),
147                args: expanded_args,
148                span: *span,
149            })
150        }
151        Expr::Field { base, field } => {
152            let base = Box::new(expand_quoted_expr(
153                program,
154                base,
155                env,
156                function_table,
157                runtime_scope,
158                builder_env_cursor.as_deref_mut(),
159            )?);
160            Ok(Expr::Field {
161                base,
162                field: field.clone(),
163            })
164        }
165        Expr::Index { base, index } => {
166            let base = Box::new(expand_quoted_expr(
167                program,
168                base,
169                env,
170                function_table,
171                runtime_scope,
172                builder_env_cursor.as_deref_mut(),
173            )?);
174            let index = Box::new(expand_quoted_expr(
175                program,
176                index,
177                env,
178                function_table,
179                runtime_scope,
180                builder_env_cursor.as_deref_mut(),
181            )?);
182            Ok(Expr::Index { base, index })
183        }
184        Expr::SliceRange { base, start, end } => {
185            let base = Box::new(expand_quoted_expr(
186                program,
187                base,
188                env,
189                function_table,
190                runtime_scope,
191                builder_env_cursor.as_deref_mut(),
192            )?);
193            let start = start
194                .as_ref()
195                .map(|expr| {
196                    expand_quoted_expr(
197                        program,
198                        expr,
199                        env,
200                        function_table,
201                        runtime_scope,
202                        builder_env_cursor.as_deref_mut(),
203                    )
204                })
205                .transpose()?
206                .map(Box::new);
207            let end = end
208                .as_ref()
209                .map(|expr| {
210                    expand_quoted_expr(
211                        program,
212                        expr,
213                        env,
214                        function_table,
215                        runtime_scope,
216                        builder_env_cursor.as_deref_mut(),
217                    )
218                })
219                .transpose()?
220                .map(Box::new);
221            Ok(Expr::SliceRange { base, start, end })
222        }
223        Expr::Prefix { op, value } => {
224            let value = Box::new(expand_quoted_expr(
225                program,
226                value,
227                env,
228                function_table,
229                runtime_scope,
230                builder_env_cursor.as_deref_mut(),
231            )?);
232            Ok(Expr::Prefix { op: *op, value })
233        }
234        Expr::Binary { op, lhs, rhs } => {
235            let lhs = Box::new(expand_quoted_expr(
236                program,
237                lhs,
238                env,
239                function_table,
240                runtime_scope,
241                builder_env_cursor.as_deref_mut(),
242            )?);
243            let rhs = Box::new(expand_quoted_expr(
244                program,
245                rhs,
246                env,
247                function_table,
248                runtime_scope,
249                builder_env_cursor.as_deref_mut(),
250            )?);
251            Ok(Expr::Binary { op: *op, lhs, rhs })
252        }
253        Expr::Relational { op, lhs, rhs } => {
254            let lhs = Box::new(expand_quoted_expr(
255                program,
256                lhs,
257                env,
258                function_table,
259                runtime_scope,
260                builder_env_cursor.as_deref_mut(),
261            )?);
262            let rhs = Box::new(expand_quoted_expr(
263                program,
264                rhs,
265                env,
266                function_table,
267                runtime_scope,
268                builder_env_cursor.as_deref_mut(),
269            )?);
270            Ok(Expr::Relational { op: *op, lhs, rhs })
271        }
272        Expr::Block(block) => Ok(Expr::Block(expand_quoted_block(
273            program,
274            block,
275            env,
276            function_table,
277            runtime_scope,
278            builder_env_cursor.as_deref_mut(),
279        )?)),
280        Expr::Splice(meta_expr) => {
281            let splice_value = eval_meta_expr(
282                program,
283                meta_expr,
284                env,
285                function_table,
286                runtime_scope,
287                builder_env_cursor,
288            )?;
289            splice_value_to_expr(splice_value)
290        }
291    }
292}
293
294pub(super) fn splice_value_to_expr(value: MetaValue) -> Result<Expr, MetaEvalError> {
295    match value {
296        MetaValue::Expr { expr, .. } => Ok(expr),
297        MetaValue::Int(value) => Ok(Expr::Int(value)),
298        MetaValue::Bool(value) => Ok(Expr::Bool(value)),
299        MetaValue::String(value) => Ok(Expr::String(value)),
300        other => Err(MetaEvalError::SpliceExpectedCode {
301            found: kind_name(&other),
302        }),
303    }
304}
305
306pub(super) fn runtime_splice_value_to_expr(value: MetaValue) -> Result<Expr, MetaEvalError> {
307    match value {
308        MetaValue::Expr { expr, .. } => Ok(expr),
309        other => Err(MetaEvalError::SpliceExpectedCode {
310            found: kind_name(&other),
311        }),
312    }
313}
314
315pub(super) fn builder_value_to_expr(value: MetaValue) -> Result<Expr, MetaEvalError> {
316    match value {
317        MetaValue::Expr { expr, .. } => Ok(expr),
318        MetaValue::Int(value) => Ok(Expr::Int(value)),
319        MetaValue::Bool(value) => Ok(Expr::Bool(value)),
320        MetaValue::String(value) => Ok(Expr::String(value)),
321        other => Err(MetaEvalError::SpliceExpectedCode {
322            found: kind_name(&other),
323        }),
324    }
325}
326
327pub(super) fn promote_splice_value(value: MetaValue) -> Result<MetaValue, MetaEvalError> {
328    match value {
329        MetaValue::Int(value) => Ok(MetaValue::Expr {
330            expr: Expr::Int(value),
331            ty: TypeExpr::Named("i64".to_owned()),
332        }),
333        MetaValue::Bool(value) => Ok(MetaValue::Expr {
334            expr: Expr::Bool(value),
335            ty: TypeExpr::Named("Bool".to_owned()),
336        }),
337        MetaValue::String(value) => Ok(MetaValue::Expr {
338            expr: Expr::String(value),
339            ty: TypeExpr::Named("String".to_owned()),
340        }),
341        MetaValue::Expr { .. } | MetaValue::Type(_) | MetaValue::Code(_) => Ok(value),
342    }
343}
344
345pub(super) fn coerce_value_to_code_for_match(value: MetaValue) -> Option<CodeValue> {
346    match value {
347        MetaValue::Expr { expr, .. } => Some(CodeValue::Expr(expr)),
348        MetaValue::Type(ty) => Some(CodeValue::Type(ty)),
349        _ => None,
350    }
351}
352
353pub(super) fn expand_quoted_block(
354    program: &Program,
355    block: &Block,
356    env: &mut BTreeMap<String, MetaValue>,
357    function_table: &BTreeMap<String, &MetaFunctionDecl>,
358    runtime_scope: &RuntimeScope,
359    mut builder_env_cursor: Option<&mut BuilderEnvCursor>,
360) -> Result<Block, MetaEvalError> {
361    let mut statements = Vec::with_capacity(block.statements.len());
362    for stmt in &block.statements {
363        statements.push(expand_quoted_stmt(
364            program,
365            stmt,
366            env,
367            function_table,
368            runtime_scope,
369            builder_env_cursor.as_deref_mut(),
370        )?);
371    }
372    Ok(Block { statements })
373}
374
375pub(super) fn expand_quoted_stmt(
376    program: &Program,
377    stmt: &Stmt,
378    env: &mut BTreeMap<String, MetaValue>,
379    function_table: &BTreeMap<String, &MetaFunctionDecl>,
380    runtime_scope: &RuntimeScope,
381    mut builder_env_cursor: Option<&mut BuilderEnvCursor>,
382) -> Result<Stmt, MetaEvalError> {
383    match stmt {
384        Stmt::Let {
385            name,
386            name_span,
387            ownership,
388            mode,
389            value,
390        } => Ok(Stmt::Let {
391            name: name.clone(),
392            name_span: *name_span,
393            ownership: *ownership,
394            mode: *mode,
395            value: expand_quoted_expr(
396                program,
397                value,
398                env,
399                function_table,
400                runtime_scope,
401                builder_env_cursor.as_deref_mut(),
402            )?,
403        }),
404        Stmt::Assign {
405            target,
406            mode,
407            value,
408        } => Ok(Stmt::Assign {
409            target: target.clone(),
410            mode: *mode,
411            value: expand_quoted_expr(
412                program,
413                value,
414                env,
415                function_table,
416                runtime_scope,
417                builder_env_cursor.as_deref_mut(),
418            )?,
419        }),
420        Stmt::If {
421            condition,
422            then_block,
423            else_block,
424        } => Ok(Stmt::If {
425            condition: expand_quoted_expr(
426                program,
427                condition,
428                env,
429                function_table,
430                runtime_scope,
431                builder_env_cursor.as_deref_mut(),
432            )?,
433            then_block: expand_quoted_block(
434                program,
435                then_block,
436                env,
437                function_table,
438                runtime_scope,
439                builder_env_cursor.as_deref_mut(),
440            )?,
441            else_block: else_block
442                .as_ref()
443                .map(|block| {
444                    expand_quoted_block(
445                        program,
446                        block,
447                        env,
448                        function_table,
449                        runtime_scope,
450                        builder_env_cursor.as_deref_mut(),
451                    )
452                })
453                .transpose()?,
454        }),
455        Stmt::For {
456            binding,
457            iterable,
458            body,
459        } => Ok(Stmt::For {
460            binding: binding.clone(),
461            iterable: expand_quoted_expr(
462                program,
463                iterable,
464                env,
465                function_table,
466                runtime_scope,
467                builder_env_cursor.as_deref_mut(),
468            )?,
469            body: expand_quoted_block(
470                program,
471                body,
472                env,
473                function_table,
474                runtime_scope,
475                builder_env_cursor.as_deref_mut(),
476            )?,
477        }),
478        Stmt::While { condition, body } => Ok(Stmt::While {
479            condition: expand_quoted_expr(
480                program,
481                condition,
482                env,
483                function_table,
484                runtime_scope,
485                builder_env_cursor.as_deref_mut(),
486            )?,
487            body: expand_quoted_block(
488                program,
489                body,
490                env,
491                function_table,
492                runtime_scope,
493                builder_env_cursor.as_deref_mut(),
494            )?,
495        }),
496        Stmt::Match { value, arms } => Ok(Stmt::Match {
497            value: expand_quoted_expr(
498                program,
499                value,
500                env,
501                function_table,
502                runtime_scope,
503                builder_env_cursor.as_deref_mut(),
504            )?,
505            arms: arms
506                .iter()
507                .map(|arm| {
508                    Ok(ruka_frontend::MatchArm {
509                        pattern: arm.pattern.clone(),
510                        body: expand_quoted_block(
511                            program,
512                            &arm.body,
513                            env,
514                            function_table,
515                            runtime_scope,
516                            builder_env_cursor.as_deref_mut(),
517                        )?,
518                    })
519                })
520                .collect::<Result<Vec<_>, MetaEvalError>>()?,
521        }),
522        Stmt::Meta { body } => Ok(Stmt::Meta { body: body.clone() }),
523        Stmt::Expr { expr, has_semi } => Ok(Stmt::Expr {
524            expr: expand_quoted_expr(
525                program,
526                expr,
527                env,
528                function_table,
529                runtime_scope,
530                builder_env_cursor,
531            )?,
532            has_semi: *has_semi,
533        }),
534    }
535}
536
537pub(super) fn match_quote_code(
538    pattern: &QuotedCode,
539    target: &CodeValue,
540    captures: &mut BTreeMap<String, MetaValue>,
541) -> bool {
542    match (pattern, target) {
543        (QuotedCode::Expr(pattern_expr), CodeValue::Expr(target_expr)) => {
544            match_quote_pattern_expr(pattern_expr, target_expr, captures)
545        }
546        (QuotedCode::Type(pattern_ty), CodeValue::Type(target_ty)) => {
547            match_quote_pattern_type(pattern_ty, target_ty)
548        }
549        _ => false,
550    }
551}
552
553pub(super) fn expand_quoted_call_arg(
554    program: &Program,
555    arg: &CallArg,
556    env: &mut BTreeMap<String, MetaValue>,
557    function_table: &BTreeMap<String, &MetaFunctionDecl>,
558    runtime_scope: &RuntimeScope,
559    builder_env_cursor: Option<&mut BuilderEnvCursor>,
560) -> Result<CallArg, MetaEvalError> {
561    match arg {
562        CallArg::Expr(expr) => Ok(CallArg::Expr(expand_quoted_expr(
563            program,
564            expr,
565            env,
566            function_table,
567            runtime_scope,
568            builder_env_cursor,
569        )?)),
570        CallArg::Spread(expr) => Ok(CallArg::Spread(expand_quoted_expr(
571            program,
572            expr,
573            env,
574            function_table,
575            runtime_scope,
576            builder_env_cursor,
577        )?)),
578        CallArg::Type(ty) => Ok(CallArg::Type(ty.clone())),
579    }
580}