Skip to main content

luaur_analysis/methods/
magic_gmatch_infer.rs

1use crate::functions::as_mutable_type_pack_alt_d::as_mutable_type_pack;
2use crate::functions::flatten_type_pack::flatten_type_pack_id;
3use crate::functions::parse_pattern_string::parse_pattern_string;
4use crate::records::function_type::FunctionType;
5use crate::records::magic_function_call_context::MagicFunctionCallContext;
6use crate::records::magic_gmatch::MagicGmatch;
7use crate::records::type_pack::TypePack;
8use crate::type_aliases::type_pack_variant::TypePackVariant;
9use luaur_ast::records::ast_expr_constant_string::AstExprConstantString;
10use luaur_ast::records::ast_node::AstNode;
11use luaur_ast::rtti::ast_node_as;
12
13impl MagicGmatch {
14    pub fn infer(&self, context: &MagicFunctionCallContext) -> bool {
15        let (params, _tail) = flatten_type_pack_id(context.arguments);
16
17        if params.len() != 2 {
18            return false;
19        }
20
21        let solver = unsafe { context.solver.as_ref() };
22        let arena = unsafe { &mut *solver.arena };
23        let call_site = unsafe { context.call_site.as_ref() };
24
25        let index = if call_site.self_ { 0 } else { 1 };
26        let pattern = if call_site.args.size > index {
27            let expr = unsafe { *call_site.args.data.add(index) };
28            unsafe { ast_node_as::<AstExprConstantString>(expr as *mut AstNode) }
29        } else {
30            core::ptr::null_mut()
31        };
32
33        if pattern.is_null() {
34            return false;
35        }
36
37        let return_types = unsafe {
38            let pattern = &*pattern;
39            parse_pattern_string(
40                core::ptr::NonNull::new_unchecked(solver.builtin_types),
41                pattern.value.data,
42                pattern.value.size,
43            )
44        };
45
46        if return_types.is_empty() {
47            return false;
48        }
49
50        unsafe {
51            let builtin_types = &*solver.builtin_types;
52            (*context.solver.as_ptr()).constraint_solver_unify(
53                context.constraint.as_ptr(),
54                params[0],
55                builtin_types.stringType,
56            );
57        }
58
59        let empty_pack = arena.add_type_pack_t(TypePack {
60            head: Vec::new(),
61            tail: None,
62        });
63        let return_list = arena.add_type_pack_t(TypePack {
64            head: return_types,
65            tail: None,
66        });
67        let iterator_type = arena.add_type(FunctionType::function_type_new(
68            empty_pack,
69            return_list,
70            None,
71            false,
72        ));
73        let res_type_pack = arena.add_type_pack_t(TypePack {
74            head: vec![iterator_type],
75            tail: None,
76        });
77
78        let result_mut = as_mutable_type_pack(context.result);
79        unsafe {
80            (*result_mut).ty = TypePackVariant::Bound(res_type_pack);
81        }
82
83        true
84    }
85}