Skip to content

Instantly share code, notes, and snippets.

@KokoseiJ
Last active July 8, 2022 02:08
Show Gist options
  • Save KokoseiJ/23e2b8c4145757bf840613f925f61ca4 to your computer and use it in GitHub Desktop.
Save KokoseiJ/23e2b8c4145757bf840613f925f61ca4 to your computer and use it in GitHub Desktop.
Automatically generate discord object parse code from their docs
import re
import requests
# Do check for: ex) "integer or string"
files = ["Application.md", "Audit_Log.md", "Channel.md", "Emoji.md", "Guild.md", "Guild_Scheduled_Event.md", "Guild_Template.md", "Invite.md", "Stage_Instance.md", "Sticker.md", "User.md", "Voice.md", "Webhook.md"]
known_types = {
# Type: [funcname, casting]
"boolean": ["boolean", None],
"integer": ["number", "int"],
"string": ["string", "char *"],
"array": ["!array", "char *"],
"default": ["!object", "char *"]
}
aliases = {
"snowflake": "string",
"iso8601 timestamp": "string",
"integer or string": "string",
"int": "integer",
"string (can be null only in reaction emoji objects)": "string"
}
unregistered_type = []
def get_func(funcname, casting):
if funcname.startswith("!"):
funcstr = f"json_serialize_to_string(json_{funcname[1:]}_get_wrapping_value(json_object_get_{funcname[1:]}({{}}, {{}})))"
else:
funcstr = f"json_object_get_{funcname}({{}}, {{}})"
if casting is not None:
funcstr = f"({casting}) {funcstr}"
return funcstr
def get_typedata(typename):
typename = typename.lower().strip().rstrip()
if typename in aliases:
typename = aliases.get(typename)
type_ = known_types.get(typename, None)
if type_ is None:
unregistered_type.append(typename)
if typename.startswith("array") or typename.startswith("list"):
type_ = known_types.get("array")
else:
type_ = known_types.get("default")
return type_
def format_full(s_name, s_data, baseindent=4):
indent = baseindent + 16 + len(s_name)
structstr = f"""\
{s_name}_t *parse_{s_name}(JSON_Value *{s_name}_value) {{
JSON_Object *{s_name} = json_object({s_name}_value);
*result = ({s_name}_t) @;
return result;
}}
"""
substr = f",\n{' '*indent}".join([get_func(*get_typedata(t_type)).format(s_name, f"\"{t_name}\"") for t_name, t_type in s_data.items()])
print(structstr.replace("@", f"{{{substr}\n{' '*baseindent}}}"))
print("\n")
def purify_item(text):
rep_txt = text.replace("?", "").replace("| ", "|").replace(" |", "|")
pure_txt = re.sub("[\\\\]+\\*", "", rep_txt)
return re.sub("\\s{2,}", "", pure_txt).split("|", 3)[1:3]
def get_structures(text):
i = 0
check = re.compile("#+ (.+?) Structure")
structures = {}
lines = text.split("\n")
while i < len(lines):
line = lines[i]
struct_match = check.match(line)
if struct_match:
struct_name = re.sub("\\s+", "_", struct_match.groups()[0].lower())
#print("###", struct_name, "###")
struct_dict = {}
if ">" in lines[i+2]:
i += 4
i += 4
while True:
line = lines[i]
if not line:
break
items = purify_item(line)
#print(items)
key, val = items
struct_dict[key] = val
i += 1
structures[struct_name] = struct_dict
i += 1
return structures
check = []
for file in files:
structures = get_structures(requests.get(f"https://raw.githubusercontent.com/discord/discord-api-docs/master/docs/resources/{file}").text)
for s_name, s_data in structures.items():
if s_name in check:
print(f"### WARNING: {s_name} already exists")
check.append(s_name)
format_full(s_name, s_data)
# print("|\n".join(check))
# print("#####")
# print("\n".join(unregistered_type))
import re
import requests
# Do check for: ex) "integer or string"
files = ["Application.md", "Audit_Log.md", "Channel.md", "Emoji.md", "Guild.md", "Guild_Scheduled_Event.md", "Guild_Template.md", "Invite.md", "Stage_Instance.md", "Sticker.md", "User.md", "Voice.md", "Webhook.md"]
known_types = {
# Type: [funcname, casting]
"boolean": ["boolean", None],
"integer": ["number", "int"],
"string": ["string", "char *"],
"array": ["!array", "char *"],
"default": ["!object", "char *"]
}
aliases = {
"snowflake": "string",
"iso8601 timestamp": "string",
"integer or string": "string",
"int": "integer",
"string (can be null only in reaction emoji objects)": "string"
}
unregistered_type = []
def get_func(funcname, casting):
if funcname.startswith("!"):
funcstr = f"json_serialize_to_string(json_{funcname[1:]}_get_wrapping_value(json_object_get_{funcname[1:]}({{}}, {{}})))"
else:
funcstr = f"json_object_get_{funcname}({{}}, {{}})"
if casting is not None:
funcstr = f"({casting}) {funcstr}"
return funcstr
def get_typedata(typename):
typename = typename.lower().strip().rstrip()
if typename in aliases:
typename = aliases.get(typename)
type_ = known_types.get(typename, None)
if type_ is None:
unregistered_type.append(typename)
if typename.startswith("array") or typename.startswith("list"):
type_ = known_types.get("array")
else:
type_ = known_types.get("default")
return type_
def format_full(s_name, s_data, baseindent=4):
indent = baseindent + 16 + len(s_name)
structstr = f"""\
{s_name}_t *parse_{s_name}(JSON_Value *{s_name}_value) {{
JSON_Object *{s_name} = json_object({s_name}_value);
*result = ({s_name}_t) @;
return result;
}}
"""
substr = f",\n{' '*indent}".join([get_func(*get_typedata(t_type)).format(s_name, f"\"{t_name}\"") for t_name, t_type in s_data.items()])
print(structstr.replace("@", f"{{{substr}\n{' '*baseindent}}}"))
print("\n")
def format_declare_full(s_name, s_data, baseindent=4):
structstr = f"""\
typedef struct yadl_{s_name} {{
@
}} {s_name}_t;
"""
substr_list = []
for t_name, t_type in s_data.items():
t_type = re.sub("\\[(.*?)\\]\\(.*?\\)", lambda x: x.groups()[0], t_type)
t_name = t_name.strip().rstrip()
funcname, casting = get_typedata(t_type)
if casting == None:
casting = "bool"
subsubstr = f"{casting}{' ' if casting[-1] != '*' else ''}{t_name};\n{' '*baseindent}"
substr_list.append(subsubstr)
if funcname.startswith("!"):
substr_list.append(f"/* {t_type} */\n{' '*baseindent}")
substr = "".join(substr_list)
print(structstr.replace("@", substr))
def purify_item(text):
rep_txt = text.replace("?", "").replace("| ", "|").replace(" |", "|")
pure_txt = re.sub("([\\\\]+)?\\*", "", rep_txt)
return re.sub("\\s{2,}", "", pure_txt).split("|", 3)[1:3]
def get_structures(text):
i = 0
check = re.compile("#+ (.+?) Structure")
structures = {}
lines = text.split("\n")
while i < len(lines):
line = lines[i]
struct_match = check.match(line)
if struct_match:
struct_name = re.sub("\\s+", "_", struct_match.groups()[0].lower())
#print("###", struct_name, "###")
struct_dict = {}
if ">" in lines[i+2]:
i += 4
i += 4
while True:
line = lines[i]
if not line:
break
items = purify_item(line)
#print(items)
key, val = items
struct_dict[key] = val
i += 1
structures[struct_name] = struct_dict
i += 1
return structures
check = []
for file in files:
structures = get_structures(requests.get(f"https://raw.githubusercontent.com/discord/discord-api-docs/master/docs/resources/{file}").text)
for s_name, s_data in structures.items():
if s_name in check:
print(f"### WARNING: {s_name} already exists")
check.append(s_name)
format_declare_full(s_name, s_data)
# print("|\n".join(check))
# print("#####")
# print("\n".join(unregistered_type))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment