mirror of https://github.com/zeldaret/tp.git
191 lines
7.4 KiB
Python
191 lines
7.4 KiB
Python
import libdemangle
|
|
|
|
from dataclasses import dataclass, field
|
|
from typing import List
|
|
|
|
from ...builder import AsyncBuilder
|
|
from ... import util
|
|
from ...types import *
|
|
from ..symbol import *
|
|
|
|
special_func_no_return = set([
|
|
"ct",
|
|
"dt"
|
|
])
|
|
|
|
|
|
@dataclass(eq=False)
|
|
class Function(Symbol):
|
|
return_type: Type = None
|
|
argument_types: List[Type] = field(default_factory=list)
|
|
func_name: libdemangle.QualifiedName = None
|
|
special_func_name: str = None
|
|
func_is_const: bool = False
|
|
template_index: int = -1
|
|
asm: bool = False
|
|
|
|
@property
|
|
def label(self):
|
|
return self.identifier.label
|
|
|
|
def function_name(self,
|
|
original: bool = False,
|
|
full_qualified_name: bool = True,
|
|
without_template: bool = False,
|
|
specialize_templates: bool = False):
|
|
|
|
if not self.func_name or original:
|
|
return self.identifier.label
|
|
|
|
name = self.func_name
|
|
if self.special_func_name and self.has_class and specialize_templates:
|
|
# fix up the constructor and destructor if the function is template specialized
|
|
special_name = None
|
|
if self.special_func_name == "ct":
|
|
special_name = name.second_last.to_str(specialize_templates=specialize_templates,
|
|
without_template=without_template)
|
|
if self.special_func_name == "dt":
|
|
special_name = "~" + name.second_last.to_str(specialize_templates=specialize_templates,
|
|
without_template=without_template)
|
|
|
|
if special_name:
|
|
name = NamedType(
|
|
self.func_name.names[:-1] + [ClassName(special_name, [])])
|
|
|
|
if full_qualified_name:
|
|
return name.to_str(specialize_templates=specialize_templates,
|
|
without_template=without_template)
|
|
else:
|
|
return name.last.to_str(specialize_templates=specialize_templates,
|
|
without_template=without_template)
|
|
|
|
def is_demangled(self):
|
|
return self.func_name != None
|
|
|
|
def valid_reference(self, addr):
|
|
return addr % 4 == 0
|
|
|
|
def cpp_reference(self, accessor, addr):
|
|
if addr == self.addr:
|
|
return self.label
|
|
else:
|
|
offset = addr - self.addr
|
|
return f"(((char*){self.label})+0x{offset:X})"
|
|
|
|
def relocation_symbols(self, context, symbol_table, section):
|
|
symbols = section.relocations_in_range(symbol_table, self.start, self.end)
|
|
return symbols
|
|
|
|
def types(self):
|
|
return set()
|
|
|
|
@property
|
|
def has_class(self):
|
|
return self.func_name and self.func_name.has_class
|
|
|
|
@property
|
|
def has_template(self):
|
|
return self.func_name and self.func_name.has_template
|
|
|
|
async def export_function_header(self, exporter,
|
|
builder: AsyncBuilder,
|
|
forward: bool,
|
|
original: bool = False,
|
|
full_qualified_name: bool = True,
|
|
specialize_templates: bool = False,
|
|
without_template: bool = False,
|
|
comment_arguments: bool = False,
|
|
template_args: List[str] = None):
|
|
# prints internal references for the function
|
|
if False:
|
|
if not forward:
|
|
refs = self.internal_references(exporter.context, exporter.gst)
|
|
await builder.write(f"/* internal references (count {len(refs)})")
|
|
for ref in refs:
|
|
await builder.write(f"// {ref.addr:08X} {ref.label}")
|
|
|
|
declspec = "extern \"C\" "
|
|
if not original and self.is_demangled():
|
|
declspec = ""
|
|
|
|
if self._section == ".init":
|
|
declspec = "SECTION_INIT "
|
|
|
|
await builder.write_nonewline(f"{declspec}")
|
|
if self.asm and not forward:
|
|
await builder.write_nonewline(f"asm ")
|
|
|
|
if full_qualified_name and not self.has_class:
|
|
# this symbol is only referenced by other symbol in the same translation unit
|
|
if self.is_static:
|
|
await builder.write_nonewline(f"static ")
|
|
|
|
if not self.special_func_name in special_func_no_return or original:
|
|
return_type = self.return_type
|
|
if not self.return_type:
|
|
return_type = VOID
|
|
|
|
await builder.write_nonewline(f"{return_type.type(specialize_templates,without_template)} ")
|
|
await builder.write_nonewline(f"{self.function_name(original, full_qualified_name, without_template, specialize_templates)}")
|
|
|
|
arg_type = ""
|
|
if not original and self.is_demangled():
|
|
if forward:
|
|
arg_type = ", ".join([x.type(specialize_templates,without_template) for x in self.argument_types])
|
|
else:
|
|
arg_type = ", ".join([x.decl(f"param_{i}",specialize_templates,without_template) for i, x in zip(
|
|
range(len(self.argument_types)), self.argument_types)])
|
|
|
|
if template_args:
|
|
args = ", ".join(template_args)
|
|
await builder.write_nonewline(f"<{args}>")
|
|
|
|
if comment_arguments:
|
|
arg_type = f"/* {arg_type} */"
|
|
await builder.write_nonewline(f"({arg_type})")
|
|
if not original and self.has_class and self.func_is_const:
|
|
await builder.write_nonewline(f" const")
|
|
|
|
async def export_forward_references(self, exporter,
|
|
builder: AsyncBuilder,
|
|
c_export: bool = False,
|
|
full_qualified_name: bool = True,
|
|
template_args: List[str] = None):
|
|
if not template_args:
|
|
template_args = []
|
|
|
|
if c_export:
|
|
# export unmangled name
|
|
await self.export_function_header(exporter, builder, forward=True, original=True)
|
|
await builder.write(f";")
|
|
return
|
|
|
|
if full_qualified_name:
|
|
if self.is_demangled():
|
|
# forward references are not written for class functions
|
|
if not self.has_class:
|
|
await self.export_function_header(exporter, builder, forward=True, full_qualified_name=True, specialize_templates=True)
|
|
await builder.write(f";")
|
|
else:
|
|
# export the function as a class method
|
|
await self.export_function_header(exporter, builder, forward=True, full_qualified_name=False, template_args=template_args)
|
|
await builder.write(f";")
|
|
|
|
async def export_function_body(self, exporter, builder: AsyncBuilder):
|
|
assert False
|
|
|
|
async def export_declaration(self, exporter, builder: AsyncBuilder):
|
|
assert self.padding == 0
|
|
|
|
if self.alignment:
|
|
await builder.write("#pragma push")
|
|
await builder.write(f"#pragma function_align {self.alignment}")
|
|
|
|
await self.export_function_header(exporter, builder, forward=False, specialize_templates=self.has_template)
|
|
await self.export_function_body(exporter, builder)
|
|
|
|
if self.alignment:
|
|
await builder.write("#pragma pop")
|
|
await builder.write("")
|
|
|