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)