Update codegen to support accepting JSON file as input
This commit is contained in:
parent
1e224702a3
commit
26fd329caa
@ -1,23 +1,60 @@
|
|||||||
|
import json
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
from codegen.datatypes import CDataType
|
from pathlib import Path
|
||||||
|
from codegen.datatypes import CDataType, CStruct
|
||||||
|
from codegen.constants import WAPP_REPO_ROOT, DBL_LIST_DATA, ARRAY_DATA
|
||||||
from codegen.dbl_list.make_dbl_list import DblListData, make_dbl_list
|
from codegen.dbl_list.make_dbl_list import DblListData, make_dbl_list
|
||||||
from codegen.array.make_array import ArrayData, make_array
|
from codegen.array.make_array import ArrayData, make_array
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main(types_file: Path | None):
|
||||||
gen_dbl_list()
|
dbl_list_datatypes: Dict[CDataType, DblListData] = {}
|
||||||
gen_array()
|
array_datatypes: Dict[CDataType, ArrayData] = {}
|
||||||
|
|
||||||
|
if types_file is not None:
|
||||||
|
with types_file.open("r") as infile:
|
||||||
|
datatypes = json.load(infile)
|
||||||
|
dbl_list_data = datatypes.get(DBL_LIST_DATA)
|
||||||
|
array_data = datatypes.get(ARRAY_DATA)
|
||||||
|
|
||||||
def gen_dbl_list():
|
if dbl_list_data is not None and isinstance(dbl_list_data, dict):
|
||||||
datatypes: Dict[CDataType, DblListData] = {}
|
dbl_list_datatypes = {k: DblListData.from_dict(v) for k, v in dbl_list_data.items()}
|
||||||
make_dbl_list(datatypes)
|
|
||||||
|
|
||||||
|
if array_data is not None and isinstance(array_data, dict):
|
||||||
|
array_datatypes = {k: ArrayData.from_dict(v) for k, v in array_data.items()}
|
||||||
|
|
||||||
def gen_array():
|
make_dbl_list(dbl_list_datatypes)
|
||||||
datatypes: Dict[CDataType, ArrayData] = {}
|
make_array(array_datatypes)
|
||||||
make_array(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()
|
||||||
|
},
|
||||||
|
ARRAY_DATA: {
|
||||||
|
"CustomType": ArrayData(
|
||||||
|
array_typename="CustomTypeArray",
|
||||||
|
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__":
|
if __name__ == "__main__":
|
||||||
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,6 +1,6 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from typing import List, Dict
|
from typing import List, Dict, Any, Type
|
||||||
from codegen.constants import WAPP_SRC_ROOT
|
from codegen.constants import WAPP_SRC_ROOT
|
||||||
from codegen.utils import load_func_body_from_file, convert_to_relative
|
from codegen.utils import load_func_body_from_file, convert_to_relative
|
||||||
from codegen.datatypes import (
|
from codegen.datatypes import (
|
||||||
@ -16,16 +16,24 @@ from codegen.datatypes import (
|
|||||||
CPointerType,
|
CPointerType,
|
||||||
CQualifier,
|
CQualifier,
|
||||||
CInclude,
|
CInclude,
|
||||||
|
SerialisableDataclass,
|
||||||
get_datatype_string,
|
get_datatype_string,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class ArrayData:
|
class ArrayData(SerialisableDataclass):
|
||||||
array_typename: str
|
array_typename: str
|
||||||
hdr_decl_types: List[CStruct] = field(default_factory=list)
|
hdr_decl_types: List[CStruct] = field(default_factory=list)
|
||||||
src_decl_types: List[CStruct] = field(default_factory=list)
|
src_decl_types: List[CStruct] = field(default_factory=list)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_dict(cls: Type["ArrayData"], d: Dict[str, Any]) -> "ArrayData":
|
||||||
|
data = ArrayData(**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_array(user_datatypes: Dict[CDataType, ArrayData] = {}):
|
def make_array(user_datatypes: Dict[CDataType, ArrayData] = {}):
|
||||||
def __format_func_body(
|
def __format_func_body(
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
# Paths
|
||||||
PACKAGE_DIR = Path(__file__).parent.resolve()
|
PACKAGE_DIR = Path(__file__).parent.resolve()
|
||||||
WAPP_SRC_ROOT = PACKAGE_DIR.parent / "src"
|
WAPP_REPO_ROOT = PACKAGE_DIR.parent
|
||||||
|
WAPP_SRC_ROOT = WAPP_REPO_ROOT / "src"
|
||||||
|
|
||||||
|
# Dictionary Keys
|
||||||
|
DBL_LIST_DATA = "dbl_list_data"
|
||||||
|
ARRAY_DATA = "array_data"
|
||||||
|
@ -1,11 +1,69 @@
|
|||||||
from enum import Enum
|
from enum import Enum
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Optional, Union, List
|
from typing import Optional, Union, List, Dict, Type, Any, TypeVar, cast
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, asdict, field, fields
|
||||||
|
|
||||||
from codegen.constants import WAPP_SRC_ROOT
|
from codegen.constants import WAPP_SRC_ROOT
|
||||||
from codegen.utils import convert_to_relative
|
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):
|
class CType(Enum):
|
||||||
VOID = "void"
|
VOID = "void"
|
||||||
@ -53,16 +111,23 @@ class CPointerType(Enum):
|
|||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class CPointer:
|
class CPointer(SerialisableDataclass):
|
||||||
_type: CPointerType = CPointerType.NONE
|
_type: CPointerType = CPointerType.NONE
|
||||||
qualifier: CQualifier = CQualifier.NONE
|
qualifier: CQualifier = CQualifier.NONE
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
return str(self._type) + str(self.qualifier)
|
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
|
@dataclass
|
||||||
class CEnumVal:
|
class CEnumVal(SerialisableDataclass):
|
||||||
name: str
|
name: str
|
||||||
value: Optional[int] = None
|
value: Optional[int] = None
|
||||||
|
|
||||||
@ -71,7 +136,7 @@ class CEnumVal:
|
|||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class CEnum:
|
class CEnum(SerialisableDataclass):
|
||||||
name: str
|
name: str
|
||||||
values: List[CEnumVal]
|
values: List[CEnumVal]
|
||||||
typedef: bool = False
|
typedef: bool = False
|
||||||
@ -90,9 +155,15 @@ class CEnum:
|
|||||||
|
|
||||||
return header + values + footer
|
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
|
@dataclass
|
||||||
class CMacro:
|
class CMacro(SerialisableDataclass):
|
||||||
name: str
|
name: str
|
||||||
value: str
|
value: str
|
||||||
|
|
||||||
@ -101,7 +172,7 @@ class CMacro:
|
|||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class CStruct:
|
class CStruct(SerialisableDataclass):
|
||||||
name: str
|
name: str
|
||||||
cargs: List["CArg"]
|
cargs: List["CArg"]
|
||||||
typedef_name: Optional[str] = None
|
typedef_name: Optional[str] = None
|
||||||
@ -122,13 +193,19 @@ class CStruct:
|
|||||||
|
|
||||||
return definition + args + footer;
|
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]
|
CUserType = Union[CStruct, CEnum]
|
||||||
CDataType = Union[CType, CUserType, str]
|
CDataType = Union[CType, CUserType, str]
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class CArg:
|
class CArg(SerialisableDataclass):
|
||||||
name: str
|
name: str
|
||||||
_type: CDataType
|
_type: CDataType
|
||||||
array: bool = False
|
array: bool = False
|
||||||
@ -143,9 +220,21 @@ class CArg:
|
|||||||
|
|
||||||
return qualifier + _type + pointer + self.name + array
|
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
|
@dataclass
|
||||||
class CFunc:
|
class CFunc(SerialisableDataclass):
|
||||||
name: str
|
name: str
|
||||||
ret_type: CDataType
|
ret_type: CDataType
|
||||||
args: List[CArg]
|
args: List[CArg]
|
||||||
@ -176,9 +265,21 @@ class CFunc:
|
|||||||
def define(self) -> str:
|
def define(self) -> str:
|
||||||
return f"{str(self)} {{\n{self.body}\n}}\n\n"
|
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
|
@dataclass
|
||||||
class CInclude:
|
class CInclude(SerialisableDataclass):
|
||||||
header: Union[str, "CHeader"]
|
header: Union[str, "CHeader"]
|
||||||
local: bool = False
|
local: bool = False
|
||||||
same_dir: bool = False
|
same_dir: bool = False
|
||||||
@ -201,9 +302,18 @@ class CInclude:
|
|||||||
|
|
||||||
return f"#include {open_symbol}{name}{close_symbol}\n"
|
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
|
@dataclass
|
||||||
class CFile:
|
class CFile(SerialisableDataclass):
|
||||||
name: str
|
name: str
|
||||||
extension: str
|
extension: str
|
||||||
includes: List[CInclude] = field(default_factory=list)
|
includes: List[CInclude] = field(default_factory=list)
|
||||||
@ -239,6 +349,22 @@ class CFile:
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@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
|
@dataclass
|
||||||
class CHeader(CFile):
|
class CHeader(CFile):
|
||||||
@ -297,6 +423,10 @@ class CHeader(CFile):
|
|||||||
header_guard_close
|
header_guard_close
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_dict(cls: Type["CHeader"], d: Dict[str, Any]) -> "CHeader":
|
||||||
|
return cast("CHeader", super().from_dict(d))
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class CSource(CFile):
|
class CSource(CFile):
|
||||||
@ -346,6 +476,13 @@ class CSource(CFile):
|
|||||||
internal_funcs_def
|
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:
|
def get_datatype_string(_type: CDataType) -> str:
|
||||||
if isinstance(_type, CType):
|
if isinstance(_type, CType):
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from typing import List, Dict
|
from typing import List, Dict, Any, Type
|
||||||
from codegen.constants import WAPP_SRC_ROOT
|
from codegen.constants import WAPP_SRC_ROOT
|
||||||
from codegen.utils import load_func_body_from_file, convert_to_relative
|
from codegen.utils import load_func_body_from_file, convert_to_relative
|
||||||
from codegen.datatypes import (
|
from codegen.datatypes import (
|
||||||
@ -16,17 +16,25 @@ from codegen.datatypes import (
|
|||||||
CPointerType,
|
CPointerType,
|
||||||
CQualifier,
|
CQualifier,
|
||||||
CInclude,
|
CInclude,
|
||||||
|
SerialisableDataclass,
|
||||||
get_datatype_string,
|
get_datatype_string,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class DblListData:
|
class DblListData(SerialisableDataclass):
|
||||||
node_typename: str
|
node_typename: str
|
||||||
list_typename: str
|
list_typename: str
|
||||||
hdr_decl_types: List[CStruct] = field(default_factory=list)
|
hdr_decl_types: List[CStruct] = field(default_factory=list)
|
||||||
src_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 make_dbl_list(user_datatypes: Dict[CDataType, DblListData] = {}):
|
||||||
def __format_func_body(
|
def __format_func_body(
|
||||||
|
29
codegen_custom_data_example.json
Normal file
29
codegen_custom_data_example.json
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"dbl_list_data": {
|
||||||
|
"CustomType": {
|
||||||
|
"node_typename": "CustomTypeNode",
|
||||||
|
"list_typename": "CustomTypeList",
|
||||||
|
"hdr_decl_types": [
|
||||||
|
{
|
||||||
|
"name": "custom_type",
|
||||||
|
"cargs": [],
|
||||||
|
"typedef_name": "CustomType"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"src_decl_types": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"array_data": {
|
||||||
|
"CustomType": {
|
||||||
|
"array_typename": "CustomTypeArray",
|
||||||
|
"hdr_decl_types": [
|
||||||
|
{
|
||||||
|
"name": "custom_type",
|
||||||
|
"cargs": [],
|
||||||
|
"typedef_name": "CustomType"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"src_decl_types": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user