rukalang/meta/
meta_types_builder.rs

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