Compare commits

..

22 Commits

Author SHA1 Message Date
9ac75ebc8c Add newline at start of c linkage closing 2025-03-02 13:16:03 +00:00
a7742ffcb5 Fix missing newline after c linkage 2025-03-02 13:14:50 +00:00
bc0816e76d Switch to using header guards and add c linkage 2025-03-02 13:13:27 +00:00
1f22745e05 Add support for relative include 2025-03-02 12:58:16 +00:00
b8e2f8a4d7 Add support for forward declarations 2025-03-02 12:52:14 +00:00
a9791962b0 Update struct to split declaration and definition 2025-03-02 12:45:42 +00:00
cb093cc030 Move load_func_body_from_file to utils module 2025-03-02 12:20:02 +00:00
8029d26c6b Revert "Restructure to keep __main__ free to be used when using codegen as part"
This reverts commit 87abfe8900.
2025-03-02 12:07:28 +00:00
87abfe8900 Restructure to keep __main__ free to be used when using codegen as part
of another project
2025-03-02 11:58:25 +00:00
acaae99107 Update snippets dir 2025-03-02 11:53:15 +00:00
Abdelrahman Said
7b16c7511f Update list example 2025-03-01 22:43:43 +00:00
Abdelrahman Said
f3fc2d5c41 Ensure includes are sorted local first 2025-03-01 22:43:16 +00:00
Abdelrahman Said
b7264e20f2 Add example for doubly linked list 2025-03-01 22:34:17 +00:00
Abdelrahman Said
6f2cdd8d62 Update datatypes 2025-03-01 22:33:53 +00:00
8d0c731b72 Use _get_arg_type_string when stringifying function return type 2025-02-08 16:14:19 +00:00
f95d68f3d2 Add a test for a generic typed array 2025-02-08 16:09:25 +00:00
2bc4d3bd5e Improve datatypes codegen 2025-02-08 16:09:08 +00:00
a8f989b76d Update .gitignore 2025-02-08 16:08:29 +00:00
51a8c66bc3 Ignore C header and source files 2025-02-08 15:31:14 +00:00
c562850645 Add run script 2025-02-07 22:40:55 +00:00
6ac6009918 Split code to smaller modules 2025-02-07 22:40:41 +00:00
3a138ec3fa Add .gitignore 2025-02-07 22:40:30 +00:00
17 changed files with 802 additions and 331 deletions

4
.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
__pycache__
*.c
*.h
main

View File

@@ -1,331 +0,0 @@
from enum import Enum
from pathlib import Path
from typing import Optional, Union
from dataclasses import dataclass, field
class CType(Enum):
VOID = "void "
BOOL = "bool "
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 = "external "
INTERNAL = "internal "
PERSISTENT = "persistent "
def __str__(self) -> str:
return self.value
class CPointerType(Enum):
NONE = ""
SINGLE = "*"
DOUBLE = "**"
def __str__(self) -> str:
return self.value
@dataclass
class CPointer:
_type: CPointerType = CPointerType.NONE
qualifier: CQualifier = CQualifier.NONE
def __str__(self) -> str:
return str(self._type) + str(self.qualifier)
@dataclass
class CEnumVal:
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:
name: str
values: list[CEnumVal]
typedef: bool = False
@dataclass
class CStruct:
name: str
cargs: list["CArg"]
CUserType = Union[CStruct, CEnum]
CDataType = Union[CType, CUserType]
@dataclass
class CArg:
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_arg_type_string(self._type)
pointer = str(self.pointer)
array = "[]" if self.array else ""
return qualifier + _type + pointer + self.name + array
@dataclass
class CFunc:
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 qualifiers:
if qualifier == CQualifier.NONE:
continue
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 + str(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"
@dataclass
class CInclude:
header: Union[str, "CHeader"]
local: bool = False
@dataclass
class CFile:
name: str
def save(self, output_dir: Path):
output_file = output_dir / self.name
with open(output_file, "w+") as outfile:
outfile.write(str(self))
def __str__(self) -> str:
return ""
@dataclass
class CHeader(CFile):
includes: list[CInclude]
types: list[CUserType]
funcs: list[CFunc]
def __str__(self) -> str:
pragma = "#pragma once\n\n"
includes = get_includes_string(self.includes)
types = ""
for _type in self.types:
types += get_user_type_string(_type)
funcs = ""
for func in self.funcs:
funcs += func.declare()
return pragma + includes + types + funcs
@dataclass
class CSource(CFile):
includes: list[CInclude]
types: list[CUserType]
internal_funcs: list[CFunc]
funcs: list[CFunc]
def __str__(self) -> str:
includes = get_includes_string(self.includes)
types = ""
for _type in self.types:
types += get_user_type_string(_type)
internal_funcs_decl = ""
internal_funcs_def = ""
for func in self.internal_funcs:
internal_funcs_decl += func.declare()
internal_funcs_def += func.define()
funcs = ""
for func in self.funcs:
funcs += func.define()
return includes + types + internal_funcs_decl + funcs + internal_funcs_def
def main():
struct = CStruct(
name="Str8",
cargs=[
CArg(name="size", _type=CType.U64),
CArg(name="capacity", _type=CType.U64),
CArg(name="buf", _type=CType.U8, pointer=CPointer(_type=CPointerType.SINGLE)),
],
)
cenum = CEnum(
name="OS",
values=[
CEnumVal(name="OS_LINUX"),
CEnumVal(name="OS_WINDOWS"),
CEnumVal(name="OS_MACOS"),
]
)
typed_enum = CEnum(
name="Compiler",
values=[
CEnumVal(name="COMPILER_GCC"),
CEnumVal(name="COMPILER_CLANG"),
CEnumVal(name="COMPILER_MSVC"),
],
typedef=True,
)
main_func = CFunc(
name="my_custom_func",
ret_type=CType.I32,
args=[
CArg(name="argc", _type=CType.I32),
CArg(name="argv", _type=CType.CHAR, pointer=CPointer(_type=CPointerType.DOUBLE), qualifier=CQualifier.CONST),
],
body=" return 0;"
)
header = CHeader(
name="str.h",
includes=[
CInclude(header="aliases.h", local=True),
],
types=[struct, cenum, typed_enum],
funcs=[main_func],
)
source = CSource(
name="str.c",
includes=[
CInclude(header=header, local=True),
CInclude(header="aliases.h", local=True),
],
types=[],
internal_funcs=[],
funcs=[main_func]
)
header.save(Path("."))
source.save(Path("."))
def get_user_type_string(_type: Union[CStruct, CEnum]) -> str:
type_str = ""
if isinstance(_type, CStruct):
type_str += cstruct_to_string(_type) + "\n"
else:
type_str += cenum_to_string(_type) + "\n"
return type_str
def cenum_to_string(cenum: CEnum) -> str:
if cenum.typedef:
header = "typedef enum {\n"
footer = f"}} {cenum.name};\n"
else:
header = f"enum {cenum.name} {{\n"
footer = "};\n"
values = ""
for value in cenum.values:
values += f" {str(value)},\n"
return header + values + footer
def cstruct_to_string(cstruct: CStruct) -> str:
typedef = f"typedef struct {cstruct.name} {cstruct.name};\n"
header = f"struct {cstruct.name} {{\n"
args = ""
for arg in cstruct.cargs:
args += f" {str(arg)};\n"
footer = "};\n"
return typedef + header + args + footer;
def get_arg_type_string(_type: CDataType) -> str:
if isinstance(_type, CType):
return str(_type)
elif isinstance(_type, CStruct) or isinstance(_type, CEnum):
return _type.name
def get_includes_string(includes: list[CInclude]) -> str:
output = ""
for include in includes:
if isinstance(include.header, CHeader):
name = include.header.name
else:
name = include.header
if include.local:
open_symbol = '"'
close_symbol = '"'
else:
open_symbol = '<'
close_symbol = '>'
output += f"#include {open_symbol}{name}{close_symbol}\n"
if len(output) > 0:
output += "\n"
return output
if __name__ == "__main__":
main()

0
codegen/__init__.py Normal file
View File

6
codegen/__main__.py Normal file
View File

@@ -0,0 +1,6 @@
from .codegen import test_str8, test_doubly_linked_list, test_typed_array
if __name__ == "__main__":
test_str8()
test_typed_array()
test_doubly_linked_list()

310
codegen/codegen.py Normal file
View File

@@ -0,0 +1,310 @@
from pathlib import Path
from .utils import load_func_body_from_file
from .datatypes import (
CDataType,
CStruct,
CEnum,
CEnumVal,
CFunc,
CHeader,
CSource,
CArg,
CType,
CPointer,
CPointerType,
CQualifier,
CInclude,
CUserType,
get_datatype_string,
)
def test_str8():
struct = CStruct(
name="Str8",
cargs=[
CArg(name="size", _type=CType.U64),
CArg(name="capacity", _type=CType.U64),
CArg(name="buf", _type=CType.U8, pointer=CPointer(_type=CPointerType.SINGLE)),
],
)
cenum = CEnum(
name="OS",
values=[
CEnumVal(name="OS_LINUX"),
CEnumVal(name="OS_WINDOWS"),
CEnumVal(name="OS_MACOS"),
]
)
typed_enum = CEnum(
name="Compiler",
values=[
CEnumVal(name="COMPILER_GCC"),
CEnumVal(name="COMPILER_CLANG"),
CEnumVal(name="COMPILER_MSVC"),
],
typedef=True,
)
main_func = CFunc(
name="my_custom_func",
ret_type=CType.I32,
args=[
CArg(name="argc", _type=CType.I32),
CArg(name="argv", _type=CType.CHAR, pointer=CPointer(_type=CPointerType.DOUBLE), qualifier=CQualifier.CONST),
],
body=" return 0;"
)
header = CHeader(
name="str",
includes=[
CInclude(header="aliases.h", local=True),
],
types=[struct, cenum, typed_enum],
funcs=[main_func],
)
source = CSource(
name="str",
includes=[
CInclude(header=header, local=True),
CInclude(header="aliases.h", local=True),
],
types=[],
internal_funcs=[],
funcs=[main_func]
)
header.save(Path("."))
source.save(Path("."))
def test_typed_array():
datatypes = [CType.U8, CType.F32, CType.CHAR]
types: list[CUserType] = []
funcs: list[CFunc] = []
getter_func_body = """\
if(idx >= arr->size) {
return 0;
}
return arr->data[idx];"""
setter_func_body = """\
if(idx >= arr->size) {
return;
}
arr->data[idx] = val;"""
for _type in datatypes:
struct = CStruct(
name=f"Array{str(_type).title()}".strip(),
cargs=[
CArg(name="size", _type=CType.U64),
CArg(name="data", _type=_type, pointer=CPointer(_type=CPointerType.SINGLE)),
],
)
types.append(struct)
funcs.append(CFunc(
name=f"array_{str(_type)}_get",
ret_type=_type,
args=[
CArg(name="arr", _type=struct, pointer=CPointer(_type=CPointerType.SINGLE), qualifier=CQualifier.CONST),
CArg(name="idx", _type=CType.U64),
],
body=getter_func_body,
))
funcs.append(CFunc(
name=f"array_{str(_type)}_set",
ret_type=CType.VOID,
args=[
CArg(name="arr", _type=struct, pointer=CPointer(_type=CPointerType.SINGLE)),
CArg(name="idx", _type=CType.U64),
CArg(name="val", _type=_type)
],
body=setter_func_body,
))
header = CHeader(
name="typed_array",
includes=[
CInclude(header="aliases.h", local=True)
],
types=types,
funcs=funcs
)
source = CSource(
name="typed_array",
includes=[
CInclude(header="aliases.h", local=True),
CInclude(header=header, local=True)
],
funcs=funcs
)
header.save(Path("."))
source.save(Path("."))
def test_doubly_linked_list():
def __format_func_body(filename: Path, type_string: str):
return load_func_body_from_file(filename).format(
T=type_string,
Tupper=type_string.upper(),
Tlower=type_string.lower(),
)
datatypes: dict[CDataType, list[CInclude]] = {"Str8": [CInclude(header="str8.h", local=True)]}
snippets_dir = Path(__file__).parent / "snippets"
for _type, includes in datatypes.items():
type_string = get_datatype_string(_type)
node = CStruct(
name=f"{type_string}Node",
cargs=[
CArg(name="string", _type=type_string, pointer=CPointer(_type=CPointerType.SINGLE)),
CArg(name="prev", _type=f"{type_string}Node", pointer=CPointer(_type=CPointerType.SINGLE)),
CArg(name="next", _type=f"{type_string}Node", pointer=CPointer(_type=CPointerType.SINGLE)),
],
)
dl_list = CStruct(
name=f"{type_string}List",
cargs=[
CArg(name="first", _type=node, pointer=CPointer(_type=CPointerType.SINGLE)),
CArg(name="last", _type=node, pointer=CPointer(_type=CPointerType.SINGLE)),
CArg(name="total_size", _type=CType.U64),
CArg(name="node_count", _type=CType.U64),
],
)
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(snippets_dir / "list_get", type_string),
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(snippets_dir / "list_push_front", type_string),
)
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(snippets_dir / "list_push_back", type_string),
)
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(snippets_dir / "list_insert", type_string),
)
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(snippets_dir / "list_pop_front", type_string),
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(snippets_dir / "list_pop_back", type_string),
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(snippets_dir / "list_remove", type_string),
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(snippets_dir / "list_empty", type_string),
)
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(snippets_dir / "node_to_list", type_string),
qualifiers=[CQualifier.INTERNAL],
)
header = CHeader(
name=f"{type_string.lower()}_list",
includes=[CInclude(header="aliases.h", local=True)],
types=[node, dl_list],
funcs=[
get_func,
push_front_func,
push_back_func,
insert_func,
pop_front_func,
pop_back_func,
remove_func,
empty_func,
]
)
source = CSource(
name=header.name,
includes=[CInclude(header="aliases.h", local=True), CInclude(header, local=True), CInclude(header="stddef.h")],
internal_funcs=[node_to_list_func],
funcs=header.funcs
)
if len(includes) > 0:
header.includes.extend(includes)
source.includes.extend(includes)
header.save(Path("."))
source.save(Path("."))

296
codegen/datatypes.py Normal file
View File

@@ -0,0 +1,296 @@
from enum import Enum
from pathlib import Path
from typing import Optional, Union
from dataclasses import dataclass, field
class CType(Enum):
VOID = "void"
BOOL = "bool"
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 = "external "
INTERNAL = "internal "
PERSISTENT = "persistent "
def __str__(self) -> str:
return self.value
class CPointerType(Enum):
NONE = ""
SINGLE = "*"
DOUBLE = "**"
def __str__(self) -> str:
return self.value
@dataclass
class CPointer:
_type: CPointerType = CPointerType.NONE
qualifier: CQualifier = CQualifier.NONE
def __str__(self) -> str:
return str(self._type) + str(self.qualifier)
@dataclass
class CEnumVal:
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:
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
@dataclass
class CStruct:
name: str
cargs: list["CArg"]
typedef_name: str | None = 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;
CUserType = Union[CStruct, CEnum]
CDataType = Union[CType, CUserType, str]
@dataclass
class CArg:
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
@dataclass
class CFunc:
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"
@dataclass
class CInclude:
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"
@dataclass
class CFile:
name: str
extension: str
decl_types: list[CStruct] = field(default_factory=list)
def save(self, output_dir: Path):
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 ""
@dataclass
class CHeader(CFile):
extension: str = "h"
includes: list[CInclude] = field(default_factory=list)
types: list[CUserType] = field(default_factory=list)
funcs: list[CFunc] = field(default_factory=list)
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 __cplusplus\nBEGIN_C_LINKAGE\n#endif // !__cplusplus\n\n"
c_linkage_close = "\n#ifdef __cplusplus\nEND_C_LINKAGE\n#endif // !__cplusplus\n\n"
includes = _get_includes_string(self.includes)
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 header_guard_open + includes + c_linkage_open + forward_declarations + types + funcs + c_linkage_close + header_guard_close
@dataclass
class CSource(CFile):
extension: str = "c"
includes: list[CInclude] = field(default_factory=list)
types: list[CUserType] = field(default_factory=list)
internal_funcs: list[CFunc] = field(default_factory=list)
funcs: list[CFunc] = field(default_factory=list)
def __str__(self) -> str:
includes = _get_includes_string(self.includes)
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 includes + forward_declarations + types + internal_funcs_decl + funcs + internal_funcs_def
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

View File

@@ -0,0 +1,8 @@
if (!list) {{
return;
}}
u64 count = list->node_count;
for (u64 i = 0; i < count; ++i) {{
wapp_str8_list_pop_back(list);
}}

13
codegen/snippets/list_get Normal file
View File

@@ -0,0 +1,13 @@
if (index >= list->node_count) {{
return NULL;
}}
{T}Node *output = NULL;
{T}Node *current = list->first;
for (u64 i = 1; i <= index; ++i) {{
current = current->next;
}}
output = current;
return output;

View File

@@ -0,0 +1,29 @@
if (!list || !node || !(node->string)) {{
return;
}}
if (index == 0) {{
wapp_str8_list_push_front(list, node);
return;
}} else if (index == list->node_count) {{
wapp_str8_list_push_back(list, node);
return;
}}
{T}Node *dst_node = wapp_str8_list_get(list, index);
if (!dst_node) {{
return;
}}
{T}List node_list = {Tlower}_node_to_list(node);
list->total_size += node_list.total_size;
list->node_count += node_list.node_count;
{T}Node *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;

View File

@@ -0,0 +1,21 @@
{T}Node *output = NULL;
if (!list || list->node_count == 0) {{
goto RETURN_{Tupper}_LIST_POP_BACK;
}}
output = list->last;
if (list->node_count == 1) {{
*list = ({T}List){{0}};
goto RETURN_{Tupper}_LIST_POP_BACK;
}}
--(list->node_count);
list->total_size -= output->string->size;
list->last = output->prev;
output->prev = output->next = NULL;
RETURN_{Tupper}_LIST_POP_BACK:
return output;

View File

@@ -0,0 +1,21 @@
{T}Node *output = NULL;
if (!list || list->node_count == 0) {{
goto RETURN_{Tupper}_LIST_POP_FRONT;
}}
output = list->first;
if (list->node_count == 1) {{
*list = ({T}List){{0}};
goto RETURN_{Tupper}_LIST_POP_FRONT;
}}
--(list->node_count);
list->total_size -= output->string->size;
list->first = output->next;
output->prev = output->next = NULL;
RETURN_{Tupper}_LIST_POP_FRONT:
return output;

View File

@@ -0,0 +1,21 @@
if (!list || !node || !(node->string)) {{
return;
}}
{T}List node_list = {Tlower}_node_to_list(node);
if (list->node_count == 0) {{
*list = node_list;
return;
}}
list->total_size += node_list.total_size;
list->node_count += node_list.node_count;
{T}Node *last = list->last;
if (last) {{
last->next = node_list.first;
}}
list->last = node_list.last;
node_list.first->prev = last;

View File

@@ -0,0 +1,21 @@
if (!list || !node || !(node->string)) {{
return;
}}
{T}List node_list = {Tlower}_node_to_list(node);
if (list->node_count == 0) {{
*list = node_list;
return;
}}
list->total_size += node_list.total_size;
list->node_count += node_list.node_count;
{T}Node *first = list->first;
if (first) {{
first->prev = node_list.last;
}}
list->first = node_list.first;
node_list.last->next = first;

View File

@@ -0,0 +1,28 @@
{T}Node *output = NULL;
if (!list) {{
goto RETURN_{Tupper}_LIST_REMOVE;
}}
if (index == 0) {{
output = wapp_str8_list_pop_front(list);
goto RETURN_{Tupper}_LIST_REMOVE;
}} else if (index == list->node_count) {{
output = wapp_str8_list_pop_back(list);
goto RETURN_{Tupper}_LIST_REMOVE;
}}
output = wapp_str8_list_get(list, index);
if (!output) {{
goto RETURN_{Tupper}_LIST_REMOVE;
}}
output->prev->next = output->next;
output->next->prev = output->prev;
--(list->node_count);
list->total_size -= output->string->size;
output->prev = output->next = NULL;
RETURN_{Tupper}_LIST_REMOVE:
return output;

View File

@@ -0,0 +1,15 @@
{T}List output = {{.first = node, .last = node, .total_size = node->string->size, .node_count = 1}};
while (output.first->prev != NULL) {{
output.total_size += output.first->prev->string->size;
output.first = output.first->prev;
++(output.node_count);
}}
while (output.last->next != NULL) {{
output.total_size += output.last->next->string->size;
output.last = output.last->next;
++(output.node_count);
}}
return output;

6
codegen/utils.py Normal file
View File

@@ -0,0 +1,6 @@
from pathlib import Path
def load_func_body_from_file(filename: Path) -> str:
with open(filename, "r") as infile:
return infile.read()

3
run Executable file
View File

@@ -0,0 +1,3 @@
#!/bin/bash
python3 -m codegen