2024-08-09 11:28:44 +08:00
|
|
|
import typing
|
|
|
|
|
import re
|
|
|
|
|
|
|
|
|
|
class FieldDecl():
|
|
|
|
|
c_EnumTuple: typing.ClassVar[tuple[str, ...]] = (
|
|
|
|
|
'VSW::DataTypes::ParameterLinkIOType',
|
|
|
|
|
'VSW::DataTypes::BehaviorLinkIOType'
|
|
|
|
|
)
|
2024-08-06 18:06:17 +08:00
|
|
|
|
|
|
|
|
m_DeclType: str
|
|
|
|
|
m_DeclName: str
|
|
|
|
|
|
|
|
|
|
def __init__(self, decl_type: str, decl_name: str):
|
|
|
|
|
self.m_DeclType = decl_type
|
|
|
|
|
self.m_DeclName = decl_name
|
|
|
|
|
|
|
|
|
|
def is_string(self):
|
|
|
|
|
return self.m_DeclType == 'YYCC::yycc_u8string'
|
|
|
|
|
|
2024-08-09 11:28:44 +08:00
|
|
|
def is_blob(self):
|
|
|
|
|
return self.m_DeclType == 'BlobDescriptor'
|
|
|
|
|
|
2024-08-06 18:06:17 +08:00
|
|
|
def is_int64(self):
|
|
|
|
|
return self.m_DeclType == 'int64_t'
|
2024-08-09 11:28:44 +08:00
|
|
|
|
|
|
|
|
def is_enum(self):
|
|
|
|
|
return self.m_DeclType in FieldDecl.c_EnumTuple
|
|
|
|
|
|
|
|
|
|
class StructDecl():
|
|
|
|
|
m_StructName: str
|
|
|
|
|
m_StructFields: tuple[FieldDecl, ...]
|
2024-08-06 18:06:17 +08:00
|
|
|
|
2024-08-09 11:28:44 +08:00
|
|
|
def __init__(self, name: str, fields: tuple[FieldDecl, ...]):
|
|
|
|
|
self.m_StructName = name
|
|
|
|
|
self.m_StructFields = fields
|
|
|
|
|
|
|
|
|
|
def accept_input() -> str:
|
|
|
|
|
cache: list[str] = list()
|
2024-08-06 18:06:17 +08:00
|
|
|
blank_line: bool = False
|
|
|
|
|
|
|
|
|
|
while True:
|
|
|
|
|
recv: str = input("> ")
|
|
|
|
|
if len(recv) == 0:
|
|
|
|
|
# If double blank line, exit
|
|
|
|
|
# Otherwise set blank line flag
|
|
|
|
|
if blank_line: break
|
|
|
|
|
else: blank_line = True
|
|
|
|
|
else:
|
|
|
|
|
# Reset blank line flag
|
|
|
|
|
blank_line = False
|
2024-08-09 11:28:44 +08:00
|
|
|
cache.append(recv)
|
|
|
|
|
|
|
|
|
|
return '\n'.join(cache)
|
|
|
|
|
|
|
|
|
|
def analyse_input(val: str) -> tuple[StructDecl, ...]:
|
|
|
|
|
# result container
|
|
|
|
|
ret: list[StructDecl] = list()
|
|
|
|
|
# regex for capturing struct declarations
|
|
|
|
|
struct_matcher: re.Pattern = re.compile('struct[ \t]+([a-zA-Z0-9_]+)[ \t]+{([^}]*)};')
|
|
|
|
|
# regex for capturing struct field declarations
|
|
|
|
|
field_matcher: re.Pattern = re.compile('([a-zA-Z0-9_:]+)[ \t]+([a-zA-Z0-9_]+)[ \t]*;')
|
|
|
|
|
|
|
|
|
|
# capture struct declaration part
|
|
|
|
|
found_match: re.Match
|
|
|
|
|
for found_match in struct_matcher.finditer(val):
|
|
|
|
|
# get struct name
|
|
|
|
|
struct_name: str = found_match.group(1)
|
|
|
|
|
# analyse struct body
|
|
|
|
|
struct_body: str = found_match.group(2)
|
|
|
|
|
struct_fields: list[FieldDecl] = []
|
|
|
|
|
for ln in struct_body.split('\n'):
|
2024-08-06 18:06:17 +08:00
|
|
|
# Skip annotation
|
2024-08-09 11:28:44 +08:00
|
|
|
ln = ln.strip()
|
|
|
|
|
if ln.startswith('//'): continue
|
|
|
|
|
# Check whether it is declaration
|
|
|
|
|
found_field_match: re.Match = field_matcher.match(ln)
|
|
|
|
|
if found_field_match is not None:
|
|
|
|
|
field_decl_type: str = found_field_match.group(1)
|
|
|
|
|
field_decl_name: str = found_field_match.group(2)
|
|
|
|
|
struct_fields.append(FieldDecl(field_decl_type, field_decl_name))
|
|
|
|
|
# add into result
|
|
|
|
|
ret.append(StructDecl(struct_name, tuple(struct_fields)))
|
2024-08-06 18:06:17 +08:00
|
|
|
|
2024-08-09 11:28:44 +08:00
|
|
|
return tuple(ret)
|
2024-08-06 18:06:17 +08:00
|
|
|
|
2024-08-09 11:28:44 +08:00
|
|
|
def output_result(decls: tuple[StructDecl, ...]) -> None:
|
|
|
|
|
# assistant function for sql create table statement
|
|
|
|
|
def conv_sql_create_table(decl_pair: FieldDecl) -> str:
|
|
|
|
|
if decl_pair.is_string(): return f'[{decl_pair.m_DeclName}] TEXT'
|
|
|
|
|
elif decl_pair.is_blob(): return f'[{decl_pair.m_DeclName}] BLOB'
|
|
|
|
|
else: return f'[{decl_pair.m_DeclName}] INTEGER'
|
|
|
|
|
# assistant function for sql insert statement
|
|
|
|
|
def conv_sql_insert(decl_pair: FieldDecl) -> str:
|
|
|
|
|
return '?'
|
|
|
|
|
# assistant function for c++ bind statement
|
|
|
|
|
def conv_cpp(decl_pair: FieldDecl) -> str:
|
2024-08-06 18:06:17 +08:00
|
|
|
if decl_pair.is_string():
|
2024-08-09 11:28:44 +08:00
|
|
|
return f'WRITER_BIND(sqlite3_bind_text(WRITER_STMT, WRITER_INDEX, REVEAL_U8STR(data.{decl_pair.m_DeclName})));'
|
2024-08-06 18:06:17 +08:00
|
|
|
elif decl_pair.is_int64():
|
|
|
|
|
return f'WRITER_BIND(sqlite3_bind_int64(WRITER_STMT, WRITER_INDEX, data.{decl_pair.m_DeclName}));'
|
2024-08-09 11:28:44 +08:00
|
|
|
elif decl_pair.is_blob():
|
|
|
|
|
return f'WRITER_BIND(sqlite3_bind_blob(WRITER_STMT, WRITER_INDEX, REVEAL_BLOB(data.{decl_pair.m_DeclName})));'
|
|
|
|
|
elif decl_pair.is_enum():
|
|
|
|
|
return f'WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, REVEAL_ENUM(data.{decl_pair.m_DeclName})));'
|
2024-08-06 18:06:17 +08:00
|
|
|
else:
|
|
|
|
|
return f'WRITER_BIND(sqlite3_bind_int(WRITER_STMT, WRITER_INDEX, data.{decl_pair.m_DeclName}));'
|
|
|
|
|
|
2024-08-09 11:28:44 +08:00
|
|
|
ret_sql_create_table: list[str] = []
|
|
|
|
|
ret_sql_insert: list[str] = []
|
|
|
|
|
ret_cpp_bind: list[tuple[str, str]] = []
|
|
|
|
|
for struct_decl in decls:
|
|
|
|
|
# generate sql create table statement
|
|
|
|
|
table_string: str = ', '.join(map(conv_sql_create_table, struct_decl.m_StructFields))
|
|
|
|
|
gen_statement: str = f'CREATE TABLE [{struct_decl.m_StructName}] ({table_string});'
|
|
|
|
|
ret_sql_create_table.append(gen_statement)
|
|
|
|
|
|
|
|
|
|
# generate sql insert statement
|
|
|
|
|
table_string = ', '.join(map(conv_sql_insert, struct_decl.m_StructFields))
|
|
|
|
|
gen_statement = f'INSERT INTO [{struct_decl.m_StructName}] VALUES ({table_string});'
|
|
|
|
|
ret_sql_insert.append(gen_statement)
|
|
|
|
|
|
|
|
|
|
# generate c++ bind statement
|
|
|
|
|
bind_string: str = '\n'.join(map(conv_cpp, struct_decl.m_StructFields))
|
|
|
|
|
ret_cpp_bind.append((struct_decl.m_StructName, bind_string))
|
|
|
|
|
|
|
|
|
|
print('========== SQL Create Table ==========')
|
|
|
|
|
for item in ret_sql_create_table:
|
|
|
|
|
print(item)
|
|
|
|
|
print('========== SQL Insert ==========')
|
|
|
|
|
for item in ret_sql_insert:
|
|
|
|
|
print(item)
|
|
|
|
|
print('========== C++ Bind ==========')
|
|
|
|
|
for name, item in ret_cpp_bind:
|
|
|
|
|
print(f'===== {name} =====')
|
|
|
|
|
print(item)
|
2024-08-06 18:06:17 +08:00
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
2024-08-09 11:28:44 +08:00
|
|
|
input_str: str = accept_input()
|
|
|
|
|
decls: tuple[StructDecl, ...] = analyse_input(input_str)
|
|
|
|
|
output_result(decls)
|