• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# coding=utf-8
2#
3# Copyright (c) 2025 Huawei Device Co., Ltd.
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16from abc import ABCMeta, abstractmethod
17from dataclasses import dataclass
18from typing import Literal
19
20from typing_extensions import override
21
22from taihe.codegen.abi.writer import CSourceWriter
23from taihe.codegen.ani.writer import StsWriter
24from taihe.codegen.cpp.analyses import (
25    EnumCppInfo,
26    IfaceCppInfo,
27    StructCppInfo,
28    TypeCppInfo,
29    UnionCppInfo,
30)
31from taihe.semantics.declarations import (
32    AttrItemDecl,
33    EnumDecl,
34    GlobFuncDecl,
35    IfaceDecl,
36    IfaceMethodDecl,
37    IfaceParentDecl,
38    PackageDecl,
39    PackageGroup,
40    ParamDecl,
41    StructDecl,
42    StructFieldDecl,
43    UnionDecl,
44    UnionFieldDecl,
45)
46from taihe.semantics.types import (
47    ArrayType,
48    CallbackType,
49    EnumType,
50    IfaceType,
51    MapType,
52    OpaqueType,
53    OptionalType,
54    ScalarKind,
55    ScalarType,
56    StringType,
57    StructType,
58    Type,
59    UnionType,
60)
61from taihe.semantics.visitor import TypeVisitor
62from taihe.utils.analyses import AbstractAnalysis, AnalysisManager
63from taihe.utils.exceptions import AdhocError
64from taihe.utils.sources import SourceLocation
65
66
67def raise_adhoc_error(
68    am: AnalysisManager,
69    msg: str,
70    loc: SourceLocation | None,
71):
72    am.diagnostics_manager.emit(AdhocError(msg, loc=loc))
73
74
75def check_attr_args(
76    am: AnalysisManager,
77    attr: AttrItemDecl,
78    pattern: str,
79) -> bool:
80    expect_dict = {"s": str, "i": int, "f": float, "b": bool}
81    trailing = "/"
82    if len(pattern) >= 2 and pattern[-1] == "*":
83        trailing = pattern[-2]
84        pattern = pattern[:-2]
85    if trailing == "/" and len(attr.args) != len(pattern):
86        raise_adhoc_error(
87            am,
88            f"@{attr.name} expects exactly {len(pattern)} arguments",
89            attr.loc,
90        )
91        return False
92    if len(attr.args) < len(pattern):
93        raise_adhoc_error(
94            am,
95            f"@{attr.name} expects at least {len(pattern)} arguments",
96            attr.loc,
97        )
98        return False
99    result = []
100    for i, arg in enumerate(attr.args):
101        p = pattern[i] if i < len(pattern) else trailing
102        if not isinstance(arg, expect_dict[p]):
103            raise_adhoc_error(
104                am,
105                f"@{attr.name} expects {i + 1}th argument to be {expect_dict[p].__name__}",
106                attr.loc,
107            )
108            return False
109        result.append(arg)
110    return True
111
112
113@dataclass(repr=False)
114class ANIType:
115    hint: str
116    base: "ANIBaseType"
117
118    def __repr__(self) -> str:
119        return f"ani_{self.hint}"
120
121    def __hash__(self) -> int:
122        return hash(self.hint)
123
124    @property
125    def suffix(self) -> str:
126        return self.base.hint[0].upper() + self.base.hint[1:]
127
128    @property
129    def fixedarray(self) -> "ANIFixedArrayType":
130        pass
131        return self.base.fixedarray_hint
132
133
134@dataclass(repr=False)
135class ANIFixedArrayType(ANIType):
136    def __hash__(self) -> int:
137        return hash(self.hint)
138
139
140@dataclass(repr=False)
141class ANIBaseType(ANIType):
142    fixedarray_hint: "ANIFixedArrayType | None"
143
144    def __init__(self, hint: str):
145        super().__init__(hint, self)
146        self.fixedarray_hint = None
147
148    def __hash__(self) -> int:
149        return hash(self.hint)
150
151
152ANI_REF = ANIBaseType(hint="ref")
153ANI_FIXEDARRAY_REF = ANIFixedArrayType(hint="fixedarray_ref", base=ANI_REF)
154ANI_REF.fixedarray_hint = ANI_FIXEDARRAY_REF
155
156ANI_BOOLEAN = ANIBaseType(hint="boolean")
157ANI_FIXEDARRAY_BOOLEAN = ANIFixedArrayType(hint="fixedarray_boolean", base=ANI_REF)
158ANI_BOOLEAN.fixedarray_hint = ANI_FIXEDARRAY_BOOLEAN
159
160ANI_FLOAT = ANIBaseType(hint="float")
161ANI_FIXEDARRAY_FLOAT = ANIFixedArrayType(hint="fixedarray_float", base=ANI_REF)
162ANI_FLOAT.fixedarray_hint = ANI_FIXEDARRAY_FLOAT
163
164ANI_DOUBLE = ANIBaseType(hint="double")
165ANI_FIXEDARRAY_DOUBLE = ANIFixedArrayType(hint="fixedarray_double", base=ANI_REF)
166ANI_DOUBLE.fixedarray_hint = ANI_FIXEDARRAY_DOUBLE
167
168ANI_BYTE = ANIBaseType(hint="byte")
169ANI_FIXEDARRAY_BYTE = ANIFixedArrayType(hint="fixedarray_byte", base=ANI_REF)
170ANI_BYTE.fixedarray_hint = ANI_FIXEDARRAY_BYTE
171
172ANI_SHORT = ANIBaseType(hint="short")
173ANI_FIXEDARRAY_SHORT = ANIFixedArrayType(hint="fixedarray_short", base=ANI_REF)
174ANI_SHORT.fixedarray_hint = ANI_FIXEDARRAY_SHORT
175
176ANI_INT = ANIBaseType(hint="int")
177ANI_FIXEDARRAY_INT = ANIFixedArrayType(hint="fixedarray_int", base=ANI_REF)
178ANI_INT.fixedarray_hint = ANI_FIXEDARRAY_INT
179
180ANI_LONG = ANIBaseType(hint="long")
181ANI_FIXEDARRAY_LONG = ANIFixedArrayType(hint="fixedarray_long", base=ANI_REF)
182ANI_LONG.fixedarray_hint = ANI_FIXEDARRAY_LONG
183
184ANI_OBJECT = ANIType(hint="object", base=ANI_REF)
185ANI_ARRAY = ANIType(hint="array_ref", base=ANI_REF)  # TODO: Array
186ANI_FN_OBJECT = ANIType(hint="fn_object", base=ANI_REF)
187ANI_ENUM_ITEM = ANIType(hint="enum_item", base=ANI_REF)
188ANI_STRING = ANIType(hint="string", base=ANI_REF)
189ANI_ARRAYBUFFER = ANIType(hint="arraybuffer", base=ANI_REF)
190
191
192@dataclass(repr=False)
193class ANIFuncLike:
194    hint: str
195
196    def __repr__(self) -> str:
197        return f"ani_{self.hint}"
198
199    def __hash__(self) -> int:
200        return hash(self.hint)
201
202    @property
203    def suffix(self) -> str:
204        return self.hint[0].upper() + self.hint[1:]
205
206    @property
207    def upper(self) -> str:
208        return self.hint.upper()
209
210
211ANI_FUNCTION = ANIFuncLike("function")
212ANI_METHOD = ANIFuncLike("method")
213
214
215@dataclass(repr=False)
216class ANIScope:
217    hint: str
218    member: ANIFuncLike
219
220    def __repr__(self) -> str:
221        return f"ani_{self.hint}"
222
223    def __hash__(self) -> int:
224        return hash(self.hint)
225
226    @property
227    def suffix(self) -> str:
228        return self.hint[0].upper() + self.hint[1:]
229
230    @property
231    def upper(self) -> str:
232        return self.hint.upper()
233
234
235ANI_CLASS = ANIScope("class", ANI_METHOD)
236ANI_MODULE = ANIScope("module", ANI_FUNCTION)
237ANI_NAMESPACE = ANIScope("namespace", ANI_FUNCTION)
238
239
240class Path:
241    def __init__(self, package: str | None = None, path: str | None = None) -> None:
242        self.package = package
243        self.path = path
244        self.ani_path = []
245        if self.package is not None:
246            self.ani_path.append(self.package)
247        if self.path is not None:
248            self.ani_path.extend(self.path.split("/"))
249
250
251class Namespace:
252    def __init__(self, name: str, parent: "Namespace | Path") -> None:
253        self.name = name
254        self.parent = parent
255
256        self.children: dict[str, Namespace] = {}
257        self.packages: list[PackageDecl] = []
258        self.is_default = False
259        self.injected_heads: list[str] = []
260        self.injected_codes: list[str] = []
261
262        if not isinstance(parent, Namespace):
263            self.module = self
264            self.path: list[str] = []
265            self.scope = ANI_MODULE
266            self.ani_path = [*parent.ani_path, *name.split(".")]
267        else:
268            self.module = parent.module
269            self.path: list[str] = [*parent.path, name]
270            self.scope = ANI_NAMESPACE
271            self.ani_path = [*parent.ani_path, name]
272
273        self.impl_desc = "L" + "/".join(self.ani_path) + ";"
274
275    def add_path(
276        self,
277        path: list[str],
278        pkg: PackageDecl,
279        is_default: bool,
280    ) -> "Namespace":
281        if not path:
282            self.packages.append(pkg)
283            self.is_default |= is_default
284            return self
285        head, *tail = path
286        child = self.children.setdefault(head, Namespace(head, self))
287        return child.add_path(tail, pkg, is_default)
288
289    def get_member(
290        self,
291        target: StsWriter,
292        sts_name: str,
293        member_is_default: bool,
294    ) -> str:
295        if not isinstance(self.parent, Namespace):
296            scope_name = "__" + "".join(c if c.isalnum() else "_" for c in self.name)
297            if member_is_default:
298                decl_name = f"{scope_name}_default"
299                target.add_import_default(f"{self.name}", decl_name)
300                return decl_name
301            target.add_import_module(f"./{self.name}", scope_name)  # TODO: Remove `./`
302        else:
303            scope_name = self.parent.get_member(target, self.name, self.is_default)
304        return f"{scope_name}.{sts_name}"
305
306
307class PackageGroupANIInfo(AbstractAnalysis[PackageGroup]):
308    def __init__(self, am: AnalysisManager, pg: PackageGroup) -> None:
309        super().__init__(am, pg)
310        self.am = am
311        self.pg = pg
312
313        self.module_dict: dict[str, Namespace] = {}
314        self.package_map: dict[PackageDecl, Namespace] = {}
315
316        self.path = Path(
317            self.am.compiler_invocation.arkts_module_prefix,
318            self.am.compiler_invocation.arkts_path_prefix,
319        )
320
321        for pkg in pg.packages:
322            if (namespace_attr := pkg.get_last_attr("namespace")) and check_attr_args(
323                am, namespace_attr, "ss*"
324            ):
325                module_name, *segments = namespace_attr.args
326                path = [part for segment in segments for part in segment.split(".")]
327            else:
328                module_name = pkg.name
329                path = []
330
331            is_default = pkg.get_last_attr("sts_export_default") is not None
332
333            mod = self.module_dict.setdefault(
334                module_name,
335                Namespace(module_name, self.path),
336            )
337            ns = self.package_map[pkg] = mod.add_path(path, pkg, is_default)
338
339            for sts_inject in pkg.get_all_attrs("sts_inject_into_module"):
340                if check_attr_args(am, sts_inject, "s"):
341                    (head,) = sts_inject.args
342                    mod.injected_heads.append(head)
343
344            for sts_inject in pkg.get_all_attrs("sts_inject"):
345                if check_attr_args(am, sts_inject, "s"):
346                    (code,) = sts_inject.args
347                    ns.injected_codes.append(code)
348
349    def get_namespace(self, pkg: PackageDecl) -> Namespace:
350        return self.package_map[pkg]
351
352
353@dataclass
354class ANINativeFuncInfo:
355    sts_native_name: str
356    full_name: str
357
358
359@dataclass
360class ANIRegisterInfo:
361    parent_scope: ANIScope
362    impl_desc: str
363    member_infos: list[ANINativeFuncInfo]
364
365
366class PackageANIInfo(AbstractAnalysis[PackageDecl]):
367    def __init__(self, am: AnalysisManager, p: PackageDecl) -> None:
368        super().__init__(am, p)
369        self.am = am
370        self.p = p
371
372        self.header = f"{p.name}.ani.hpp"
373        self.source = f"{p.name}.ani.cpp"
374
375        self.cpp_ns = "::".join(p.segments)
376
377        pg_ani_info = PackageGroupANIInfo.get(am, p.parent_group)
378        self.ns = pg_ani_info.get_namespace(p)
379
380
381class GlobFuncANIInfo(AbstractAnalysis[GlobFuncDecl]):
382    def __init__(self, am: AnalysisManager, f: GlobFuncDecl) -> None:
383        super().__init__(am, f)
384        self.am = am
385        self.f = f
386
387        self.sts_native_name = f"{f.name}_inner"
388
389        self.sts_static_scope = None
390        self.sts_ctor_scope = None
391
392        self.sts_func_name = None
393        self.on_off_type = None
394        self.get_name = None
395        self.set_name = None
396
397        self.sts_async_name = None
398        self.sts_promise_name = None
399
400        if self.resolve_ctor() or (
401            self.resolve_static() and (self.resolve_getter() or self.resolve_setter())
402        ):
403            pass
404        elif self.resolve_on_off() or self.resolve_normal():
405            self.resolve_async()
406            self.resolve_promise()
407
408        self.sts_params: list[ParamDecl] = []
409        for param in f.params:
410            if param.get_last_attr("sts_this"):
411                continue
412            self.sts_params.append(param)
413
414    def resolve_ctor(self) -> bool:
415        if (ctor_attr := self.f.get_last_attr("ctor")) is None:
416            return False
417        if not check_attr_args(self.am, ctor_attr, "s"):
418            return True
419        (self.sts_ctor_scope,) = ctor_attr.args
420        return True
421
422    def resolve_static(self) -> bool:
423        if (static_attr := self.f.get_last_attr("static")) is None:
424            return False
425        if not check_attr_args(self.am, static_attr, "s"):
426            return True
427        (self.sts_static_scope,) = static_attr.args
428        return True
429
430    def resolve_getter(self) -> bool:
431        if (get_attr := self.f.get_last_attr("get")) is None:
432            return False
433        if len(self.f.params) != 0 or self.f.return_ty_ref is None:
434            raise_adhoc_error(
435                self.am,
436                "@get method should take no parameters and return non-void",
437                self.f.loc,
438            )
439            return True
440        if get_attr.args and check_attr_args(self.am, get_attr, "s"):
441            (get_name,) = get_attr.args
442        elif self.f.name[:3].lower() == "get":
443            get_name = self.f.name[3:]
444            get_name = get_name[0].lower() + get_name[1:]
445        else:
446            raise_adhoc_error(
447                self.am,
448                '@get method name must start with "Get/get" or have @get argument',
449                self.f.loc,
450            )
451            return True
452        self.get_name = get_name
453        return True
454
455    def resolve_setter(self) -> bool:
456        if (set_attr := self.f.get_last_attr("set")) is None:
457            return False
458        if len(self.f.params) != 1 or self.f.return_ty_ref is not None:
459            raise_adhoc_error(
460                self.am,
461                "@set method should have one parameter and return void",
462                self.f.loc,
463            )
464            return True
465        if set_attr.args and check_attr_args(self.am, set_attr, "s"):
466            (set_name,) = set_attr.args
467        elif self.f.name[:3].lower() == "set":
468            set_name = self.f.name[3:]
469            set_name = set_name[0].lower() + set_name[1:]
470        else:
471            raise_adhoc_error(
472                self.am,
473                '@set method name must start with "Set/set" or have @set argument',
474                self.f.loc,
475            )
476            return True
477        self.set_name = set_name
478        return True
479
480    def resolve_on_off(self) -> bool:
481        if (on_off_attr := self.f.get_last_attr("on_off")) is None:
482            return False
483        if on_off_attr.args:
484            if not check_attr_args(self.am, on_off_attr, "s"):
485                return True
486            (type_name,) = on_off_attr.args
487        else:
488            type_name = None
489        if overload_attr := self.f.get_last_attr("overload"):
490            if not check_attr_args(self.am, overload_attr, "s"):
491                return True
492            (func_name,) = overload_attr.args
493            if type_name is None:
494                if self.f.name[: len(func_name)].lower() == func_name.lower():
495                    type_name = self.f.name[len(func_name) :]
496                    type_name = type_name[0].lower() + type_name[1:]
497                else:
498                    raise_adhoc_error(
499                        self.am,
500                        f"@on_off method name must start with {func_name}",
501                        self.f.loc,
502                    )
503                    return True
504        else:
505            for func_name in ("on", "off"):
506                if self.f.name[: len(func_name)].lower() == func_name.lower():
507                    if type_name is None:
508                        type_name = self.f.name[len(func_name) :]
509                        type_name = type_name[0].lower() + type_name[1:]
510                    break
511            else:
512                raise_adhoc_error(
513                    self.am,
514                    '@on_off method name must start with "On/on/Off/off" or use together with @overload',
515                    self.f.loc,
516                )
517                return True
518        self.sts_func_name = func_name
519        self.on_off_type = type_name
520        return True
521
522    def resolve_normal(self) -> bool:
523        if overload_attr := self.f.get_last_attr("overload"):
524            if not check_attr_args(self.am, overload_attr, "s"):
525                return True
526            (func_name,) = overload_attr.args
527        else:
528            if self.am.compiler_invocation.sts_keep_name:
529                func_name = self.f.name
530            else:
531                func_name = self.f.name[0].lower() + self.f.name[1:]
532        self.sts_func_name = func_name
533        return True
534
535    def resolve_async(self) -> bool:
536        if (async_attr := self.f.get_last_attr("gen_async")) is None:
537            return False
538        if self.sts_func_name is None:
539            return True
540        if async_attr.args and check_attr_args(self.am, async_attr, "s"):
541            (self.sts_async_name,) = async_attr.args
542        elif self.sts_func_name[-4:].lower() == "sync":
543            self.sts_async_name = self.sts_func_name[:-4]
544        else:
545            raise_adhoc_error(
546                self.am,
547                '@gen_async method name must end with "Sync" or have @gen_async argument',
548                self.f.loc,
549            )
550        return True
551
552    def resolve_promise(self) -> bool:
553        if (promise_attr := self.f.get_last_attr("gen_promise")) is None:
554            return False
555        if self.sts_func_name is None:
556            return True
557        if promise_attr.args and check_attr_args(self.am, promise_attr, "s"):
558            (self.sts_promise_name,) = promise_attr.args
559        elif self.sts_func_name[-4:].lower() == "sync":
560            self.sts_promise_name = self.sts_func_name[:-4]
561        else:
562            raise_adhoc_error(
563                self.am,
564                '@gen_promise method name must end with "Sync" or have @gen_promise argument',
565                self.f.loc,
566            )
567        return True
568
569    def call_native_with(self, sts_args: list[str], this: str = "this") -> str:
570        arg = iter(sts_args)
571        sts_native_args: list[str] = []
572        for param in self.f.params:
573            if param.get_last_attr("sts_this"):
574                sts_native_args.append(this)
575                continue
576            sts_native_args.append(next(arg))
577        sts_native_args_str = ", ".join(sts_native_args)
578        return f"{self.sts_native_name}({sts_native_args_str})"
579
580
581class IfaceMethodANIInfo(AbstractAnalysis[IfaceMethodDecl]):
582    def __init__(self, am: AnalysisManager, f: IfaceMethodDecl) -> None:
583        super().__init__(am, f)
584        self.am = am
585        self.f = f
586
587        self.sts_native_name = f"{f.name}_inner"
588
589        self.ani_method_name = None
590
591        self.sts_method_name = None
592        self.get_name = None
593        self.set_name = None
594        self.on_off_type = None
595
596        self.sts_async_name = None
597        self.sts_promise_name = None
598
599        if self.resolve_getter() or self.resolve_setter():
600            pass
601        elif self.resolve_on_off() or self.resolve_normal():
602            self.resolve_async()
603            self.resolve_promise()
604
605        self.sts_params: list[ParamDecl] = []
606        for param in f.params:
607            if param.get_last_attr("sts_this"):
608                continue
609            self.sts_params.append(param)
610
611    def resolve_getter(self) -> bool:
612        if (get_attr := self.f.get_last_attr("get")) is None:
613            return False
614        if len(self.f.params) != 0 or self.f.return_ty_ref is None:
615            raise_adhoc_error(
616                self.am,
617                "@get method should take no parameters and return non-void",
618                self.f.loc,
619            )
620            return True
621        if get_attr.args and check_attr_args(self.am, get_attr, "s"):
622            (get_name,) = get_attr.args
623        elif self.f.name[:3].lower() == "get":
624            get_name = self.f.name[3:]
625            get_name = get_name[0].lower() + get_name[1:]
626        else:
627            raise_adhoc_error(
628                self.am,
629                '@get method name must start with "Get/get" or have @get argument',
630                self.f.loc,
631            )
632            return True
633        self.ani_method_name = f"<get>{get_name}"
634        self.get_name = get_name
635        return True
636
637    def resolve_setter(self) -> bool:
638        if (set_attr := self.f.get_last_attr("set")) is None:
639            return False
640        if len(self.f.params) != 1 or self.f.return_ty_ref is not None:
641            raise_adhoc_error(
642                self.am,
643                "@set method should have one parameter and return void",
644                self.f.loc,
645            )
646            return True
647        if set_attr.args and check_attr_args(self.am, set_attr, "s"):
648            (set_name,) = set_attr.args
649        elif self.f.name[:3].lower() == "set":
650            set_name = self.f.name[3:]
651            set_name = set_name[0].lower() + set_name[1:]
652        else:
653            raise_adhoc_error(
654                self.am,
655                '@set method name must start with "Set/set" or have @set argument',
656                self.f.loc,
657            )
658            return True
659        self.ani_method_name = f"<set>{set_name}"
660        self.set_name = set_name
661        return True
662
663    def resolve_on_off(self) -> bool:
664        if (on_off_attr := self.f.get_last_attr("on_off")) is None:
665            return False
666        if on_off_attr.args:
667            if not check_attr_args(self.am, on_off_attr, "s"):
668                return True
669            (type_name,) = on_off_attr.args
670        else:
671            type_name = None
672        if overload_attr := self.f.get_last_attr("overload"):
673            if not check_attr_args(self.am, overload_attr, "s"):
674                return True
675            (method_name,) = overload_attr.args
676            if type_name is None:
677                if self.f.name[: len(method_name)].lower() == method_name.lower():
678                    type_name = self.f.name[len(method_name) :]
679                    type_name = type_name[0].lower() + type_name[1:]
680                else:
681                    raise_adhoc_error(
682                        self.am,
683                        f"@on_off method name must start with {method_name}",
684                        self.f.loc,
685                    )
686                    return True
687        else:
688            for method_name in ("on", "off"):
689                if self.f.name[: len(method_name)].lower() == method_name.lower():
690                    if type_name is None:
691                        type_name = self.f.name[len(method_name) :]
692                        type_name = type_name[0].lower() + type_name[1:]
693                    break
694            else:
695                raise_adhoc_error(
696                    self.am,
697                    '@on_off method name must start with "On/on/Off/off" or use together with @overload',
698                    self.f.loc,
699                )
700                return True
701        self.ani_method_name = method_name
702        self.sts_method_name = method_name
703        self.on_off_type = type_name
704        return True
705
706    def resolve_normal(self) -> bool:
707        if overload_attr := self.f.get_last_attr("overload"):
708            if not check_attr_args(self.am, overload_attr, "s"):
709                return True
710            (method_name,) = overload_attr.args
711        else:
712            if self.am.compiler_invocation.sts_keep_name:
713                method_name = self.f.name
714            else:
715                method_name = self.f.name[0].lower() + self.f.name[1:]
716        self.ani_method_name = method_name
717        self.sts_method_name = method_name
718        return True
719
720    def resolve_async(self) -> bool:
721        if (async_attr := self.f.get_last_attr("gen_async")) is None:
722            return False
723        if self.sts_method_name is None:
724            return True
725        if async_attr.args and check_attr_args(self.am, async_attr, "s"):
726            (self.sts_async_name,) = async_attr.args
727        elif self.sts_method_name[-4:].lower() == "sync":
728            self.sts_async_name = self.sts_method_name[:-4]
729        else:
730            raise_adhoc_error(
731                self.am,
732                '@gen_async method name must end with "Sync" or have @gen_async argument',
733                self.f.loc,
734            )
735        return True
736
737    def resolve_promise(self) -> bool:
738        if (promise_attr := self.f.get_last_attr("gen_promise")) is None:
739            return False
740        if self.sts_method_name is None:
741            return True
742        if promise_attr.args and check_attr_args(self.am, promise_attr, "s"):
743            (self.sts_promise_name,) = promise_attr.args
744        elif self.sts_method_name[-4:].lower() == "sync":
745            self.sts_promise_name = self.sts_method_name[:-4]
746        else:
747            raise_adhoc_error(
748                self.am,
749                '@gen_promise method name must end with "Sync" or have @gen_promise argument',
750                self.f.loc,
751            )
752        return True
753
754    def call_native_with(self, sts_args: list[str], this: str = "this") -> str:
755        arg = iter(sts_args)
756        sts_native_args: list[str] = []
757        for param in self.f.params:
758            if param.get_last_attr("sts_this"):
759                sts_native_args.append(this)
760                continue
761            sts_native_args.append(next(arg))
762        sts_native_args_str = ", ".join(sts_native_args)
763        return f"{this}.{self.sts_native_name}({sts_native_args_str})"
764
765
766class EnumANIInfo(AbstractAnalysis[EnumDecl]):
767    def __init__(self, am: AnalysisManager, d: EnumDecl) -> None:
768        super().__init__(am, d)
769
770        self.parent_ns = PackageANIInfo.get(am, d.parent_pkg).ns
771        self.sts_type_name = d.name
772        self.type_desc = (
773            "L" + "/".join([*self.parent_ns.ani_path, self.sts_type_name]) + ";"
774        )
775
776        self.const = d.get_last_attr("const") is not None
777
778        if (
779            not self.const
780            and isinstance(d.ty_ref.resolved_ty, ScalarType)
781            and d.ty_ref.resolved_ty.kind
782            in (
783                ScalarKind.BOOL,
784                ScalarKind.F32,
785                ScalarKind.F64,
786            )
787        ):
788            raise_adhoc_error(
789                am,
790                f"{d.description} without @const cannot have type {d.ty_ref.resolved_ty.signature}",
791                d.loc,
792            )
793
794        self.is_default = d.get_last_attr("sts_export_default") is not None
795
796    def sts_type_in(self, target: StsWriter):
797        return self.parent_ns.get_member(
798            target,
799            self.sts_type_name,
800            self.is_default,
801        )
802
803
804class UnionFieldANIInfo(AbstractAnalysis[UnionFieldDecl]):
805    field_ty: Type | None | Literal["null", "undefined"]
806
807    def __init__(self, am: AnalysisManager, d: UnionFieldDecl) -> None:
808        super().__init__(am, d)
809        if d.ty_ref is None:
810            if d.get_last_attr("null"):
811                self.field_ty = "null"
812                return
813            if d.get_last_attr("undefined"):
814                self.field_ty = "undefined"
815                return
816            raise_adhoc_error(
817                am,
818                f"union field {d.name} must have a type or have @null/@undefined attribute",
819                d.loc,
820            )
821            self.field_ty = None
822        else:
823            self.field_ty = d.ty_ref.resolved_ty
824
825
826class UnionANIInfo(AbstractAnalysis[UnionDecl]):
827    def __init__(self, am: AnalysisManager, d: UnionDecl) -> None:
828        super().__init__(am, d)
829        self.decl_header = f"{d.parent_pkg.name}.{d.name}.ani.1.h"
830        self.impl_header = f"{d.parent_pkg.name}.{d.name}.ani.2.h"
831
832        self.parent_ns = PackageANIInfo.get(am, d.parent_pkg).ns
833        self.sts_type_name = d.name
834        self.type_desc = "Lstd/core/Object;"
835
836        self.sts_final_fields: list[list[UnionFieldDecl]] = []
837        for field in d.fields:
838            if field.ty_ref and isinstance(ty := field.ty_ref.resolved_ty, UnionType):
839                inner_ani_info = UnionANIInfo.get(am, ty.ty_decl)
840                self.sts_final_fields.extend(
841                    [field, *parts] for parts in inner_ani_info.sts_final_fields
842                )
843            else:
844                self.sts_final_fields.append([field])
845
846        self.is_default = d.get_last_attr("sts_export_default") is not None
847
848    def sts_type_in(self, target: StsWriter):
849        return self.parent_ns.get_member(
850            target,
851            self.sts_type_name,
852            self.is_default,
853        )
854
855
856class StructFieldANIInfo(AbstractAnalysis[StructFieldDecl]):
857    def __init__(self, am: AnalysisManager, d: StructFieldDecl) -> None:
858        super().__init__(am, d)
859        self.readonly = d.get_last_attr("readonly") is not None
860
861
862class StructANIInfo(AbstractAnalysis[StructDecl]):
863    def __init__(self, am: AnalysisManager, d: StructDecl) -> None:
864        super().__init__(am, d)
865        self.decl_header = f"{d.parent_pkg.name}.{d.name}.ani.1.h"
866        self.impl_header = f"{d.parent_pkg.name}.{d.name}.ani.2.h"
867
868        self.parent_ns = PackageANIInfo.get(am, d.parent_pkg).ns
869        self.sts_type_name = d.name
870        if d.get_last_attr("class"):
871            self.sts_impl_name = f"{d.name}"
872        else:
873            self.sts_impl_name = f"{d.name}_inner"
874        self.type_desc = (
875            "L" + "/".join([*self.parent_ns.ani_path, self.sts_type_name]) + ";"
876        )
877        self.impl_desc = (
878            "L" + "/".join([*self.parent_ns.ani_path, self.sts_impl_name]) + ";"
879        )
880
881        self.interface_injected_codes: list[str] = []
882        for iface_injected in d.get_all_attrs("sts_inject_into_interface"):
883            if check_attr_args(am, iface_injected, "s"):
884                (code,) = iface_injected.args
885                self.interface_injected_codes.append(code)
886        self.class_injected_codes: list[str] = []
887        for class_injected in d.get_all_attrs("sts_inject_into_class"):
888            if check_attr_args(am, class_injected, "s"):
889                (code,) = class_injected.args
890                self.class_injected_codes.append(code)
891
892        self.sts_fields: list[StructFieldDecl] = []
893        self.sts_iface_parents: list[StructFieldDecl] = []
894        self.sts_class_parents: list[StructFieldDecl] = []
895        self.sts_final_fields: list[list[StructFieldDecl]] = []
896        for field in d.fields:
897            if field.get_last_attr("extends"):
898                ty = field.ty_ref.resolved_ty
899                if not isinstance(ty, StructType):
900                    raise_adhoc_error(
901                        am,
902                        "struct cannot extend non-struct type",
903                        field.loc,
904                    )
905                    continue
906                parent_ani_info = StructANIInfo.get(am, ty.ty_decl)
907                if parent_ani_info.is_class():
908                    self.sts_class_parents.append(field)
909                else:
910                    self.sts_iface_parents.append(field)
911                self.sts_final_fields.extend(
912                    [field, *parts] for parts in parent_ani_info.sts_final_fields
913                )
914            else:
915                self.sts_fields.append(field)
916                self.sts_final_fields.append([field])
917
918        self.is_default = d.get_last_attr("sts_export_default") is not None
919
920    def is_class(self):
921        return self.sts_type_name == self.sts_impl_name
922
923    def sts_type_in(self, target: StsWriter):
924        return self.parent_ns.get_member(
925            target,
926            self.sts_type_name,
927            self.is_default,
928        )
929
930
931class IfaceANIInfo(AbstractAnalysis[IfaceDecl]):
932    def __init__(self, am: AnalysisManager, d: IfaceDecl) -> None:
933        super().__init__(am, d)
934        self.decl_header = f"{d.parent_pkg.name}.{d.name}.ani.1.h"
935        self.impl_header = f"{d.parent_pkg.name}.{d.name}.ani.2.h"
936
937        self.parent_ns = PackageANIInfo.get(am, d.parent_pkg).ns
938        self.sts_type_name = d.name
939        if d.get_last_attr("class"):
940            self.sts_impl_name = f"{d.name}"
941        else:
942            self.sts_impl_name = f"{d.name}_inner"
943        self.type_desc = (
944            "L" + "/".join([*self.parent_ns.ani_path, self.sts_type_name]) + ";"
945        )
946        self.impl_desc = (
947            "L" + "/".join([*self.parent_ns.ani_path, self.sts_impl_name]) + ";"
948        )
949
950        self.interface_injected_codes: list[str] = []
951        for iface_injected in d.get_all_attrs("sts_inject_into_interface"):
952            if check_attr_args(am, iface_injected, "s"):
953                (code,) = iface_injected.args
954                self.interface_injected_codes.append(code)
955        self.class_injected_codes: list[str] = []
956        for class_injected in d.get_all_attrs("sts_inject_into_class"):
957            if check_attr_args(am, class_injected, "s"):
958                (code,) = class_injected.args
959                self.class_injected_codes.append(code)
960
961        self.sts_class_parents: list[IfaceParentDecl] = []
962        self.sts_iface_parents: list[IfaceParentDecl] = []
963        for parent in d.parents:
964            ty = parent.ty_ref.resolved_ty
965            pass
966            parent_ani_info = IfaceANIInfo.get(am, ty.ty_decl)
967            if parent_ani_info.is_class():
968                self.sts_class_parents.append(parent)
969            else:
970                self.sts_iface_parents.append(parent)
971
972        self.is_default = d.get_last_attr("sts_export_default") is not None
973
974    def is_class(self):
975        return self.sts_type_name == self.sts_impl_name
976
977    def sts_type_in(self, target: StsWriter):
978        return self.parent_ns.get_member(
979            target,
980            self.sts_type_name,
981            self.is_default,
982        )
983
984
985class AbstractTypeANIInfo(metaclass=ABCMeta):
986    ani_type: ANIType
987    type_desc: str
988
989    def __init__(self, am: AnalysisManager, t: Type):
990        self.cpp_info = TypeCppInfo.get(am, t)
991
992    @property
993    def type_desc_boxed(self) -> str:
994        if self.ani_type.base == ANI_REF:
995            return self.type_desc
996        return f"Lstd/core/{self.ani_type.suffix};"
997
998    @abstractmethod
999    def sts_type_in(self, target: StsWriter) -> str:
1000        pass
1001
1002    @abstractmethod
1003    def from_ani(
1004        self,
1005        target: CSourceWriter,
1006        env: str,
1007        ani_value: str,
1008        cpp_result: str,
1009    ):
1010        pass
1011
1012    @abstractmethod
1013    def into_ani(
1014        self,
1015        target: CSourceWriter,
1016        env: str,
1017        cpp_value: str,
1018        ani_result: str,
1019    ):
1020        pass
1021
1022    def into_ani_boxed(
1023        self,
1024        target: CSourceWriter,
1025        env: str,
1026        cpp_value: str,
1027        ani_result: str,
1028    ):
1029        if self.ani_type.base == ANI_REF:
1030            self.into_ani(target, env, cpp_value, ani_result)
1031        else:
1032            ani_value = f"{ani_result}_ani"
1033            target.writelns(
1034                f"ani_object {ani_result};",
1035            )
1036            self.into_ani(target, env, cpp_value, ani_value)
1037            target.writelns(
1038                f'{env}->Object_New(TH_ANI_FIND_CLASS({env}, "{self.type_desc_boxed}"), TH_ANI_FIND_CLASS_METHOD({env}, "{self.type_desc_boxed}", "<ctor>", "{self.type_desc}:V"), &{ani_result}, {ani_value});',
1039            )
1040
1041    def from_ani_boxed(
1042        self,
1043        target: CSourceWriter,
1044        env: str,
1045        ani_value: str,
1046        cpp_result: str,
1047    ):
1048        if self.ani_type.base == ANI_REF:
1049            self.from_ani(
1050                target,
1051                env,
1052                f"static_cast<{self.ani_type}>({ani_value})",
1053                cpp_result,
1054            )
1055        else:
1056            ani_result = f"{cpp_result}_ani"
1057            target.writelns(
1058                f"{self.ani_type} {ani_result};",
1059                f'{env}->Object_CallMethod_{self.ani_type.suffix}((ani_object){ani_value}, TH_ANI_FIND_CLASS_METHOD({env}, "{self.type_desc_boxed}", "unboxed", ":{self.type_desc}"), &{ani_result});',
1060            )
1061            self.from_ani(target, env, ani_result, cpp_result)
1062
1063    def from_ani_fixedarray(
1064        self,
1065        target: CSourceWriter,
1066        env: str,
1067        ani_size: str,
1068        ani_fixedarray_value: str,
1069        cpp_fixedarray_buffer: str,
1070    ):
1071        if self.ani_type.base == ANI_REF:
1072            ani_value = f"{cpp_fixedarray_buffer}_ani_item"
1073            cpp_result = f"{cpp_fixedarray_buffer}_cpp_item"
1074            cpp_i = f"{cpp_fixedarray_buffer}_i"
1075            with target.indented(
1076                f"for (size_t {cpp_i} = 0; {cpp_i} < {ani_size}; {cpp_i}++) {{",
1077                f"}}",
1078            ):
1079                target.writelns(
1080                    f"{self.ani_type} {ani_value};",
1081                    f"{env}->FixedArray_Get_Ref({ani_fixedarray_value}, {cpp_i}, reinterpret_cast<ani_ref*>(&{ani_value}));",
1082                )
1083                self.from_ani(target, env, ani_value, cpp_result)
1084                target.writelns(
1085                    f"new (&{cpp_fixedarray_buffer}[{cpp_i}]) {self.cpp_info.as_owner}(std::move({cpp_result}));",
1086                )
1087        else:
1088            target.writelns(
1089                f"{env}->FixedArray_GetRegion_{self.ani_type.suffix}({ani_fixedarray_value}, 0, {ani_size}, reinterpret_cast<{self.ani_type}*>({cpp_fixedarray_buffer}));",
1090            )
1091
1092    def into_ani_fixedarray(
1093        self,
1094        target: CSourceWriter,
1095        env: str,
1096        cpp_size: str,
1097        cpp_fixedarray_value: str,
1098        ani_fixedarray_result: str,
1099    ):
1100        if self.ani_type.base == ANI_REF:
1101            ani_class = f"{ani_fixedarray_result}_cls"
1102            ani_result = f"{ani_fixedarray_result}_item"
1103            ani_undefined = f"{ani_fixedarray_result}_undef"
1104            cpp_i = f"{ani_fixedarray_result}_i"
1105            target.writelns(
1106                f"ani_fixedarray_ref {ani_fixedarray_result};",
1107                f"ani_class {ani_class};",
1108                f'{env}->FindClass("{self.type_desc}", &{ani_class});',
1109                f"ani_ref {ani_undefined};",
1110                f"{env}->GetUndefined(&{ani_undefined});",
1111                f"{env}->FixedArray_New_Ref({ani_class}, {cpp_size}, {ani_undefined}, &{ani_fixedarray_result});",
1112            )
1113            with target.indented(
1114                f"for (size_t {cpp_i} = 0; {cpp_i} < {cpp_size}; {cpp_i}++) {{",
1115                f"}}",
1116            ):
1117                self.into_ani(
1118                    target, env, f"{cpp_fixedarray_value}[{cpp_i}]", ani_result
1119                )
1120                target.writelns(
1121                    f"{env}->FixedArray_Set_Ref({ani_fixedarray_result}, {cpp_i}, {ani_result});",
1122                )
1123        else:
1124            target.writelns(
1125                f"{self.ani_type.fixedarray} {ani_fixedarray_result};",
1126                f"{env}->FixedArray_New_{self.ani_type.suffix}({cpp_size}, &{ani_fixedarray_result});",
1127                f"{env}->FixedArray_SetRegion_{self.ani_type.suffix}({ani_fixedarray_result}, 0, {cpp_size}, reinterpret_cast<{self.ani_type} const*>({cpp_fixedarray_value}));",
1128            )
1129
1130
1131class EnumTypeANIInfo(AbstractTypeANIInfo, AbstractAnalysis[EnumType]):
1132    def __init__(self, am: AnalysisManager, t: EnumType):
1133        super().__init__(am, t)
1134        self.am = am
1135        self.t = t
1136        enum_ani_info = EnumANIInfo.get(self.am, self.t.ty_decl)
1137        self.ani_type = ANI_ENUM_ITEM
1138        self.type_desc = enum_ani_info.type_desc
1139        if enum_ani_info.const:
1140            raise_adhoc_error(
1141                am,
1142                f"@const {t.ty_decl.description} cannot be used as type",
1143                t.ty_ref.loc,
1144            )
1145
1146    @override
1147    def sts_type_in(self, target: StsWriter) -> str:
1148        enum_ani_info = EnumANIInfo.get(self.am, self.t.ty_decl)
1149        return enum_ani_info.sts_type_in(target)
1150
1151    @override
1152    def from_ani(
1153        self,
1154        target: CSourceWriter,
1155        env: str,
1156        ani_value: str,
1157        cpp_result: str,
1158    ):
1159        ani_index = f"{cpp_result}_idx"
1160        enum_cpp_info = EnumCppInfo.get(self.am, self.t.ty_decl)
1161        target.writelns(
1162            f"ani_size {ani_index};",
1163            f"{env}->EnumItem_GetIndex({ani_value}, &{ani_index});",
1164            f"{enum_cpp_info.full_name} {cpp_result}(({enum_cpp_info.full_name}::key_t){ani_index});",
1165        )
1166
1167    @override
1168    def into_ani(
1169        self,
1170        target: CSourceWriter,
1171        env: str,
1172        cpp_value: str,
1173        ani_result: str,
1174    ):
1175        ani_class = f"{ani_result}_cls"
1176        target.writelns(
1177            f"ani_enum {ani_class};",
1178            f'{env}->FindEnum("{self.type_desc}", &{ani_class});',
1179            f"ani_enum_item {ani_result};",
1180            f"{env}->Enum_GetEnumItemByIndex({ani_class}, (ani_size){cpp_value}.get_key(), &{ani_result});",
1181        )
1182
1183
1184class StructTypeANIInfo(AbstractTypeANIInfo, AbstractAnalysis[StructType]):
1185    def __init__(self, am: AnalysisManager, t: StructType):
1186        super().__init__(am, t)
1187        self.am = am
1188        self.t = t
1189        struct_ani_info = StructANIInfo.get(self.am, self.t.ty_decl)
1190        self.ani_type = ANI_OBJECT
1191        self.type_desc = struct_ani_info.type_desc
1192
1193    @override
1194    def sts_type_in(self, target: StsWriter) -> str:
1195        struct_ani_info = StructANIInfo.get(self.am, self.t.ty_decl)
1196        return struct_ani_info.sts_type_in(target)
1197
1198    @override
1199    def from_ani(
1200        self,
1201        target: CSourceWriter,
1202        env: str,
1203        ani_value: str,
1204        cpp_result: str,
1205    ):
1206        struct_ani_info = StructANIInfo.get(self.am, self.t.ty_decl)
1207        struct_cpp_info = StructCppInfo.get(self.am, self.t.ty_decl)
1208        target.add_include(struct_ani_info.impl_header)
1209        target.writelns(
1210            f"{self.cpp_info.as_owner} {cpp_result} = ::taihe::from_ani<{struct_cpp_info.as_owner}>({env}, {ani_value});",
1211        )
1212
1213    @override
1214    def into_ani(
1215        self,
1216        target: CSourceWriter,
1217        env: str,
1218        cpp_value: str,
1219        ani_result: str,
1220    ):
1221        struct_ani_info = StructANIInfo.get(self.am, self.t.ty_decl)
1222        struct_cpp_info = StructCppInfo.get(self.am, self.t.ty_decl)
1223        target.add_include(struct_ani_info.impl_header)
1224        target.writelns(
1225            f"ani_object {ani_result} = ::taihe::into_ani<{struct_cpp_info.as_owner}>({env}, {cpp_value});",
1226        )
1227
1228
1229class UnionTypeANIInfo(AbstractTypeANIInfo, AbstractAnalysis[UnionType]):
1230    def __init__(self, am: AnalysisManager, t: UnionType):
1231        super().__init__(am, t)
1232        self.am = am
1233        self.t = t
1234        union_ani_info = UnionANIInfo.get(self.am, self.t.ty_decl)
1235        self.ani_type = ANI_REF
1236        self.type_desc = union_ani_info.type_desc
1237
1238    @override
1239    def sts_type_in(self, target: StsWriter) -> str:
1240        union_ani_info = UnionANIInfo.get(self.am, self.t.ty_decl)
1241        return union_ani_info.sts_type_in(target)
1242
1243    @override
1244    def from_ani(
1245        self,
1246        target: CSourceWriter,
1247        env: str,
1248        ani_value: str,
1249        cpp_result: str,
1250    ):
1251        union_ani_info = UnionANIInfo.get(self.am, self.t.ty_decl)
1252        union_cpp_info = UnionCppInfo.get(self.am, self.t.ty_decl)
1253        target.add_include(union_ani_info.impl_header)
1254        target.writelns(
1255            f"{self.cpp_info.as_owner} {cpp_result} = ::taihe::from_ani<{union_cpp_info.as_owner}>({env}, {ani_value});",
1256        )
1257
1258    @override
1259    def into_ani(
1260        self,
1261        target: CSourceWriter,
1262        env: str,
1263        cpp_value: str,
1264        ani_result: str,
1265    ):
1266        union_ani_info = UnionANIInfo.get(self.am, self.t.ty_decl)
1267        union_cpp_info = UnionCppInfo.get(self.am, self.t.ty_decl)
1268        target.add_include(union_ani_info.impl_header)
1269        target.writelns(
1270            f"ani_ref {ani_result} = ::taihe::into_ani<{union_cpp_info.as_owner}>({env}, {cpp_value});",
1271        )
1272
1273
1274class IfaceTypeANIInfo(AbstractTypeANIInfo, AbstractAnalysis[IfaceType]):
1275    def __init__(self, am: AnalysisManager, t: IfaceType):
1276        super().__init__(am, t)
1277        self.am = am
1278        self.t = t
1279        iface_ani_info = IfaceANIInfo.get(self.am, self.t.ty_decl)
1280        self.ani_type = ANI_OBJECT
1281        self.type_desc = iface_ani_info.type_desc
1282
1283    @override
1284    def sts_type_in(self, target: StsWriter) -> str:
1285        iface_ani_info = IfaceANIInfo.get(self.am, self.t.ty_decl)
1286        return iface_ani_info.sts_type_in(target)
1287
1288    @override
1289    def from_ani(
1290        self,
1291        target: CSourceWriter,
1292        env: str,
1293        ani_value: str,
1294        cpp_result: str,
1295    ):
1296        iface_ani_info = IfaceANIInfo.get(self.am, self.t.ty_decl)
1297        iface_cpp_info = IfaceCppInfo.get(self.am, self.t.ty_decl)
1298        target.add_include(iface_ani_info.impl_header)
1299        target.writelns(
1300            f"{self.cpp_info.as_owner} {cpp_result} = ::taihe::from_ani<{iface_cpp_info.as_owner}>({env}, {ani_value});",
1301        )
1302
1303    @override
1304    def into_ani(
1305        self,
1306        target: CSourceWriter,
1307        env: str,
1308        cpp_value: str,
1309        ani_result: str,
1310    ):
1311        iface_ani_info = IfaceANIInfo.get(self.am, self.t.ty_decl)
1312        iface_cpp_info = IfaceCppInfo.get(self.am, self.t.ty_decl)
1313        target.add_include(iface_ani_info.impl_header)
1314        target.writelns(
1315            f"ani_object {ani_result} = ::taihe::into_ani<{iface_cpp_info.as_owner}>({env}, {cpp_value});",
1316        )
1317
1318
1319class ScalarTypeANIInfo(AbstractTypeANIInfo, AbstractAnalysis[ScalarType]):
1320    def __init__(self, am: AnalysisManager, t: ScalarType):
1321        super().__init__(am, t)
1322        sts_info = {
1323            ScalarKind.BOOL: ("boolean", ANI_BOOLEAN, "Z"),
1324            ScalarKind.F32: ("float", ANI_FLOAT, "F"),
1325            ScalarKind.F64: ("double", ANI_DOUBLE, "D"),
1326            ScalarKind.I8: ("byte", ANI_BYTE, "B"),
1327            ScalarKind.I16: ("short", ANI_SHORT, "S"),
1328            ScalarKind.I32: ("int", ANI_INT, "I"),
1329            ScalarKind.I64: ("long", ANI_LONG, "J"),
1330            ScalarKind.U8: ("byte", ANI_BYTE, "B"),
1331            ScalarKind.U16: ("short", ANI_SHORT, "S"),
1332            ScalarKind.U32: ("int", ANI_INT, "I"),
1333            ScalarKind.U64: ("long", ANI_LONG, "J"),
1334        }.get(t.kind)
1335        if sts_info is None:
1336            raise ValueError
1337        sts_type, ani_type, type_desc = sts_info
1338        self.sts_type = sts_type
1339        self.ani_type = ani_type
1340        self.type_desc = type_desc
1341
1342    @override
1343    def sts_type_in(self, target: StsWriter) -> str:
1344        return self.sts_type
1345
1346    @override
1347    def from_ani(
1348        self,
1349        target: CSourceWriter,
1350        env: str,
1351        ani_value: str,
1352        cpp_result: str,
1353    ):
1354        target.writelns(
1355            f"{self.cpp_info.as_owner} {cpp_result} = ({self.cpp_info.as_owner}){ani_value};",
1356        )
1357
1358    @override
1359    def into_ani(
1360        self,
1361        target: CSourceWriter,
1362        env: str,
1363        cpp_value: str,
1364        ani_result: str,
1365    ):
1366        target.writelns(
1367            f"{self.ani_type} {ani_result} = ({self.cpp_info.as_owner}){cpp_value};",
1368        )
1369
1370
1371class OpaqueTypeANIInfo(AbstractTypeANIInfo, AbstractAnalysis[OpaqueType]):
1372    def __init__(self, am: AnalysisManager, t: OpaqueType) -> None:
1373        super().__init__(am, t)
1374        self.am = am
1375        self.t = t
1376        self.ani_type = ANI_OBJECT
1377        if (
1378            sts_type_attr := self.t.ty_ref.get_last_attr("sts_type")
1379        ) and check_attr_args(self.am, sts_type_attr, "s"):
1380            (sts_type,) = sts_type_attr.args
1381            self.sts_type = sts_type
1382        else:
1383            self.sts_type = "Object"
1384        self.type_desc = "Lstd/core/Object;"
1385
1386    @override
1387    def sts_type_in(self, target: StsWriter) -> str:
1388        return self.sts_type
1389
1390    @override
1391    def from_ani(
1392        self,
1393        target: CSourceWriter,
1394        env: str,
1395        ani_value: str,
1396        cpp_result: str,
1397    ):
1398        target.writelns(
1399            f"{self.cpp_info.as_owner} {cpp_result} = ({self.cpp_info.as_owner}){ani_value};",
1400        )
1401
1402    @override
1403    def into_ani(
1404        self,
1405        target: CSourceWriter,
1406        env: str,
1407        cpp_value: str,
1408        ani_result: str,
1409    ):
1410        target.writelns(
1411            f"{self.ani_type} {ani_result} = ({self.ani_type}){cpp_value};",
1412        )
1413
1414
1415class StringTypeANIInfo(AbstractTypeANIInfo, AbstractAnalysis[StringType]):
1416    def __init__(self, am: AnalysisManager, t: StringType):
1417        super().__init__(am, t)
1418        self.ani_type = ANI_STRING
1419        self.type_desc = "Lstd/core/String;"
1420
1421    @override
1422    def sts_type_in(self, target: StsWriter) -> str:
1423        return "string"
1424
1425    @override
1426    def from_ani(
1427        self,
1428        target: CSourceWriter,
1429        env: str,
1430        ani_value: str,
1431        cpp_result: str,
1432    ):
1433        ani_length = f"{cpp_result}_len"
1434        cpp_tstr = f"{cpp_result}_tstr"
1435        cpp_buffer = f"{cpp_result}_buf"
1436        target.writelns(
1437            f"ani_size {ani_length};",
1438            f"{env}->String_GetUTF8Size({ani_value}, &{ani_length});",
1439            f"TString {cpp_tstr};",
1440            f"char* {cpp_buffer} = tstr_initialize(&{cpp_tstr}, {ani_length} + 1);",
1441            f"{env}->String_GetUTF8({ani_value}, {cpp_buffer}, {ani_length} + 1, &{ani_length});",
1442            f"{cpp_buffer}[{ani_length}] = '\\0';",
1443            f"{cpp_tstr}.length = {ani_length};",
1444            f"::taihe::string {cpp_result} = ::taihe::string({cpp_tstr});",
1445        )
1446
1447    @override
1448    def into_ani(
1449        self,
1450        target: CSourceWriter,
1451        env: str,
1452        cpp_value: str,
1453        ani_result: str,
1454    ):
1455        target.writelns(
1456            f"ani_string {ani_result};",
1457            f"{env}->String_NewUTF8({cpp_value}.c_str(), {cpp_value}.size(), &{ani_result});",
1458        )
1459
1460
1461class OptionalTypeANIInfo(AbstractTypeANIInfo, AbstractAnalysis[OptionalType]):
1462    def __init__(self, am: AnalysisManager, t: OptionalType) -> None:
1463        super().__init__(am, t)
1464        self.am = am
1465        self.t = t
1466        item_ty_ani_info = TypeANIInfo.get(self.am, self.t.item_ty)
1467        self.ani_type = ANI_REF
1468        self.type_desc = item_ty_ani_info.type_desc_boxed
1469
1470    @override
1471    def sts_type_in(self, target: StsWriter) -> str:
1472        item_ty_ani_info = TypeANIInfo.get(self.am, self.t.item_ty)
1473        sts_type = item_ty_ani_info.sts_type_in(target)
1474        return f"({sts_type} | undefined)"
1475
1476    @override
1477    def from_ani(
1478        self,
1479        target: CSourceWriter,
1480        env: str,
1481        ani_value: str,
1482        cpp_result: str,
1483    ):
1484        ani_is_undefined = f"{cpp_result}_flag"
1485        cpp_pointer = f"{cpp_result}_ptr"
1486        cpp_spec = f"{cpp_result}_spec"
1487        item_ty_cpp_info = TypeCppInfo.get(self.am, self.t.item_ty)
1488        target.writelns(
1489            f"ani_boolean {ani_is_undefined};",
1490            f"{item_ty_cpp_info.as_owner}* {cpp_pointer} = nullptr;",
1491            f"{env}->Reference_IsUndefined({ani_value}, &{ani_is_undefined});",
1492        )
1493        with target.indented(
1494            f"if (!{ani_is_undefined}) {{",
1495            f"}};",
1496        ):
1497            item_ty_ani_info = TypeANIInfo.get(self.am, self.t.item_ty)
1498            item_ty_ani_info.from_ani_boxed(target, env, ani_value, cpp_spec)
1499            target.writelns(
1500                f"{cpp_pointer} = new {item_ty_cpp_info.as_owner}(std::move({cpp_spec}));",
1501            )
1502        target.writelns(
1503            f"{self.cpp_info.as_owner} {cpp_result}({cpp_pointer});",
1504        )
1505
1506    @override
1507    def into_ani(
1508        self,
1509        target: CSourceWriter,
1510        env: str,
1511        cpp_value: str,
1512        ani_result: str,
1513    ):
1514        ani_spec = f"{ani_result}_spec"
1515        target.writelns(
1516            f"ani_ref {ani_result};",
1517        )
1518        with target.indented(
1519            f"if (!{cpp_value}) {{",
1520            f"}}",
1521        ):
1522            target.writelns(
1523                f"{env}->GetUndefined(&{ani_result});",
1524            )
1525        with target.indented(
1526            f"else {{",
1527            f"}}",
1528        ):
1529            item_ty_ani_info = TypeANIInfo.get(self.am, self.t.item_ty)
1530            item_ty_ani_info.into_ani_boxed(target, env, f"(*{cpp_value})", ani_spec)
1531            target.writelns(
1532                f"{ani_result} = {ani_spec};",
1533            )
1534
1535
1536class FixedArrayTypeANIInfo(AbstractTypeANIInfo, AbstractAnalysis[ArrayType]):
1537    def __init__(self, am: AnalysisManager, t: ArrayType) -> None:
1538        super().__init__(am, t)
1539        self.am = am
1540        self.t = t
1541        item_ty_ani_info = TypeANIInfo.get(self.am, self.t.item_ty)
1542        self.ani_type = item_ty_ani_info.ani_type.fixedarray
1543        self.type_desc = f"Lescompat/FixedArray;"
1544
1545    @override
1546    def sts_type_in(self, target: StsWriter) -> str:
1547        item_ty_ani_info = TypeANIInfo.get(self.am, self.t.item_ty)
1548        sts_type = item_ty_ani_info.sts_type_in(target)
1549        return f"FixedArray<{sts_type}>"
1550
1551    @override
1552    def from_ani(
1553        self,
1554        target: CSourceWriter,
1555        env: str,
1556        ani_value: str,
1557        cpp_result: str,
1558    ):
1559        item_ty_cpp_info = TypeCppInfo.get(self.am, self.t.item_ty)
1560        ani_size = f"{cpp_result}_size"
1561        cpp_buffer = f"{cpp_result}_buffer"
1562        target.writelns(
1563            f"size_t {ani_size};",
1564            f"{env}->FixedArray_GetLength({ani_value}, &{ani_size});",
1565            f"{item_ty_cpp_info.as_owner}* {cpp_buffer} = reinterpret_cast<{item_ty_cpp_info.as_owner}*>(malloc({ani_size} * sizeof({item_ty_cpp_info.as_owner})));",
1566        )
1567        item_ty_ani_info = TypeANIInfo.get(self.am, self.t.item_ty)
1568        item_ty_ani_info.from_ani_fixedarray(
1569            target, env, ani_size, ani_value, cpp_buffer
1570        )
1571        target.writelns(
1572            f"{self.cpp_info.as_owner} {cpp_result}({cpp_buffer}, {ani_size});",
1573        )
1574
1575    @override
1576    def into_ani(
1577        self,
1578        target: CSourceWriter,
1579        env: str,
1580        cpp_value: str,
1581        ani_result: str,
1582    ):
1583        item_ty_ani_info = TypeANIInfo.get(self.am, self.t.item_ty)
1584        cpp_size = f"{ani_result}_size"
1585        target.writelns(
1586            f"size_t {cpp_size} = {cpp_value}.size();",
1587        )
1588        item_ty_ani_info.into_ani_fixedarray(
1589            target, env, cpp_size, f"{cpp_value}.data()", ani_result
1590        )
1591
1592
1593class ArrayTypeANIInfo(AbstractTypeANIInfo, AbstractAnalysis[ArrayType]):
1594    def __init__(self, am: AnalysisManager, t: ArrayType) -> None:
1595        super().__init__(am, t)
1596        self.am = am
1597        self.t = t
1598        self.ani_type = ANI_ARRAY
1599        self.type_desc = f"Lescompat/Array;"
1600
1601    @override
1602    def sts_type_in(self, target: StsWriter) -> str:
1603        item_ty_ani_info = TypeANIInfo.get(self.am, self.t.item_ty)
1604        sts_type = item_ty_ani_info.sts_type_in(target)
1605        return f"Array<{sts_type}>"
1606
1607    @override
1608    def from_ani(
1609        self,
1610        target: CSourceWriter,
1611        env: str,
1612        ani_value: str,
1613        cpp_result: str,
1614    ):
1615        item_ty_cpp_info = TypeCppInfo.get(self.am, self.t.item_ty)
1616        item_ty_ani_info = TypeANIInfo.get(self.am, self.t.item_ty)
1617        ani_size = f"{cpp_result}_size"
1618        cpp_buffer = f"{cpp_result}_buffer"
1619        ani_item = f"{cpp_buffer}_ani_item"
1620        cpp_item = f"{cpp_buffer}_cpp_item"
1621        cpp_ctr = f"{cpp_buffer}_i"
1622        target.writelns(
1623            f"size_t {ani_size};",
1624            f"{env}->Array_GetLength({ani_value}, &{ani_size});",
1625            f"{item_ty_cpp_info.as_owner}* {cpp_buffer} = reinterpret_cast<{item_ty_cpp_info.as_owner}*>(malloc({ani_size} * sizeof({item_ty_cpp_info.as_owner})));",
1626        )
1627        with target.indented(
1628            f"for (size_t {cpp_ctr} = 0; {cpp_ctr} < {ani_size}; {cpp_ctr}++) {{",
1629            f"}}",
1630        ):
1631            target.writelns(
1632                f"ani_object {ani_item};",
1633                f"{env}->Array_Get_Ref({ani_value}, {cpp_ctr}, reinterpret_cast<ani_ref*>(&{ani_item}));",  # TODO: Array
1634            )
1635            item_ty_ani_info.from_ani_boxed(target, env, ani_item, cpp_item)
1636            target.writelns(
1637                f"new (&{cpp_buffer}[{cpp_ctr}]) {item_ty_ani_info.cpp_info.as_owner}(std::move({cpp_item}));",
1638            )
1639        target.writelns(
1640            f"{self.cpp_info.as_owner} {cpp_result}({cpp_buffer}, {ani_size});",
1641        )
1642
1643    @override
1644    def into_ani(
1645        self,
1646        target: CSourceWriter,
1647        env: str,
1648        cpp_value: str,
1649        ani_result: str,
1650    ):
1651        item_ty_ani_info = TypeANIInfo.get(self.am, self.t.item_ty)
1652        cpp_size = f"{ani_result}_size"
1653        ani_item = f"{ani_result}_item"
1654        ani_undefined = f"{ani_result}_undef"
1655        cpp_ctr = f"{ani_result}_i"
1656        target.writelns(
1657            f"size_t {cpp_size} = {cpp_value}.size();",
1658            f"ani_array_ref {ani_result};",  # TODO: Array
1659            f"ani_ref {ani_undefined};",
1660            f"{env}->GetUndefined(&{ani_undefined});",
1661            f'{env}->Array_New_Ref(TH_ANI_FIND_CLASS({env}, "Lstd/core/Object;"), {cpp_size}, {ani_undefined}, &{ani_result});',  # TODO: Array
1662        )
1663        with target.indented(
1664            f"for (size_t {cpp_ctr} = 0; {cpp_ctr} < {cpp_size}; {cpp_ctr}++) {{",
1665            f"}}",
1666        ):
1667            item_ty_ani_info.into_ani_boxed(
1668                target, env, f"{cpp_value}[{cpp_ctr}]", ani_item
1669            )
1670            target.writelns(
1671                f"{env}->Array_Set_Ref({ani_result}, {cpp_ctr}, {ani_item});",  # TODO: Array
1672            )
1673
1674
1675class ArrayBufferTypeANIInfo(AbstractTypeANIInfo, AbstractAnalysis[ArrayType]):
1676    def __init__(self, am: AnalysisManager, t: ArrayType) -> None:
1677        super().__init__(am, t)
1678        self.am = am
1679        self.t = t
1680        if not isinstance(t.item_ty, ScalarType) or t.item_ty.kind not in (
1681            ScalarKind.I8,
1682            ScalarKind.U8,
1683        ):
1684            raise_adhoc_error(
1685                am,
1686                "@arraybuffer only supports Array<i8> or Array<i8>",
1687                t.ty_ref.loc,
1688            )
1689        self.ani_type = ANI_ARRAYBUFFER
1690        self.type_desc = "Lescompat/ArrayBuffer;"
1691
1692    @override
1693    def sts_type_in(self, target: StsWriter) -> str:
1694        return "ArrayBuffer"
1695
1696    @override
1697    def from_ani(
1698        self,
1699        target: CSourceWriter,
1700        env: str,
1701        ani_value: str,
1702        cpp_result: str,
1703    ):
1704        item_ty_cpp_info = TypeCppInfo.get(self.am, self.t.item_ty)
1705        ani_data = f"{cpp_result}_data"
1706        ani_length = f"{cpp_result}_length"
1707        target.writelns(
1708            f"char* {ani_data} = nullptr;",
1709            f"size_t {ani_length} = 0;",
1710            f"{env}->ArrayBuffer_GetInfo({ani_value}, reinterpret_cast<void**>(&{ani_data}), &{ani_length});",
1711            f"{self.cpp_info.as_param} {cpp_result}(reinterpret_cast<{item_ty_cpp_info.as_owner}*>({ani_data}), {ani_length});",
1712        )
1713
1714    @override
1715    def into_ani(
1716        self,
1717        target: CSourceWriter,
1718        env: str,
1719        cpp_value: str,
1720        ani_result: str,
1721    ):
1722        ani_data = f"{ani_result}_data"
1723        target.writelns(
1724            f"char* {ani_data} = nullptr;",
1725            f"ani_arraybuffer {ani_result};",
1726            f"{env}->CreateArrayBuffer({cpp_value}.size(), reinterpret_cast<void**>(&{ani_data}), &{ani_result});",
1727            f"memcpy({ani_data}, {cpp_value}.data(), {cpp_value}.size());",
1728        )
1729
1730
1731class TypedArrayTypeANIInfo(AbstractTypeANIInfo, AbstractAnalysis[ArrayType]):
1732    def __init__(self, am: AnalysisManager, t: ArrayType):
1733        super().__init__(am, t)
1734        self.am = am
1735        self.t = t
1736        if (
1737            not isinstance(t.item_ty, ScalarType)
1738            or (
1739                sts_type := {
1740                    ScalarKind.F32: "Float32Array",
1741                    ScalarKind.F64: "Float64Array",
1742                    ScalarKind.I8: "Int8Array",
1743                    ScalarKind.I16: "Int16Array",
1744                    ScalarKind.I32: "Int32Array",
1745                    ScalarKind.I64: "BigInt64Array",
1746                    ScalarKind.U8: "Uint8Array",
1747                    ScalarKind.U16: "Uint16Array",
1748                    ScalarKind.U32: "Uint32Array",
1749                    ScalarKind.U64: "BigUint64Array",
1750                }.get(t.item_ty.kind)
1751            )
1752            is None
1753        ):
1754            raise_adhoc_error(
1755                am,
1756                f"@typedarray does not supports Array<{t.item_ty.ty_ref.text}>",
1757                t.ty_ref.loc,
1758            )
1759            self.sts_type = "TypedArray"
1760        else:
1761            self.sts_type = sts_type
1762        self.ani_type = ANI_OBJECT
1763        self.type_desc = f"Lescompat/{self.sts_type};"
1764
1765    @override
1766    def sts_type_in(self, target: StsWriter) -> str:
1767        return self.sts_type
1768
1769    @override
1770    def from_ani(
1771        self,
1772        target: CSourceWriter,
1773        env: str,
1774        ani_value: str,
1775        cpp_result: str,
1776    ):
1777        item_ty_cpp_info = TypeCppInfo.get(self.am, self.t.item_ty)
1778        ani_byte_length = f"{cpp_result}_bylen"
1779        ani_byte_offset = f"{cpp_result}_byoff"
1780        ani_arrbuf = f"{cpp_result}_arrbuf"
1781        ani_data = f"{cpp_result}_data"
1782        ani_length = f"{cpp_result}_length"
1783        target.writelns(
1784            f"ani_double {ani_byte_length};",
1785            f"ani_double {ani_byte_offset};",
1786            f"ani_arraybuffer {ani_arrbuf};",
1787            f'{env}->Object_GetPropertyByName_Double({ani_value}, "byteLength", &{ani_byte_length});',
1788            f'{env}->Object_GetPropertyByName_Double({ani_value}, "byteOffset", &{ani_byte_offset});',
1789            f'{env}->Object_GetPropertyByName_Ref({ani_value}, "buffer", reinterpret_cast<ani_ref*>(&{ani_arrbuf}));',
1790            f"char* {ani_data} = nullptr;",
1791            f"size_t {ani_length} = 0;",
1792            f"{env}->ArrayBuffer_GetInfo({ani_arrbuf}, reinterpret_cast<void**>(&{ani_data}), &{ani_length});",
1793            f"{self.cpp_info.as_param} {cpp_result}(reinterpret_cast<{item_ty_cpp_info.as_owner}*>({ani_data} + (size_t){ani_byte_offset}), (size_t){ani_byte_length} / (sizeof({item_ty_cpp_info.as_owner}) / sizeof(char)));",
1794        )
1795
1796    @override
1797    def into_ani(
1798        self,
1799        target: CSourceWriter,
1800        env: str,
1801        cpp_value: str,
1802        ani_result: str,
1803    ):
1804        item_ty_cpp_info = TypeCppInfo.get(self.am, self.t.item_ty)
1805        ani_data = f"{ani_result}_data"
1806        ani_arrbuf = f"{ani_result}_arrbuf"
1807        ani_byte_length = f"{ani_result}_bylen"
1808        ani_byte_offset = f"{ani_result}_byoff"
1809        target.writelns(
1810            f"char* {ani_data} = nullptr;",
1811            f"ani_arraybuffer {ani_arrbuf};",
1812            f"{env}->CreateArrayBuffer({cpp_value}.size() * (sizeof({item_ty_cpp_info.as_owner}) / sizeof(char)), reinterpret_cast<void**>(&{ani_data}), &{ani_arrbuf});",
1813            f"memcpy({ani_data}, {cpp_value}.data(), {cpp_value}.size() * (sizeof({item_ty_cpp_info.as_owner}) / sizeof(char)));",
1814            f"ani_ref {ani_byte_length};",
1815            f"{env}->GetUndefined(&{ani_byte_length});",
1816            f"ani_ref {ani_byte_offset};",
1817            f"{env}->GetUndefined(&{ani_byte_offset});",
1818            f"ani_object {ani_result};",
1819            f'{env}->Object_New(TH_ANI_FIND_CLASS({env}, "{self.type_desc}"), TH_ANI_FIND_CLASS_METHOD({env}, "{self.type_desc}", "<ctor>", "Lescompat/ArrayBuffer;Lstd/core/Double;Lstd/core/Double;:V"), &{ani_result}, {ani_arrbuf}, {ani_byte_length}, {ani_byte_offset});',
1820        )
1821
1822
1823class BigIntTypeANIInfo(AbstractTypeANIInfo, AbstractAnalysis[ArrayType]):
1824    def __init__(self, am: AnalysisManager, t: ArrayType) -> None:
1825        super().__init__(am, t)
1826        self.am = am
1827        self.t = t
1828        if not isinstance(t.item_ty, ScalarType) or t.item_ty.kind not in (
1829            ScalarKind.I8,
1830            ScalarKind.I16,
1831            ScalarKind.I32,
1832            ScalarKind.I64,
1833            ScalarKind.U8,
1834            ScalarKind.U16,
1835            ScalarKind.U32,
1836            ScalarKind.U64,
1837        ):
1838            raise_adhoc_error(
1839                am,
1840                f"@bigint does not supports Array<{t.item_ty.ty_ref.text}>",
1841                t.ty_ref.loc,
1842            )
1843        self.ani_type = ANI_OBJECT
1844        self.type_desc = "Lescompat/BigInt;"
1845
1846    @override
1847    def sts_type_in(self, target: StsWriter) -> str:
1848        return "BigInt"
1849
1850    @override
1851    def from_ani(
1852        self,
1853        target: CSourceWriter,
1854        env: str,
1855        ani_value: str,
1856        cpp_result: str,
1857    ):
1858        item_ty_cpp_info = TypeCppInfo.get(self.am, self.t.item_ty)
1859        pkg_ani_info = PackageANIInfo.get(self.am, self.t.ty_ref.parent_pkg)
1860        ani_arrbuf = f"{cpp_result}_arrbuf"
1861        ani_data = f"{cpp_result}_data"
1862        ani_length = f"{cpp_result}_length"
1863        target.writelns(
1864            f"ani_arraybuffer {ani_arrbuf};",
1865            f'{env}->Function_Call_Ref(TH_ANI_FIND_MODULE_FUNCTION({env}, "{pkg_ani_info.ns.module.impl_desc}", "__fromBigIntToArrayBuffer", nullptr), reinterpret_cast<ani_ref*>(&{ani_arrbuf}), {ani_value}, sizeof({item_ty_cpp_info.as_owner}) / sizeof(char));'
1866            f"char* {ani_data} = nullptr;",
1867            f"size_t {ani_length} = 0;",
1868            f"{env}->ArrayBuffer_GetInfo({ani_arrbuf}, reinterpret_cast<void**>(&{ani_data}), &{ani_length});",
1869            f"{self.cpp_info.as_param} {cpp_result}(reinterpret_cast<{item_ty_cpp_info.as_owner}*>({ani_data}), {ani_length} / (sizeof({item_ty_cpp_info.as_owner}) / sizeof(char)));",
1870        )
1871
1872    @override
1873    def into_ani(
1874        self,
1875        target: CSourceWriter,
1876        env: str,
1877        cpp_value: str,
1878        ani_result: str,
1879    ):
1880        item_ty_cpp_info = TypeCppInfo.get(self.am, self.t.item_ty)
1881        pkg_ani_info = PackageANIInfo.get(self.am, self.t.ty_ref.parent_pkg)
1882        ani_data = f"{ani_result}_data"
1883        ani_arrbuf = f"{ani_result}_arrbuf"
1884        target.writelns(
1885            f"char* {ani_data} = nullptr;",
1886            f"ani_arraybuffer {ani_arrbuf};",
1887            f"{env}->CreateArrayBuffer({cpp_value}.size() * (sizeof({item_ty_cpp_info.as_owner}) / sizeof(char)), reinterpret_cast<void**>(&{ani_data}), &{ani_arrbuf});",
1888            f"memcpy({ani_data}, {cpp_value}.data(), {cpp_value}.size() * (sizeof({item_ty_cpp_info.as_owner}) / sizeof(char)));",
1889            f"ani_object {ani_result};",
1890            f'{env}->Function_Call_Ref(TH_ANI_FIND_MODULE_FUNCTION({env}, "{pkg_ani_info.ns.module.impl_desc}", "__fromArrayBufferToBigInt", nullptr), reinterpret_cast<ani_ref*>(&{ani_result}), {ani_arrbuf});',
1891        )
1892
1893
1894class RecordTypeANIInfo(AbstractTypeANIInfo, AbstractAnalysis[MapType]):
1895    def __init__(self, am: AnalysisManager, t: MapType) -> None:
1896        super().__init__(am, t)
1897        self.am = am
1898        self.t = t
1899        self.ani_type = ANI_OBJECT
1900        self.type_desc = "Lescompat/Record;"
1901
1902    @override
1903    def sts_type_in(self, target: StsWriter) -> str:
1904        key_ty_ani_info = TypeANIInfo.get(self.am, self.t.key_ty)
1905        val_ty_ani_info = TypeANIInfo.get(self.am, self.t.val_ty)
1906        key_sts_type = key_ty_ani_info.sts_type_in(target)
1907        val_sts_type = val_ty_ani_info.sts_type_in(target)
1908        return f"Record<{key_sts_type}, {val_sts_type}>"
1909
1910    @override
1911    def from_ani(
1912        self,
1913        target: CSourceWriter,
1914        env: str,
1915        ani_value: str,
1916        cpp_result: str,
1917    ):
1918        ani_iter = f"{cpp_result}_iter"
1919        ani_item = f"{cpp_result}_item"
1920        ani_next = f"{cpp_result}_next"
1921        ani_done = f"{cpp_result}_done"
1922        ani_key = f"{cpp_result}_ani_key"
1923        ani_val = f"{cpp_result}_ani_val"
1924        cpp_key = f"{cpp_result}_cpp_key"
1925        cpp_val = f"{cpp_result}_cpp_val"
1926        key_ty_ani_info = TypeANIInfo.get(self.am, self.t.key_ty)
1927        val_ty_ani_info = TypeANIInfo.get(self.am, self.t.val_ty)
1928        target.writelns(
1929            f"ani_ref {ani_iter};",
1930            f'{env}->Object_CallMethod_Ref({ani_value}, TH_ANI_FIND_CLASS_METHOD({env}, "Lescompat/Record;", "$_iterator", nullptr), &{ani_iter});',
1931            f"{self.cpp_info.as_owner} {cpp_result};",
1932        )
1933        with target.indented(
1934            f"while (true) {{",
1935            f"}}",
1936        ):
1937            target.writelns(
1938                f"ani_ref {ani_next};",
1939                f"ani_boolean {ani_done};",
1940                f'{env}->Object_CallMethod_Ref(static_cast<ani_object>({ani_iter}), TH_ANI_FIND_CLASS_METHOD({env}, "Lescompat/MapIterator;", "next", nullptr), &{ani_next});',
1941                f'{env}->Object_GetField_Boolean(static_cast<ani_object>({ani_next}), TH_ANI_FIND_CLASS_FIELD({env}, "Lescompat/IteratorResult;", "done"), &{ani_done});',
1942            )
1943            with target.indented(
1944                f"if ({ani_done}) {{;",
1945                f"}};",
1946            ):
1947                target.writelns(
1948                    f"break;",
1949                )
1950            target.writelns(
1951                f"ani_ref {ani_item};",
1952                f'{env}->Object_GetField_Ref(static_cast<ani_object>({ani_next}),  TH_ANI_FIND_CLASS_FIELD({env}, "Lescompat/IteratorResult;", "value"), &{ani_item});',
1953                f"ani_ref {ani_key};",
1954                f"{env}->TupleValue_GetItem_Ref(static_cast<ani_tuple_value>({ani_item}), 0, &{ani_key});",
1955                f"ani_ref {ani_val};",
1956                f"{env}->TupleValue_GetItem_Ref(static_cast<ani_tuple_value>({ani_item}), 1, &{ani_val});",
1957            )
1958            key_ty_ani_info.from_ani_boxed(target, env, ani_key, cpp_key)
1959            val_ty_ani_info.from_ani_boxed(target, env, ani_val, cpp_val)
1960            target.writelns(
1961                f"{cpp_result}.emplace({cpp_key}, {cpp_val});",
1962            )
1963
1964    @override
1965    def into_ani(
1966        self,
1967        target: CSourceWriter,
1968        env: str,
1969        cpp_value: str,
1970        ani_result: str,
1971    ):
1972        key_ty_ani_info = TypeANIInfo.get(self.am, self.t.key_ty)
1973        val_ty_ani_info = TypeANIInfo.get(self.am, self.t.val_ty)
1974        cpp_key = f"{ani_result}_cpp_key"
1975        cpp_val = f"{ani_result}_cpp_val"
1976        ani_key = f"{ani_result}_ani_key"
1977        ani_val = f"{ani_result}_ani_val"
1978        target.writelns(
1979            f"ani_object {ani_result};",
1980            f'{env}->Object_New(TH_ANI_FIND_CLASS({env}, "{self.type_desc}"), TH_ANI_FIND_CLASS_METHOD({env}, "{self.type_desc}", "<ctor>", nullptr), &{ani_result});',
1981        )
1982        with target.indented(
1983            f"for (const auto& [{cpp_key}, {cpp_val}] : {cpp_value}) {{",
1984            f"}}",
1985        ):
1986            key_ty_ani_info.into_ani_boxed(target, env, cpp_key, ani_key)
1987            val_ty_ani_info.into_ani_boxed(target, env, cpp_val, ani_val)
1988            target.writelns(
1989                f'{env}->Object_CallMethod_Void({ani_result}, TH_ANI_FIND_CLASS_METHOD({env}, "Lescompat/Record;", "$_set", nullptr), {ani_key}, {ani_val});',
1990            )
1991
1992
1993class MapTypeANIInfo(AbstractTypeANIInfo, AbstractAnalysis[MapType]):
1994    def __init__(self, am: AnalysisManager, t: MapType) -> None:
1995        super().__init__(am, t)
1996        self.am = am
1997        self.t = t
1998        self.ani_type = ANI_OBJECT
1999        self.type_desc = "Lescompat/Map;"
2000        raise_adhoc_error(
2001            am,
2002            f"Map is not supported yet, "
2003            f"if you want to use TS Record type, "
2004            f"please use `@record Map<{self.t.key_ty.ty_ref.text}, {self.t.val_ty.ty_ref.text}>`",
2005            self.t.ty_ref.loc,
2006        )
2007
2008    @override
2009    def sts_type_in(self, target: StsWriter) -> str:
2010        key_ty_ani_info = TypeANIInfo.get(self.am, self.t.key_ty)
2011        val_ty_ani_info = TypeANIInfo.get(self.am, self.t.val_ty)
2012        key_sts_type = key_ty_ani_info.sts_type_in(target)
2013        val_sts_type = val_ty_ani_info.sts_type_in(target)
2014        return f"Map<{key_sts_type}, {val_sts_type}>"
2015
2016    @override
2017    def from_ani(
2018        self,
2019        target: CSourceWriter,
2020        env: str,
2021        ani_value: str,
2022        cpp_result: str,
2023    ):
2024        target.writelns(
2025            f"{self.cpp_info.as_owner} {cpp_result};",
2026        )
2027
2028    @override
2029    def into_ani(
2030        self,
2031        target: CSourceWriter,
2032        env: str,
2033        cpp_value: str,
2034        ani_result: str,
2035    ):
2036        target.writelns(
2037            f"ani_object {ani_result} = {{}};",
2038        )
2039
2040
2041class CallbackTypeANIInfo(AbstractTypeANIInfo, AbstractAnalysis[CallbackType]):
2042    def __init__(self, am: AnalysisManager, t: CallbackType) -> None:
2043        super().__init__(am, t)
2044        self.am = am
2045        self.t = t
2046        self.ani_type = ANI_FN_OBJECT
2047        self.type_desc = f"Lstd/core/Function{len(t.params_ty)};"
2048
2049    @override
2050    def sts_type_in(self, target: StsWriter) -> str:
2051        params_ty_sts = []
2052        for index, param_ty in enumerate(self.t.params_ty):
2053            param_ty_sts_info = TypeANIInfo.get(self.am, param_ty)
2054            prm_sts_type = param_ty_sts_info.sts_type_in(target)
2055            params_ty_sts.append(f"arg_{index}: {prm_sts_type}")
2056        params_ty_sts_str = ", ".join(params_ty_sts)
2057        if return_ty := self.t.return_ty:
2058            return_ty_sts_info = TypeANIInfo.get(self.am, return_ty)
2059            ret_sts_type = return_ty_sts_info.sts_type_in(target)
2060            return_ty_sts = ret_sts_type
2061        else:
2062            return_ty_sts = "void"
2063        return f"(({params_ty_sts_str}) => {return_ty_sts})"
2064
2065    @override
2066    def from_ani(
2067        self,
2068        target: CSourceWriter,
2069        env: str,
2070        ani_value: str,
2071        cpp_result: str,
2072    ):
2073        cpp_impl_class = f"{cpp_result}_cpp_impl_t"
2074        with target.indented(
2075            f"struct {cpp_impl_class} : ::taihe::dref_guard {{",
2076            f"}};",
2077        ):
2078            target.writelns(
2079                f"{cpp_impl_class}(ani_env* env, ani_ref val) : ::taihe::dref_guard(env, val) {{}}",
2080            )
2081            inner_cpp_params = []
2082            inner_ani_args = []
2083            inner_cpp_args = []
2084            for index, param_ty in enumerate(self.t.params_ty):
2085                inner_cpp_arg = f"cpp_arg_{index}"
2086                inner_ani_arg = f"ani_arg_{index}"
2087                param_ty_cpp_info = TypeCppInfo.get(self.am, param_ty)
2088                inner_cpp_params.append(f"{param_ty_cpp_info.as_param} {inner_cpp_arg}")
2089                inner_ani_args.append(inner_ani_arg)
2090                inner_cpp_args.append(inner_cpp_arg)
2091            cpp_params_str = ", ".join(inner_cpp_params)
2092            if return_ty := self.t.return_ty:
2093                return_ty_cpp_info = TypeCppInfo.get(self.am, return_ty)
2094                return_ty_as_owner = return_ty_cpp_info.as_owner
2095            else:
2096                return_ty_as_owner = "void"
2097            with target.indented(
2098                f"{return_ty_as_owner} operator()({cpp_params_str}) {{",
2099                f"}}",
2100            ):
2101                target.writelns(
2102                    f"::taihe::env_guard guard;",
2103                    f"ani_env *env = guard.get_env();",
2104                )
2105                for inner_ani_arg, inner_cpp_arg, param_ty in zip(
2106                    inner_ani_args, inner_cpp_args, self.t.params_ty, strict=True
2107                ):
2108                    param_ty_ani_info = TypeANIInfo.get(self.am, param_ty)
2109                    param_ty_ani_info.into_ani_boxed(
2110                        target, "env", inner_cpp_arg, inner_ani_arg
2111                    )
2112                inner_ani_args_str = ", ".join(inner_ani_args)
2113                if return_ty := self.t.return_ty:
2114                    inner_ani_res = "ani_result"
2115                    inner_cpp_res = "cpp_result"
2116                    target.writelns(
2117                        f"ani_ref ani_argv[] = {{{inner_ani_args_str}}};",
2118                        f"ani_ref {inner_ani_res};",
2119                        f"env->FunctionalObject_Call(static_cast<ani_fn_object>(this->ref), {len(self.t.params_ty)}, ani_argv, &{inner_ani_res});",
2120                    )
2121                    return_ty_ani_info = TypeANIInfo.get(self.am, return_ty)
2122                    return_ty_ani_info.from_ani_boxed(
2123                        target, "env", inner_ani_res, inner_cpp_res
2124                    )
2125                    target.writelns(
2126                        f"return {inner_cpp_res};",
2127                    )
2128                else:
2129                    inner_ani_res = "ani_result"
2130                    target.writelns(
2131                        f"ani_ref ani_argv[] = {{{inner_ani_args_str}}};",
2132                        f"ani_ref {inner_ani_res};",
2133                        f"env->FunctionalObject_Call(static_cast<ani_fn_object>(this->ref), {len(self.t.params_ty)}, ani_argv, &{inner_ani_res});",
2134                        f"return;",
2135                    )
2136            with target.indented(
2137                f"uintptr_t getGlobalReference() const {{",
2138                f"}}",
2139            ):
2140                target.writelns(
2141                    f"return reinterpret_cast<uintptr_t>(this->ref);",
2142                )
2143        target.writelns(
2144            f"{self.cpp_info.as_owner} {cpp_result} = ::taihe::make_holder<{cpp_impl_class}, {self.cpp_info.as_owner}, ::taihe::platform::ani::AniObject>({env}, {ani_value});",
2145        )
2146
2147    @override
2148    def into_ani(
2149        self,
2150        target: CSourceWriter,
2151        env: str,
2152        cpp_value: str,
2153        ani_result: str,
2154    ):
2155        # TODO: Callback into ani
2156        target.writelns(
2157            f"ani_fn_object {ani_result} = {{}};",
2158        )
2159
2160
2161class TypeANIInfo(TypeVisitor[AbstractTypeANIInfo]):
2162    def __init__(self, am: AnalysisManager):
2163        self.am = am
2164
2165    @staticmethod
2166    def get(am: AnalysisManager, t: Type) -> AbstractTypeANIInfo:
2167        return TypeANIInfo(am).handle_type(t)
2168
2169    @override
2170    def visit_enum_type(self, t: EnumType) -> AbstractTypeANIInfo:
2171        return EnumTypeANIInfo.get(self.am, t)
2172
2173    @override
2174    def visit_union_type(self, t: UnionType) -> AbstractTypeANIInfo:
2175        return UnionTypeANIInfo.get(self.am, t)
2176
2177    @override
2178    def visit_struct_type(self, t: StructType) -> AbstractTypeANIInfo:
2179        return StructTypeANIInfo.get(self.am, t)
2180
2181    @override
2182    def visit_iface_type(self, t: IfaceType) -> AbstractTypeANIInfo:
2183        return IfaceTypeANIInfo.get(self.am, t)
2184
2185    @override
2186    def visit_scalar_type(self, t: ScalarType) -> AbstractTypeANIInfo:
2187        return ScalarTypeANIInfo.get(self.am, t)
2188
2189    @override
2190    def visit_string_type(self, t: StringType) -> AbstractTypeANIInfo:
2191        return StringTypeANIInfo.get(self.am, t)
2192
2193    @override
2194    def visit_array_type(self, t: ArrayType) -> AbstractTypeANIInfo:
2195        if t.ty_ref.attrs.get("bigint"):
2196            return BigIntTypeANIInfo.get(self.am, t)
2197        if t.ty_ref.attrs.get("typedarray"):
2198            return TypedArrayTypeANIInfo.get(self.am, t)
2199        if t.ty_ref.attrs.get("arraybuffer"):
2200            return ArrayBufferTypeANIInfo.get(self.am, t)
2201        if t.ty_ref.attrs.get("fixedarray"):
2202            return FixedArrayTypeANIInfo.get(self.am, t)
2203        return ArrayTypeANIInfo.get(self.am, t)
2204
2205    @override
2206    def visit_optional_type(self, t: OptionalType) -> AbstractTypeANIInfo:
2207        return OptionalTypeANIInfo.get(self.am, t)
2208
2209    @override
2210    def visit_opaque_type(self, t: OpaqueType) -> AbstractTypeANIInfo:
2211        return OpaqueTypeANIInfo.get(self.am, t)
2212
2213    @override
2214    def visit_map_type(self, t: MapType) -> AbstractTypeANIInfo:
2215        if t.ty_ref.attrs.get("record"):
2216            return RecordTypeANIInfo.get(self.am, t)
2217        return MapTypeANIInfo.get(self.am, t)
2218
2219    @override
2220    def visit_callback_type(self, t: CallbackType) -> AbstractTypeANIInfo:
2221        return CallbackTypeANIInfo.get(self.am, t)