No codegen doubly-linked list #8
11
Makefile
11
Makefile
@@ -1,4 +1,4 @@
|
|||||||
.PHONY: help full base os prng testing uuid all clean builddir build-test run-test codegen install build-lib ccodegen
|
.PHONY: help full base os prng testing uuid all clean builddir build-test run-test install build-lib ccodegen
|
||||||
|
|
||||||
# External variables
|
# External variables
|
||||||
CC = clang
|
CC = clang
|
||||||
@@ -7,7 +7,6 @@ AR = ar
|
|||||||
BUILD_TYPE = Debug
|
BUILD_TYPE = Debug
|
||||||
BUILD_DIR = libwapp-build/$(PLATFORM)-$(BUILD_TYPE)
|
BUILD_DIR = libwapp-build/$(PLATFORM)-$(BUILD_TYPE)
|
||||||
INSTALL_PREFIX = dist
|
INSTALL_PREFIX = dist
|
||||||
CODEGEN_INPUT = ""
|
|
||||||
RUNTIME_ASSERT = true
|
RUNTIME_ASSERT = true
|
||||||
|
|
||||||
# Internal variables
|
# Internal variables
|
||||||
@@ -95,7 +94,7 @@ ifeq ($(KERNEL), Darwin)
|
|||||||
ECHO_E = echo
|
ECHO_E = echo
|
||||||
endif
|
endif
|
||||||
|
|
||||||
all: clean builddir codegen run-c-test full run-cc-test
|
all: clean builddir run-c-test full run-cc-test
|
||||||
|
|
||||||
help:
|
help:
|
||||||
@$(ECHO_E) "$(BOLD)$(BLUE)Available build variables:$(RESET)"
|
@$(ECHO_E) "$(BOLD)$(BLUE)Available build variables:$(RESET)"
|
||||||
@@ -105,7 +104,6 @@ help:
|
|||||||
@$(ECHO_E) " $(GREEN)BUILD_TYPE$(RESET) Build type $(MAGENTA)[Debug | RelWithDebInfo | Release] $(YELLOW)(Default: Debug)$(RESET)."
|
@$(ECHO_E) " $(GREEN)BUILD_TYPE$(RESET) Build type $(MAGENTA)[Debug | RelWithDebInfo | Release] $(YELLOW)(Default: Debug)$(RESET)."
|
||||||
@$(ECHO_E) " $(GREEN)BUILD_DIR$(RESET) Directory where build files will be written."
|
@$(ECHO_E) " $(GREEN)BUILD_DIR$(RESET) Directory where build files will be written."
|
||||||
@$(ECHO_E) " $(GREEN)INSTALL_PREFIX$(RESET) Prefix where library and include files will be installed."
|
@$(ECHO_E) " $(GREEN)INSTALL_PREFIX$(RESET) Prefix where library and include files will be installed."
|
||||||
@$(ECHO_E) " $(GREEN)CODEGEN_INPUT$(RESET) Input file for code generation (See $(CYAN)codegen_custom_data_example.json$(RESET) for an example)."
|
|
||||||
@$(ECHO_E) " $(GREEN)RUNTIME_ASSERT$(RESET) Whether runtime asserts are enabled $(MAGENTA)[true | false] $(YELLOW)(Default: true)$(RESET)."
|
@$(ECHO_E) " $(GREEN)RUNTIME_ASSERT$(RESET) Whether runtime asserts are enabled $(MAGENTA)[true | false] $(YELLOW)(Default: true)$(RESET)."
|
||||||
@$(ECHO_E) " $(GREEN)$(RESET) $(BOLD)$(BG_RED)DISCLAIMER:$(RESET) Using this flag is not recommended as it disables safety checks"
|
@$(ECHO_E) " $(GREEN)$(RESET) $(BOLD)$(BG_RED)DISCLAIMER:$(RESET) Using this flag is not recommended as it disables safety checks"
|
||||||
@$(ECHO_E) " $(GREEN)$(RESET) potentially leading to Undefined Behaviour."
|
@$(ECHO_E) " $(GREEN)$(RESET) potentially leading to Undefined Behaviour."
|
||||||
@@ -167,10 +165,7 @@ run-cc-test: build-cc-test
|
|||||||
@export LD_LIBRARY_PATH=$$LD_LIBRARY_PATH:"$(BUILD_DIR)" && "$(TEST_CXX_OUT)"
|
@export LD_LIBRARY_PATH=$$LD_LIBRARY_PATH:"$(BUILD_DIR)" && "$(TEST_CXX_OUT)"
|
||||||
@rm "$(TEST_CXX_OUT)"
|
@rm "$(TEST_CXX_OUT)"
|
||||||
|
|
||||||
codegen:
|
install: build-lib
|
||||||
python3 -m codegen -f $(CODEGEN_INPUT)
|
|
||||||
|
|
||||||
install: codegen build-lib
|
|
||||||
@mkdir -p "$(LIB_INSTALL)"
|
@mkdir -p "$(LIB_INSTALL)"
|
||||||
@cp -v "$(LIB_OUT)" "$(LIB_INSTALL)"
|
@cp -v "$(LIB_OUT)" "$(LIB_INSTALL)"
|
||||||
@mkdir -p "$(INCLUDE_INSTALL)"
|
@mkdir -p "$(INCLUDE_INSTALL)"
|
||||||
|
|||||||
@@ -1,47 +0,0 @@
|
|||||||
import json
|
|
||||||
from typing import Dict
|
|
||||||
from pathlib import Path
|
|
||||||
from codegen.datatypes import CDataType, CStruct
|
|
||||||
from codegen.constants import WAPP_REPO_ROOT, DBL_LIST_DATA
|
|
||||||
from codegen.dbl_list.make_dbl_list import DblListData, make_dbl_list
|
|
||||||
|
|
||||||
|
|
||||||
def main(types_file: Path | None):
|
|
||||||
dbl_list_datatypes: Dict[CDataType, DblListData] = {}
|
|
||||||
|
|
||||||
if types_file is not None and types_file.is_file() and "json" in types_file.suffix.lower():
|
|
||||||
with types_file.open("r") as infile:
|
|
||||||
datatypes = json.load(infile)
|
|
||||||
dbl_list_data = datatypes.get(DBL_LIST_DATA)
|
|
||||||
|
|
||||||
if dbl_list_data is not None and isinstance(dbl_list_data, dict):
|
|
||||||
dbl_list_datatypes = {k: DblListData.from_dict(v) for k, v in dbl_list_data.items()}
|
|
||||||
|
|
||||||
make_dbl_list(dbl_list_datatypes)
|
|
||||||
|
|
||||||
# Save example types file
|
|
||||||
custom_struct = CStruct(name="custom_type", cargs=[], typedef_name="CustomType")
|
|
||||||
example = {
|
|
||||||
DBL_LIST_DATA: {
|
|
||||||
"CustomType": DblListData(
|
|
||||||
node_typename="CustomTypeNode",
|
|
||||||
list_typename="CustomTypeList",
|
|
||||||
hdr_decl_types=[custom_struct],
|
|
||||||
).to_dict()
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
example_file = WAPP_REPO_ROOT / "codegen_custom_data_example.json"
|
|
||||||
with example_file.open("w") as outfile:
|
|
||||||
json.dump(example, outfile, indent=2)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
from argparse import ArgumentParser
|
|
||||||
|
|
||||||
parser = ArgumentParser()
|
|
||||||
parser.add_argument("-f", "--types-file", type=Path, help="JSON file containing custom types for codegen")
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
main(args.types_file)
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
from pathlib import Path
|
|
||||||
|
|
||||||
# Paths
|
|
||||||
PACKAGE_DIR = Path(__file__).parent.resolve()
|
|
||||||
WAPP_REPO_ROOT = PACKAGE_DIR.parent
|
|
||||||
WAPP_SRC_ROOT = WAPP_REPO_ROOT / "src"
|
|
||||||
|
|
||||||
# Dictionary Keys
|
|
||||||
DBL_LIST_DATA = "dbl_list_data"
|
|
||||||
@@ -1,503 +0,0 @@
|
|||||||
from enum import Enum
|
|
||||||
from pathlib import Path
|
|
||||||
from typing import Optional, Union, List, Dict, Type, Any, TypeVar, cast
|
|
||||||
from dataclasses import dataclass, asdict, field, fields
|
|
||||||
|
|
||||||
from codegen.constants import WAPP_SRC_ROOT
|
|
||||||
from codegen.utils import convert_to_relative
|
|
||||||
|
|
||||||
E = TypeVar("E", bound="Enum")
|
|
||||||
S = TypeVar("S", bound="SerialisableDataclass")
|
|
||||||
F = TypeVar("F", bound="CFile")
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class SerialisableDataclass:
|
|
||||||
def to_dict(self) -> Dict[str, Any]:
|
|
||||||
d = asdict(self)
|
|
||||||
for f in fields(self):
|
|
||||||
member = getattr(self, f.name)
|
|
||||||
|
|
||||||
if isinstance(member, list):
|
|
||||||
d[f.name] = [self.__serialise_member(i) for i in member]
|
|
||||||
else:
|
|
||||||
d[f.name] = self.__serialise_member(member)
|
|
||||||
|
|
||||||
return d
|
|
||||||
|
|
||||||
def __serialise_member(self, member: Any) -> Any:
|
|
||||||
if isinstance(member, Enum):
|
|
||||||
return member.value
|
|
||||||
elif isinstance(member, SerialisableDataclass):
|
|
||||||
return member.to_dict()
|
|
||||||
|
|
||||||
return member
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def to_enum_value(value: Any, _type: Type[E]) -> "E":
|
|
||||||
if isinstance(value, _type):
|
|
||||||
return value
|
|
||||||
|
|
||||||
return _type(value)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def to_c_usertype(value: dict[str, Any]) -> "CUserType":
|
|
||||||
try:
|
|
||||||
output = CStruct.from_dict(value)
|
|
||||||
except TypeError:
|
|
||||||
output = CEnum.from_dict(value)
|
|
||||||
|
|
||||||
return output
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def to_cdatatype(value: Any) -> "CDataType":
|
|
||||||
if isinstance(value, dict):
|
|
||||||
output = SerialisableDataclass.to_c_usertype(value)
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
output = CType(value)
|
|
||||||
except ValueError:
|
|
||||||
output = value
|
|
||||||
|
|
||||||
return output
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_dict(cls: Type[S], d: Dict[str, Any]) -> "S":
|
|
||||||
return cls(**d)
|
|
||||||
|
|
||||||
|
|
||||||
class CType(Enum):
|
|
||||||
VOID = "void"
|
|
||||||
BOOL = "b8"
|
|
||||||
CHAR = "char"
|
|
||||||
C8 = "c8"
|
|
||||||
C16 = "c16"
|
|
||||||
C32 = "c32"
|
|
||||||
I8 = "i8"
|
|
||||||
I16 = "i16"
|
|
||||||
I32 = "i32"
|
|
||||||
I64 = "i64"
|
|
||||||
U8 = "u8"
|
|
||||||
U16 = "u16"
|
|
||||||
U32 = "u32"
|
|
||||||
U64 = "u64"
|
|
||||||
F32 = "f32"
|
|
||||||
F64 = "f64"
|
|
||||||
F128 = "f128"
|
|
||||||
IPTR = "iptr"
|
|
||||||
UPTR = "uptr"
|
|
||||||
|
|
||||||
def __str__(self) -> str:
|
|
||||||
return self.value
|
|
||||||
|
|
||||||
|
|
||||||
class CQualifier(Enum):
|
|
||||||
NONE = ""
|
|
||||||
CONST = "const "
|
|
||||||
EXTERNAL = "wapp_extern "
|
|
||||||
INTERNAL = "wapp_intern "
|
|
||||||
PERSISTENT = "wapp_persist "
|
|
||||||
|
|
||||||
def __str__(self) -> str:
|
|
||||||
return self.value
|
|
||||||
|
|
||||||
|
|
||||||
class CPointerType(Enum):
|
|
||||||
NONE = ""
|
|
||||||
SINGLE = "*"
|
|
||||||
DOUBLE = "**"
|
|
||||||
|
|
||||||
def __str__(self) -> str:
|
|
||||||
return self.value
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class CPointer(SerialisableDataclass):
|
|
||||||
_type: CPointerType = CPointerType.NONE
|
|
||||||
qualifier: CQualifier = CQualifier.NONE
|
|
||||||
|
|
||||||
def __str__(self) -> str:
|
|
||||||
return str(self._type) + str(self.qualifier)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_dict(cls: Type["CPointer"], d: Dict[str, Any]) -> "CPointer":
|
|
||||||
ptr = CPointer(**d)
|
|
||||||
ptr._type = CPointer.to_enum_value(ptr._type, CPointerType)
|
|
||||||
ptr.qualifier = CPointer.to_enum_value(ptr.qualifier, CQualifier)
|
|
||||||
return ptr
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class CEnumVal(SerialisableDataclass):
|
|
||||||
name: str
|
|
||||||
value: Optional[int] = None
|
|
||||||
|
|
||||||
def __str__(self) -> str:
|
|
||||||
return self.name + "" if self.value is None else f" = {self.value}"
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class CEnum(SerialisableDataclass):
|
|
||||||
name: str
|
|
||||||
values: List[CEnumVal]
|
|
||||||
typedef: bool = False
|
|
||||||
|
|
||||||
def __str__(self) -> str:
|
|
||||||
if self.typedef:
|
|
||||||
header = "typedef enum {\n"
|
|
||||||
footer = f"}} {self.name};\n"
|
|
||||||
else:
|
|
||||||
header = f"enum {self.name} {{\n"
|
|
||||||
footer = "};\n"
|
|
||||||
|
|
||||||
values = ""
|
|
||||||
for value in self.values:
|
|
||||||
values += f" {str(value)},\n"
|
|
||||||
|
|
||||||
return header + values + footer
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_dict(cls: Type["CEnum"], d: Dict[str, Any]) -> "CEnum":
|
|
||||||
e = CEnum(**d)
|
|
||||||
e.values = [CEnumVal.from_dict(v) for v in e.values if isinstance(v, dict)]
|
|
||||||
return e
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class CMacro(SerialisableDataclass):
|
|
||||||
name: str
|
|
||||||
value: str
|
|
||||||
|
|
||||||
def __str__(self) -> str:
|
|
||||||
return f"#define {self.name} {self.value}\n"
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class CStruct(SerialisableDataclass):
|
|
||||||
name: str
|
|
||||||
cargs: List["CArg"]
|
|
||||||
typedef_name: Optional[str] = None
|
|
||||||
|
|
||||||
def __str__(self) -> str:
|
|
||||||
return self.declare() + self.define()
|
|
||||||
|
|
||||||
def declare(self) -> str:
|
|
||||||
declaration = f"typedef struct {self.name} {self.typedef_name if self.typedef_name is not None else self.name};\n"
|
|
||||||
return declaration
|
|
||||||
|
|
||||||
def define(self):
|
|
||||||
definition = f"struct {self.name} {{\n"
|
|
||||||
args = ""
|
|
||||||
for arg in self.cargs:
|
|
||||||
args += f" {str(arg)};\n"
|
|
||||||
footer = "};\n"
|
|
||||||
|
|
||||||
return definition + args + footer;
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_dict(cls: Type["CStruct"], d: Dict[str, Any]) -> "CStruct":
|
|
||||||
s = CStruct(**d)
|
|
||||||
s.cargs = [CArg.from_dict(v) for v in s.cargs if isinstance(v, dict)]
|
|
||||||
return s
|
|
||||||
|
|
||||||
|
|
||||||
CUserType = Union[CStruct, CEnum]
|
|
||||||
CDataType = Union[CType, CUserType, str]
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class CArg(SerialisableDataclass):
|
|
||||||
name: str
|
|
||||||
_type: CDataType
|
|
||||||
array: bool = False
|
|
||||||
pointer: CPointer = field(default_factory=CPointer)
|
|
||||||
qualifier: CQualifier = CQualifier.NONE
|
|
||||||
|
|
||||||
def __str__(self) -> str:
|
|
||||||
qualifier = str(self.qualifier)
|
|
||||||
_type = get_datatype_string(self._type) + " "
|
|
||||||
pointer = str(self.pointer)
|
|
||||||
array = "[]" if self.array else ""
|
|
||||||
|
|
||||||
return qualifier + _type + pointer + self.name + array
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_dict(cls: Type["CArg"], d: Dict[str, Any]) -> "CArg":
|
|
||||||
arg = CArg(**d)
|
|
||||||
arg._type = CArg.to_cdatatype(arg._type)
|
|
||||||
|
|
||||||
if isinstance(arg.pointer, dict):
|
|
||||||
arg.pointer = CPointer.from_dict(arg.pointer)
|
|
||||||
|
|
||||||
arg.qualifier = CArg.to_enum_value(arg.qualifier, CQualifier)
|
|
||||||
|
|
||||||
return arg
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class CFunc(SerialisableDataclass):
|
|
||||||
name: str
|
|
||||||
ret_type: CDataType
|
|
||||||
args: List[CArg]
|
|
||||||
body: str
|
|
||||||
pointer: CPointer = field(default_factory=CPointer)
|
|
||||||
qualifiers: List[CQualifier] = field(default_factory=list)
|
|
||||||
|
|
||||||
def __str__(self) -> str:
|
|
||||||
qualifiers = ""
|
|
||||||
for qualifier in self.qualifiers:
|
|
||||||
if qualifier == CQualifier.NONE:
|
|
||||||
continue
|
|
||||||
if len(qualifiers) > 0:
|
|
||||||
qualifiers += " "
|
|
||||||
qualifiers += f"{str(qualifier)}"
|
|
||||||
|
|
||||||
args = ""
|
|
||||||
for i, arg in enumerate(self.args):
|
|
||||||
args += f"{str(arg)}"
|
|
||||||
if i + 1 < len(self.args):
|
|
||||||
args += ", "
|
|
||||||
|
|
||||||
return qualifiers + get_datatype_string(self.ret_type) + " " + str(self.pointer) + self.name + f"({args})"
|
|
||||||
|
|
||||||
def declare(self) -> str:
|
|
||||||
return f"{str(self)};\n"
|
|
||||||
|
|
||||||
def define(self) -> str:
|
|
||||||
return f"{str(self)} {{\n{self.body}\n}}\n\n"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_dict(cls: Type["CFunc"], d: Dict[str, Any]) -> "CFunc":
|
|
||||||
f = CFunc(**d)
|
|
||||||
f.ret_type = CFunc.to_cdatatype(f.ret_type)
|
|
||||||
f.args = [CArg.from_dict(v) for v in f.args if isinstance(v, dict)]
|
|
||||||
f.qualifiers = [CFunc.to_enum_value(v, CQualifier) for v in f.qualifiers]
|
|
||||||
|
|
||||||
if isinstance(f.pointer, dict):
|
|
||||||
f.pointer = CPointer.from_dict(f.pointer)
|
|
||||||
|
|
||||||
return f
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class CInclude(SerialisableDataclass):
|
|
||||||
header: Union[str, "CHeader"]
|
|
||||||
local: bool = False
|
|
||||||
same_dir: bool = False
|
|
||||||
|
|
||||||
def __str__(self) -> str:
|
|
||||||
if isinstance(self.header, CHeader):
|
|
||||||
name = f"{self.header.name}.{self.header.extension}"
|
|
||||||
else:
|
|
||||||
name = self.header
|
|
||||||
|
|
||||||
if self.local:
|
|
||||||
open_symbol = '"'
|
|
||||||
close_symbol = '"'
|
|
||||||
|
|
||||||
if self.same_dir:
|
|
||||||
name = f"./{name}"
|
|
||||||
else:
|
|
||||||
open_symbol = '<'
|
|
||||||
close_symbol = '>'
|
|
||||||
|
|
||||||
return f"#include {open_symbol}{name}{close_symbol}\n"
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_dict(cls: Type["CInclude"], d: Dict[str, Any]) -> "CInclude":
|
|
||||||
inc = CInclude(**d)
|
|
||||||
|
|
||||||
if isinstance(inc.header, dict):
|
|
||||||
inc.header = CHeader.from_dict(inc.header)
|
|
||||||
|
|
||||||
return inc
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class CFile(SerialisableDataclass):
|
|
||||||
name: str
|
|
||||||
extension: str
|
|
||||||
includes: List[CInclude] = field(default_factory=list)
|
|
||||||
types: List[CUserType] = field(default_factory=list)
|
|
||||||
funcs: List[CFunc] = field(default_factory=list)
|
|
||||||
decl_types: List[CStruct] = field(default_factory=list)
|
|
||||||
macros: List[CMacro] = field(default_factory=list)
|
|
||||||
c_macros: List[CMacro] = field(default_factory=list)
|
|
||||||
cpp_macros: List[CMacro] = field(default_factory=list)
|
|
||||||
|
|
||||||
def save(self, output_dir: Path):
|
|
||||||
self.includes.extend(
|
|
||||||
[
|
|
||||||
CInclude(
|
|
||||||
header=str(convert_to_relative(WAPP_SRC_ROOT / "common" / "aliases" / "aliases.h", output_dir)).replace("\\", "/"),
|
|
||||||
local=True,
|
|
||||||
),
|
|
||||||
CInclude(
|
|
||||||
header=str(convert_to_relative(WAPP_SRC_ROOT / "common" / "platform" / "platform.h", output_dir)).replace("\\", "/"),
|
|
||||||
local=True,
|
|
||||||
)
|
|
||||||
]
|
|
||||||
)
|
|
||||||
output_file = output_dir / f"{self.name}.{self.extension}"
|
|
||||||
with open(output_file, "w+") as outfile:
|
|
||||||
outfile.write(str(self))
|
|
||||||
|
|
||||||
def __str__(self) -> str:
|
|
||||||
return """\
|
|
||||||
/**
|
|
||||||
* THIS FILE IS AUTOMATICALLY GENERATED. ANY MODIFICATIONS TO IT WILL BE OVERWRITTEN.
|
|
||||||
*/
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_dict(cls: Type["CFile"], d: Dict[str, Any]) -> "CFile":
|
|
||||||
f = CFile(**d)
|
|
||||||
f.deserialise_c_file_data()
|
|
||||||
|
|
||||||
return f
|
|
||||||
|
|
||||||
def deserialise_c_file_data(self) -> None:
|
|
||||||
self.includes = [CInclude.from_dict(v) for v in self.includes if isinstance(v, dict)]
|
|
||||||
self.types = [CFile.to_c_usertype(v) for v in self.types if isinstance(v, dict)]
|
|
||||||
self.funcs = [CFunc.from_dict(v) for v in self.funcs if isinstance(v, dict)]
|
|
||||||
self.decl_types = [CStruct.from_dict(v) for v in self.decl_types if isinstance(v, dict)]
|
|
||||||
self.macros = [CMacro.from_dict(v) for v in self.macros if isinstance(v, dict)]
|
|
||||||
self.c_macros = [CMacro.from_dict(v) for v in self.c_macros if isinstance(v, dict)]
|
|
||||||
self.cpp_macros = [CMacro.from_dict(v) for v in self.cpp_macros if isinstance(v, dict)]
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class CHeader(CFile):
|
|
||||||
extension: str = "h"
|
|
||||||
|
|
||||||
def __str__(self) -> str:
|
|
||||||
name_upper = self.name.upper()
|
|
||||||
header_guard_name = f"{name_upper}_H"
|
|
||||||
header_guard_open = f"#ifndef {header_guard_name}\n#define {header_guard_name}\n\n"
|
|
||||||
header_guard_close = f"#endif // !{header_guard_name}\n"
|
|
||||||
|
|
||||||
c_linkage_open = "#ifdef WAPP_PLATFORM_CPP\nBEGIN_C_LINKAGE\n#endif // !WAPP_PLATFORM_CPP\n\n"
|
|
||||||
c_linkage_close = "\n#ifdef WAPP_PLATFORM_CPP\nEND_C_LINKAGE\n#endif // !WAPP_PLATFORM_CPP\n\n"
|
|
||||||
|
|
||||||
includes = _get_includes_string(self.includes)
|
|
||||||
|
|
||||||
macros = ""
|
|
||||||
for macro in self.macros:
|
|
||||||
macros += str(macro)
|
|
||||||
if len(macros) > 0:
|
|
||||||
macros += "\n"
|
|
||||||
|
|
||||||
if len(self.cpp_macros) > 0:
|
|
||||||
macros += "#ifdef WAPP_PLATFORM_CPP\n"
|
|
||||||
for macro in self.cpp_macros:
|
|
||||||
macros += str(macro)
|
|
||||||
macros += "#else\n"
|
|
||||||
for macro in self.c_macros:
|
|
||||||
macros += str(macro)
|
|
||||||
macros += "#endif // !WAPP_PLATFORM_CPP\n\n"
|
|
||||||
|
|
||||||
forward_declarations = ""
|
|
||||||
for _type in self.decl_types:
|
|
||||||
forward_declarations += _type.declare()
|
|
||||||
if len(forward_declarations) > 0:
|
|
||||||
forward_declarations += "\n"
|
|
||||||
|
|
||||||
types = ""
|
|
||||||
for _type in self.types:
|
|
||||||
types += str(_type) + "\n"
|
|
||||||
|
|
||||||
funcs = ""
|
|
||||||
for func in self.funcs:
|
|
||||||
funcs += func.declare()
|
|
||||||
|
|
||||||
return (
|
|
||||||
super().__str__() +
|
|
||||||
header_guard_open +
|
|
||||||
includes +
|
|
||||||
c_linkage_open +
|
|
||||||
macros +
|
|
||||||
forward_declarations +
|
|
||||||
types +
|
|
||||||
funcs +
|
|
||||||
c_linkage_close +
|
|
||||||
header_guard_close
|
|
||||||
)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_dict(cls: Type["CHeader"], d: Dict[str, Any]) -> "CHeader":
|
|
||||||
return cast("CHeader", super().from_dict(d))
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class CSource(CFile):
|
|
||||||
extension: str = "c"
|
|
||||||
internal_funcs: List[CFunc] = field(default_factory=list)
|
|
||||||
|
|
||||||
def __str__(self) -> str:
|
|
||||||
includes = _get_includes_string(self.includes)
|
|
||||||
|
|
||||||
macros = ""
|
|
||||||
for macro in self.macros:
|
|
||||||
macros += str(macro)
|
|
||||||
if len(macros) > 0:
|
|
||||||
macros += "\n"
|
|
||||||
|
|
||||||
forward_declarations = ""
|
|
||||||
for _type in self.decl_types:
|
|
||||||
forward_declarations += _type.declare()
|
|
||||||
if len(forward_declarations) > 0:
|
|
||||||
forward_declarations += "\n"
|
|
||||||
|
|
||||||
types = ""
|
|
||||||
for _type in self.types:
|
|
||||||
types += str(_type) + "\n"
|
|
||||||
|
|
||||||
internal_funcs_decl = ""
|
|
||||||
internal_funcs_def = ""
|
|
||||||
for func in self.internal_funcs:
|
|
||||||
internal_funcs_decl += func.declare()
|
|
||||||
internal_funcs_def += func.define()
|
|
||||||
|
|
||||||
if len(internal_funcs_decl) > 0:
|
|
||||||
internal_funcs_decl += "\n"
|
|
||||||
|
|
||||||
funcs = ""
|
|
||||||
for func in self.funcs:
|
|
||||||
funcs += func.define()
|
|
||||||
|
|
||||||
return (
|
|
||||||
super().__str__() +
|
|
||||||
includes +
|
|
||||||
macros +
|
|
||||||
forward_declarations +
|
|
||||||
types +
|
|
||||||
internal_funcs_decl +
|
|
||||||
funcs +
|
|
||||||
internal_funcs_def
|
|
||||||
)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_dict(cls: Type["CSource"], d: Dict[str, Any]) -> "CSource":
|
|
||||||
s = CSource(**d)
|
|
||||||
s.deserialise_c_file_data()
|
|
||||||
s.internal_funcs = [CFunc.from_dict(v) for v in s.funcs if isinstance(v, dict)]
|
|
||||||
return s
|
|
||||||
|
|
||||||
|
|
||||||
def get_datatype_string(_type: CDataType) -> str:
|
|
||||||
if isinstance(_type, CType):
|
|
||||||
return str(_type)
|
|
||||||
elif isinstance(_type, CStruct) or isinstance(_type, CEnum):
|
|
||||||
return _type.name
|
|
||||||
elif isinstance(_type, str):
|
|
||||||
return _type
|
|
||||||
|
|
||||||
|
|
||||||
def _get_includes_string(includes: List[CInclude]) -> str:
|
|
||||||
output = ""
|
|
||||||
for include in sorted(includes, key=lambda inc: inc.local, reverse=True):
|
|
||||||
output += str(include)
|
|
||||||
if len(output) > 0:
|
|
||||||
output += "\n"
|
|
||||||
|
|
||||||
return output
|
|
||||||
@@ -1,339 +0,0 @@
|
|||||||
from pathlib import Path
|
|
||||||
from dataclasses import dataclass, field
|
|
||||||
from typing import List, Dict, Any, Type
|
|
||||||
from codegen.constants import WAPP_SRC_ROOT
|
|
||||||
from codegen.utils import load_func_body_from_file, convert_to_relative
|
|
||||||
from codegen.datatypes import (
|
|
||||||
CDataType,
|
|
||||||
CMacro,
|
|
||||||
CStruct,
|
|
||||||
CFunc,
|
|
||||||
CHeader,
|
|
||||||
CSource,
|
|
||||||
CArg,
|
|
||||||
CType,
|
|
||||||
CPointer,
|
|
||||||
CPointerType,
|
|
||||||
CQualifier,
|
|
||||||
CInclude,
|
|
||||||
SerialisableDataclass,
|
|
||||||
get_datatype_string,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class DblListData(SerialisableDataclass):
|
|
||||||
node_typename: str
|
|
||||||
list_typename: str
|
|
||||||
hdr_decl_types: List[CStruct] = field(default_factory=list)
|
|
||||||
src_decl_types: List[CStruct] = field(default_factory=list)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_dict(cls: Type["DblListData"], d: Dict[str, Any]) -> "DblListData":
|
|
||||||
data = DblListData(**d)
|
|
||||||
data.hdr_decl_types = [CStruct.from_dict(v) for v in data.hdr_decl_types if isinstance(v, dict)]
|
|
||||||
data.src_decl_types = [CStruct.from_dict(v) for v in data.src_decl_types if isinstance(v, dict)]
|
|
||||||
return data
|
|
||||||
|
|
||||||
|
|
||||||
def make_dbl_list(user_datatypes: Dict[CDataType, DblListData] = {}):
|
|
||||||
def __format_func_body(
|
|
||||||
filename: Path,
|
|
||||||
type_string: str,
|
|
||||||
type_string_upper: str,
|
|
||||||
type_string_lower: str,
|
|
||||||
node_typename: str,
|
|
||||||
list_typename: str
|
|
||||||
):
|
|
||||||
return load_func_body_from_file(filename).format(
|
|
||||||
T=type_string,
|
|
||||||
NodeType=node_typename,
|
|
||||||
ListType=list_typename,
|
|
||||||
Tupper=type_string_upper,
|
|
||||||
Tlower=type_string_lower,
|
|
||||||
)
|
|
||||||
|
|
||||||
out_dir = WAPP_SRC_ROOT / "base" / "dbl_list"
|
|
||||||
out_dir.mkdir(parents=True, exist_ok=True)
|
|
||||||
|
|
||||||
common_decl_types: List[CStruct] = []
|
|
||||||
|
|
||||||
datatypes: dict[CDataType, DblListData] = {
|
|
||||||
CType.VOID: DblListData(node_typename="GenericNode", list_typename="GenericList"),
|
|
||||||
"void *": DblListData(node_typename="VoidPNode", list_typename="VoidPList"),
|
|
||||||
"Str8": DblListData(
|
|
||||||
node_typename="Str8Node",
|
|
||||||
list_typename="Str8List",
|
|
||||||
hdr_decl_types=[
|
|
||||||
CStruct(name="str8", cargs=[], typedef_name="Str8"),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
}
|
|
||||||
|
|
||||||
for _type in CType:
|
|
||||||
if _type == CType.VOID:
|
|
||||||
continue
|
|
||||||
|
|
||||||
type_title = _type.value.title()
|
|
||||||
datatypes[_type] = DblListData(
|
|
||||||
node_typename=f"{type_title}Node",
|
|
||||||
list_typename=f"{type_title}List",
|
|
||||||
)
|
|
||||||
|
|
||||||
datatypes.update(user_datatypes)
|
|
||||||
|
|
||||||
snippets_dir = Path(__file__).parent / "snippets"
|
|
||||||
|
|
||||||
header = CHeader(
|
|
||||||
name="dbl_list",
|
|
||||||
decl_types=[*common_decl_types],
|
|
||||||
includes=[],
|
|
||||||
types=[],
|
|
||||||
funcs=[]
|
|
||||||
)
|
|
||||||
|
|
||||||
source = CSource(
|
|
||||||
name=header.name,
|
|
||||||
decl_types=[*common_decl_types],
|
|
||||||
includes=[
|
|
||||||
CInclude(header, local=True, same_dir=True),
|
|
||||||
CInclude(
|
|
||||||
header=str(convert_to_relative(WAPP_SRC_ROOT / "common" / "assert" / "assert.h", out_dir)).replace("\\", "/"),
|
|
||||||
local=True
|
|
||||||
),
|
|
||||||
CInclude(header="stddef.h"),
|
|
||||||
],
|
|
||||||
internal_funcs=[],
|
|
||||||
funcs=header.funcs
|
|
||||||
)
|
|
||||||
|
|
||||||
for _type, dbl_list_data in datatypes.items():
|
|
||||||
type_string = get_datatype_string(_type)
|
|
||||||
clean_type_string = type_string.replace(" ", "").replace("*", "_ptr")
|
|
||||||
type_string_upper = clean_type_string.upper()
|
|
||||||
type_string_lower = clean_type_string.lower()
|
|
||||||
|
|
||||||
node = CStruct(
|
|
||||||
name=dbl_list_data.node_typename,
|
|
||||||
cargs=[
|
|
||||||
CArg(name="item", _type=type_string, pointer=CPointer(_type=CPointerType.SINGLE)),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
node.cargs.extend([
|
|
||||||
CArg(name="prev", _type=node, pointer=CPointer(_type=CPointerType.SINGLE)),
|
|
||||||
CArg(name="next", _type=node, pointer=CPointer(_type=CPointerType.SINGLE)),
|
|
||||||
])
|
|
||||||
|
|
||||||
dl_list = CStruct(
|
|
||||||
name=dbl_list_data.list_typename,
|
|
||||||
cargs=[
|
|
||||||
CArg(name="first", _type=node, pointer=CPointer(_type=CPointerType.SINGLE)),
|
|
||||||
CArg(name="last", _type=node, pointer=CPointer(_type=CPointerType.SINGLE)),
|
|
||||||
CArg(name="node_count", _type=CType.U64),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
header.types.extend([node, dl_list])
|
|
||||||
header.decl_types.extend(dbl_list_data.hdr_decl_types)
|
|
||||||
source.decl_types.extend(dbl_list_data.src_decl_types)
|
|
||||||
if isinstance(_type, CType) and _type == CType.VOID:
|
|
||||||
# Don't define any functions for the generic node and list
|
|
||||||
continue
|
|
||||||
|
|
||||||
node_cmacro = CMacro(
|
|
||||||
name=f"wapp_{type_string_lower}_list_node(ITEM_PTR)",
|
|
||||||
value=__format_func_body(
|
|
||||||
filename=snippets_dir / "list_node",
|
|
||||||
type_string=type_string,
|
|
||||||
type_string_upper=type_string_upper,
|
|
||||||
type_string_lower=type_string_lower,
|
|
||||||
node_typename=dbl_list_data.node_typename,
|
|
||||||
list_typename=dbl_list_data.list_typename
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
node_cppmacro = CMacro(
|
|
||||||
name=f"wapp_{type_string_lower}_list_node(ITEM_PTR)",
|
|
||||||
value=__format_func_body(
|
|
||||||
filename=snippets_dir / "list_node_cpp",
|
|
||||||
type_string=type_string,
|
|
||||||
type_string_upper=type_string_upper,
|
|
||||||
type_string_lower=type_string_lower,
|
|
||||||
node_typename=dbl_list_data.node_typename,
|
|
||||||
list_typename=dbl_list_data.list_typename
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
get_func = CFunc(
|
|
||||||
name=f"wapp_{type_string_lower}_list_get",
|
|
||||||
ret_type=node,
|
|
||||||
args=[
|
|
||||||
CArg(name="list", _type=dl_list, pointer=CPointer(CPointerType.SINGLE), qualifier=CQualifier.CONST),
|
|
||||||
CArg(name="index", _type=CType.U64),
|
|
||||||
],
|
|
||||||
body=__format_func_body(
|
|
||||||
filename=snippets_dir / "list_get",
|
|
||||||
type_string=type_string,
|
|
||||||
type_string_upper=type_string_upper,
|
|
||||||
type_string_lower=type_string_lower,
|
|
||||||
node_typename=dbl_list_data.node_typename,
|
|
||||||
list_typename=dbl_list_data.list_typename
|
|
||||||
),
|
|
||||||
pointer=CPointer(CPointerType.SINGLE),
|
|
||||||
)
|
|
||||||
|
|
||||||
push_front_func = CFunc(
|
|
||||||
name=f"wapp_{type_string_lower}_list_push_front",
|
|
||||||
ret_type=CType.VOID,
|
|
||||||
args=[
|
|
||||||
CArg(name="list", _type=dl_list, pointer=CPointer(CPointerType.SINGLE)),
|
|
||||||
CArg(name="node", _type=node, pointer=CPointer(CPointerType.SINGLE)),
|
|
||||||
],
|
|
||||||
body=__format_func_body(
|
|
||||||
filename=snippets_dir / "list_push_front",
|
|
||||||
type_string=type_string,
|
|
||||||
type_string_upper=type_string_upper,
|
|
||||||
type_string_lower=type_string_lower,
|
|
||||||
node_typename=dbl_list_data.node_typename,
|
|
||||||
list_typename=dbl_list_data.list_typename
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
push_back_func = CFunc(
|
|
||||||
name=f"wapp_{type_string_lower}_list_push_back",
|
|
||||||
ret_type=CType.VOID,
|
|
||||||
args=[
|
|
||||||
CArg(name="list", _type=dl_list, pointer=CPointer(CPointerType.SINGLE)),
|
|
||||||
CArg(name="node", _type=node, pointer=CPointer(CPointerType.SINGLE)),
|
|
||||||
],
|
|
||||||
body=__format_func_body(
|
|
||||||
filename=snippets_dir / "list_push_back",
|
|
||||||
type_string=type_string,
|
|
||||||
type_string_upper=type_string_upper,
|
|
||||||
type_string_lower=type_string_lower,
|
|
||||||
node_typename=dbl_list_data.node_typename,
|
|
||||||
list_typename=dbl_list_data.list_typename
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
insert_func = CFunc(
|
|
||||||
name=f"wapp_{type_string_lower}_list_insert",
|
|
||||||
ret_type=CType.VOID,
|
|
||||||
args=[
|
|
||||||
CArg(name="list", _type=dl_list, pointer=CPointer(CPointerType.SINGLE)),
|
|
||||||
CArg(name="node", _type=node, pointer=CPointer(CPointerType.SINGLE)),
|
|
||||||
CArg(name="index", _type=CType.U64),
|
|
||||||
],
|
|
||||||
body=__format_func_body(
|
|
||||||
filename=snippets_dir / "list_insert",
|
|
||||||
type_string=type_string,
|
|
||||||
type_string_upper=type_string_upper,
|
|
||||||
type_string_lower=type_string_lower,
|
|
||||||
node_typename=dbl_list_data.node_typename,
|
|
||||||
list_typename=dbl_list_data.list_typename
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
pop_front_func = CFunc(
|
|
||||||
name=f"wapp_{type_string_lower}_list_pop_front",
|
|
||||||
ret_type=node,
|
|
||||||
args=[
|
|
||||||
CArg(name="list", _type=dl_list, pointer=CPointer(CPointerType.SINGLE)),
|
|
||||||
],
|
|
||||||
body=__format_func_body(
|
|
||||||
filename=snippets_dir / "list_pop_front",
|
|
||||||
type_string=type_string,
|
|
||||||
type_string_upper=type_string_upper,
|
|
||||||
type_string_lower=type_string_lower,
|
|
||||||
node_typename=dbl_list_data.node_typename,
|
|
||||||
list_typename=dbl_list_data.list_typename
|
|
||||||
),
|
|
||||||
pointer=CPointer(CPointerType.SINGLE),
|
|
||||||
)
|
|
||||||
|
|
||||||
pop_back_func = CFunc(
|
|
||||||
name=f"wapp_{type_string_lower}_list_pop_back",
|
|
||||||
ret_type=node,
|
|
||||||
args=[
|
|
||||||
CArg(name="list", _type=dl_list, pointer=CPointer(CPointerType.SINGLE)),
|
|
||||||
],
|
|
||||||
body=__format_func_body(
|
|
||||||
filename=snippets_dir / "list_pop_back",
|
|
||||||
type_string=type_string,
|
|
||||||
type_string_upper=type_string_upper,
|
|
||||||
type_string_lower=type_string_lower,
|
|
||||||
node_typename=dbl_list_data.node_typename,
|
|
||||||
list_typename=dbl_list_data.list_typename
|
|
||||||
),
|
|
||||||
pointer=CPointer(CPointerType.SINGLE),
|
|
||||||
)
|
|
||||||
|
|
||||||
remove_func = CFunc(
|
|
||||||
name=f"wapp_{type_string_lower}_list_remove",
|
|
||||||
ret_type=node,
|
|
||||||
args=[
|
|
||||||
CArg(name="list", _type=dl_list, pointer=CPointer(CPointerType.SINGLE)),
|
|
||||||
CArg(name="index", _type=CType.U64),
|
|
||||||
],
|
|
||||||
body=__format_func_body(
|
|
||||||
filename=snippets_dir / "list_remove",
|
|
||||||
type_string=type_string,
|
|
||||||
type_string_upper=type_string_upper,
|
|
||||||
type_string_lower=type_string_lower,
|
|
||||||
node_typename=dbl_list_data.node_typename,
|
|
||||||
list_typename=dbl_list_data.list_typename
|
|
||||||
),
|
|
||||||
pointer=CPointer(CPointerType.SINGLE),
|
|
||||||
)
|
|
||||||
|
|
||||||
empty_func = CFunc(
|
|
||||||
name=f"wapp_{type_string_lower}_list_empty",
|
|
||||||
ret_type=CType.VOID,
|
|
||||||
args=[
|
|
||||||
CArg(name="list", _type=dl_list, pointer=CPointer(CPointerType.SINGLE)),
|
|
||||||
],
|
|
||||||
body=__format_func_body(
|
|
||||||
filename=snippets_dir / "list_empty",
|
|
||||||
type_string=type_string,
|
|
||||||
type_string_upper=type_string_upper,
|
|
||||||
type_string_lower=type_string_lower,
|
|
||||||
node_typename=dbl_list_data.node_typename,
|
|
||||||
list_typename=dbl_list_data.list_typename
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
node_to_list_func = CFunc(
|
|
||||||
name=f"{type_string_lower}_node_to_list",
|
|
||||||
ret_type=dl_list,
|
|
||||||
args=[
|
|
||||||
CArg(name="node", _type=node, pointer=CPointer(CPointerType.SINGLE)),
|
|
||||||
],
|
|
||||||
body=__format_func_body(
|
|
||||||
filename=snippets_dir / "node_to_list",
|
|
||||||
type_string=type_string,
|
|
||||||
type_string_upper=type_string_upper,
|
|
||||||
type_string_lower=type_string_lower,
|
|
||||||
node_typename=dbl_list_data.node_typename,
|
|
||||||
list_typename=dbl_list_data.list_typename
|
|
||||||
),
|
|
||||||
qualifiers=[CQualifier.INTERNAL],
|
|
||||||
)
|
|
||||||
|
|
||||||
header.c_macros.append(node_cmacro)
|
|
||||||
header.cpp_macros.append(node_cppmacro)
|
|
||||||
header.funcs.extend([
|
|
||||||
get_func,
|
|
||||||
push_front_func,
|
|
||||||
push_back_func,
|
|
||||||
insert_func,
|
|
||||||
pop_front_func,
|
|
||||||
pop_back_func,
|
|
||||||
remove_func,
|
|
||||||
empty_func,
|
|
||||||
])
|
|
||||||
|
|
||||||
source.internal_funcs.append(node_to_list_func)
|
|
||||||
source.funcs = header.funcs
|
|
||||||
|
|
||||||
header.save(out_dir)
|
|
||||||
source.save(out_dir)
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
wapp_debug_assert(list != NULL, "`list` should not be NULL");
|
|
||||||
|
|
||||||
u64 count = list->node_count;
|
|
||||||
for (u64 i = 0; i < count; ++i) {{
|
|
||||||
wapp_{Tlower}_list_pop_back(list);
|
|
||||||
}}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
wapp_runtime_assert(index < list->node_count, "`index` is out of bounds");
|
|
||||||
|
|
||||||
{NodeType} *output = NULL;
|
|
||||||
{NodeType} *current = list->first;
|
|
||||||
for (u64 i = 1; i <= index; ++i) {{
|
|
||||||
current = current->next;
|
|
||||||
}}
|
|
||||||
|
|
||||||
output = current;
|
|
||||||
|
|
||||||
return output;
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");
|
|
||||||
|
|
||||||
if (index == 0) {{
|
|
||||||
wapp_{Tlower}_list_push_front(list, node);
|
|
||||||
return;
|
|
||||||
}} else if (index == list->node_count) {{
|
|
||||||
wapp_{Tlower}_list_push_back(list, node);
|
|
||||||
return;
|
|
||||||
}}
|
|
||||||
|
|
||||||
{NodeType} *dst_node = wapp_{Tlower}_list_get(list, index);
|
|
||||||
if (!dst_node) {{
|
|
||||||
return;
|
|
||||||
}}
|
|
||||||
|
|
||||||
{ListType} node_list = {Tlower}_node_to_list(node);
|
|
||||||
|
|
||||||
list->node_count += node_list.node_count;
|
|
||||||
|
|
||||||
{NodeType} *prev = dst_node->prev;
|
|
||||||
|
|
||||||
dst_node->prev = node_list.last;
|
|
||||||
prev->next = node_list.first;
|
|
||||||
|
|
||||||
node_list.first->prev = prev;
|
|
||||||
node_list.last->next = dst_node;
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
(({NodeType}){{.item = ITEM_PTR}})
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{NodeType}{{ITEM_PTR, nullptr, nullptr}}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
wapp_debug_assert(list != NULL, "`list` should not be NULL");
|
|
||||||
|
|
||||||
{NodeType} *output = NULL;
|
|
||||||
|
|
||||||
if (list->node_count == 0) {{
|
|
||||||
goto RETURN_{Tupper}_LIST_POP_BACK;
|
|
||||||
}}
|
|
||||||
|
|
||||||
output = list->last;
|
|
||||||
|
|
||||||
if (list->node_count == 1) {{
|
|
||||||
*list = ({ListType}){{0}};
|
|
||||||
goto RETURN_{Tupper}_LIST_POP_BACK;
|
|
||||||
}}
|
|
||||||
|
|
||||||
--(list->node_count);
|
|
||||||
list->last = output->prev;
|
|
||||||
|
|
||||||
output->prev = output->next = NULL;
|
|
||||||
|
|
||||||
RETURN_{Tupper}_LIST_POP_BACK:
|
|
||||||
return output;
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
wapp_debug_assert(list != NULL, "`list` should not be NULL");
|
|
||||||
|
|
||||||
{NodeType} *output = NULL;
|
|
||||||
|
|
||||||
if (list->node_count == 0) {{
|
|
||||||
goto RETURN_{Tupper}_LIST_POP_FRONT;
|
|
||||||
}}
|
|
||||||
|
|
||||||
output = list->first;
|
|
||||||
|
|
||||||
if (list->node_count == 1) {{
|
|
||||||
*list = ({ListType}){{0}};
|
|
||||||
goto RETURN_{Tupper}_LIST_POP_FRONT;
|
|
||||||
}}
|
|
||||||
|
|
||||||
--(list->node_count);
|
|
||||||
list->first = output->next;
|
|
||||||
|
|
||||||
output->prev = output->next = NULL;
|
|
||||||
|
|
||||||
RETURN_{Tupper}_LIST_POP_FRONT:
|
|
||||||
return output;
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");
|
|
||||||
|
|
||||||
{ListType} node_list = {Tlower}_node_to_list(node);
|
|
||||||
|
|
||||||
if (list->node_count == 0) {{
|
|
||||||
*list = node_list;
|
|
||||||
return;
|
|
||||||
}}
|
|
||||||
|
|
||||||
list->node_count += node_list.node_count;
|
|
||||||
|
|
||||||
{NodeType} *last = list->last;
|
|
||||||
if (last) {{
|
|
||||||
last->next = node_list.first;
|
|
||||||
}}
|
|
||||||
|
|
||||||
list->last = node_list.last;
|
|
||||||
node_list.first->prev = last;
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");
|
|
||||||
|
|
||||||
{ListType} node_list = {Tlower}_node_to_list(node);
|
|
||||||
|
|
||||||
if (list->node_count == 0) {{
|
|
||||||
*list = node_list;
|
|
||||||
return;
|
|
||||||
}}
|
|
||||||
|
|
||||||
list->node_count += node_list.node_count;
|
|
||||||
|
|
||||||
{NodeType} *first = list->first;
|
|
||||||
if (first) {{
|
|
||||||
first->prev = node_list.last;
|
|
||||||
}}
|
|
||||||
|
|
||||||
list->first = node_list.first;
|
|
||||||
node_list.last->next = first;
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
wapp_debug_assert(list != NULL, "`list` should not be NULL");
|
|
||||||
|
|
||||||
{NodeType} *output = NULL;
|
|
||||||
|
|
||||||
if (index == 0) {{
|
|
||||||
output = wapp_{Tlower}_list_pop_front(list);
|
|
||||||
goto RETURN_{Tupper}_LIST_REMOVE;
|
|
||||||
}} else if (index == list->node_count) {{
|
|
||||||
output = wapp_{Tlower}_list_pop_back(list);
|
|
||||||
goto RETURN_{Tupper}_LIST_REMOVE;
|
|
||||||
}}
|
|
||||||
|
|
||||||
output = wapp_{Tlower}_list_get(list, index);
|
|
||||||
if (!output) {{
|
|
||||||
goto RETURN_{Tupper}_LIST_REMOVE;
|
|
||||||
}}
|
|
||||||
|
|
||||||
output->prev->next = output->next;
|
|
||||||
output->next->prev = output->prev;
|
|
||||||
|
|
||||||
--(list->node_count);
|
|
||||||
|
|
||||||
output->prev = output->next = NULL;
|
|
||||||
|
|
||||||
RETURN_{Tupper}_LIST_REMOVE:
|
|
||||||
return output;
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
{ListType} output = {{.first = node, .last = node, .node_count = 1}};
|
|
||||||
|
|
||||||
while (output.first->prev != NULL) {{
|
|
||||||
output.first = output.first->prev;
|
|
||||||
++(output.node_count);
|
|
||||||
}}
|
|
||||||
|
|
||||||
while (output.last->next != NULL) {{
|
|
||||||
output.last = output.last->next;
|
|
||||||
++(output.node_count);
|
|
||||||
}}
|
|
||||||
|
|
||||||
return output;
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
import os
|
|
||||||
import sys
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
|
|
||||||
def load_func_body_from_file(filename: Path) -> str:
|
|
||||||
with open(filename, "r") as infile:
|
|
||||||
return infile.read().rstrip()
|
|
||||||
|
|
||||||
|
|
||||||
def convert_to_relative(path: Path, target: Path) -> Path:
|
|
||||||
major = sys.version_info.major
|
|
||||||
minor = sys.version_info.minor
|
|
||||||
|
|
||||||
if major >= 3 and minor >= 12:
|
|
||||||
return path.relative_to(target, walk_up=True)
|
|
||||||
else:
|
|
||||||
return Path(os.path.relpath(str(path), start=str(target)))
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
{
|
|
||||||
"dbl_list_data": {
|
|
||||||
"CustomType": {
|
|
||||||
"node_typename": "CustomTypeNode",
|
|
||||||
"list_typename": "CustomTypeList",
|
|
||||||
"hdr_decl_types": [
|
|
||||||
{
|
|
||||||
"name": "custom_type",
|
|
||||||
"cargs": [],
|
|
||||||
"typedef_name": "CustomType"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"src_decl_types": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user