Init new repository

This commit is contained in:
Krzosa Karol
2024-04-13 15:29:53 +02:00
commit 5a2e3dcec4
335 changed files with 61571 additions and 0 deletions

285
tools/bindgen.py Normal file
View File

@@ -0,0 +1,285 @@
import subprocess
import json
import code
def filter_types(str):
return str.replace('_Bool', 'bool')
def parse_struct(decl):
if decl.get("inner") == None:
return None
outp = {}
outp['kind'] = 'struct'
outp['struct_kind'] = decl["tagUsed"]
outp['name'] = decl['name']
outp['fields'] = []
for item_decl in decl['inner']:
if item_decl['kind'] == 'FullComment': continue
if item_decl['kind'] != 'FieldDecl':
print(f"// ERROR: Structs must only contain simple fields ({decl['name']})")
print("/*", item_decl, "*/")
return None
item = {}
if 'name' in item_decl:
item['name'] = item_decl['name']
item['type'] = filter_types(item_decl['type']['qualType'])
outp['fields'].append(item)
return outp
def parse_enum(decl):
if decl.get("inner") == None:
return None
outp = {}
if 'name' in decl:
outp['kind'] = 'enum'
outp['name'] = decl['name']
needs_value = False
else:
outp['kind'] = 'consts'
needs_value = True
outp['items'] = []
for item_decl in decl['inner']:
if item_decl['kind'] == 'EnumConstantDecl':
item = {}
item['name'] = item_decl['name']
if 'inner' in item_decl:
const_expr = item_decl['inner'][0]
if const_expr['kind'] != 'ConstantExpr':
print(f"// ERROR: Enum values must be a ConstantExpr ({item_decl['name']}), is '{const_expr['kind']}'")
return None
if const_expr['valueCategory'] != 'rvalue' and const_expr['valueCategory'] != 'prvalue':
print(f"// ERROR: Enum value ConstantExpr must be 'rvalue' or 'prvalue' ({item_decl['name']}), is '{const_expr['valueCategory']}'")
return None
if not ((len(const_expr['inner']) == 1) and (const_expr['inner'][0]['kind'] == 'IntegerLiteral')):
print(f"// ERROR: Enum value ConstantExpr must have exactly one IntegerLiteral ({item_decl['name']})")
return None
item['value'] = const_expr['inner'][0]['value']
if needs_value and 'value' not in item:
print(f"// ERROR: anonymous enum items require an explicit value")
return None
outp['items'].append(item)
return outp
def parse_func(decl):
outp = {}
outp['kind'] = 'func'
outp['name'] = decl['name']
outp['type'] = filter_types(decl['type']['qualType'])
outp['variadic'] = False
if decl.get("variadic"):
outp['variadic'] = True
outp['params'] = []
if 'inner' in decl:
for param in decl['inner']:
if param['kind'] != 'ParmVarDecl':
if param['kind'] == 'BuiltinAttr': continue
if param['kind'] == 'NoThrowAttr': continue
if param['kind'] == 'FullComment': continue
if param['kind'] == 'PureAttr': continue
if param['kind'] == 'DLLImportAttr': continue
if param['kind'] == 'CompoundStmt': continue # function with body
if param['kind'] == 'AlwaysInlineAttr': continue
if param['kind'] == 'FormatAttr':
outp['variadic'] = True
continue
print(f"// warning: ignoring func {decl['name']} (unsupported parameter type) {param['kind']}")
return None
if param.get('name') == None: return None
outp_param = {}
outp_param['name'] = param['name']
outp_param['type'] = filter_types(param['type']['qualType'])
outp['params'].append(outp_param)
return outp
def parse_typedef(decl):
if decl['type']['qualType'].startswith("struct") or\
decl['type']['qualType'].startswith("union") or\
decl['type']['qualType'].startswith("enum"):
return None
outp = {};
outp['kind'] = 'typedef'
outp['name'] = decl['name']
outp['type'] = filter_types(decl['type']['qualType'])
return outp
def parse_decl(decl):
kind = decl['kind']
if kind == 'RecordDecl':
return parse_struct(decl)
elif kind == 'EnumDecl':
return parse_enum(decl)
elif kind == 'FunctionDecl':
return parse_func(decl)
elif kind == "TypedefDecl":
return parse_typedef(decl)
else:
return None
def bindgen_enum(decl):
r += decl["name"] + " :: typedef int;\n"
for item in decl["items"]:
r += item["name"]
if item.get("value"):
r += " :: " + item["value"]
r += ";\n"
return r
types = {
"unsigned int": "uint",
"unsigned long": "ulong",
"unsigned long long": "ullong",
"long long": "llong",
"unsigned int": "uint",
"unsigned": "uint",
"unsigned short": "ushort",
"unsigned char": "uchar",
"uint64_t": "u64",
"uint32_t": "u32",
"uint16_t": "u16",
"uint8_t": "u8",
"int64_t": "i64",
"int32_t": "i32",
"int16_t": "i16",
"int8_t": "i8",
"size_t": "usize",
}
def bindgen_type(type):
type = type.replace("const ", "")
type = type.strip()
if types.get(type): return types[type]
if type[-1] == '*': return "*" + bindgen_type(type[:-1])
if type[-1] == ' ': return bindgen_type(type[:-1])
if type[-1] == ']':
i = -1
while type[i] != '[': i += 1
array = type[i:]
return array + bindgen_type(type[:i])
func_ptr_idx = type.find('(*)')
if func_ptr_idx != -1:
args = type[func_ptr_idx+4:-1]
args = args.split(",")
new_args = []
name = 'a'
for it in args:
new_args.append(name + ": " + bindgen_type(it))
name = chr(ord(name[0]) + 1)
new_args = ', '.join(new_args)
ret = type[:func_ptr_idx]
return "proc(" + new_args + "): " + bindgen_type(ret)
func_idx = type.find('(')
if func_idx != -1:
args = type[func_idx+1:-1]
args = args.split(",")
new_args = []
name = 'a'
for it in args:
new_args.append(name + ": " + bindgen_type(it))
name = chr(ord(name[0]) + 1)
new_args = ', '.join(new_args)
ret = type[:func_idx]
return "proc(" + new_args + "): " + bindgen_type(ret)
return type
def bindgen_struct(decl):
r = ""
r += decl["name"] + " :: " + decl["struct_kind"] + " {\n"
for field in decl["fields"]:
r += " " + field["name"] + ": " + bindgen_type(field["type"]) + ";\n"
r += "}\n"
return r
def bindgen_func(decl):
r = ""
vargs = decl['variadic']
r += decl["name"] + " :: proc("
i = 0
for param in decl["params"]:
r += param["name"] + ": " + bindgen_type(param["type"])
if i != len(decl["params"]) - 1 or vargs:
r += ", "
i += 1
if vargs: r += ".."
r += ")"
decl_type = decl["type"]
return_type = decl_type[:decl_type.index('(')].strip()
return_type = bindgen_type(return_type)
if return_type != "void":
r += ": " + return_type
r += ";"
return r
def bindgen_typedef(decl):
return decl["name"] + " :: typedef " + bindgen_type(decl["type"]) + ";"
def get_clang_ast(file):
cmd = ['clang', '-IC:/Work/', '-Xclang', '-ast-dump=json']
cmd.append(file)
out = subprocess.run(cmd, stdout=subprocess.PIPE)
if out.returncode == 0:
tu = json.loads(out.stdout)
return tu
return None
def has_prefix(decl, prefixes):
if prefixes == None or len(prefixes) == 0: return True
for it in prefixes:
if decl["name"].startswith(it):
return True
return False
def bindgen_to_stdout(file, prefixes):
tu = get_clang_ast(file)
if tu == None: return
decls = []
for decl in tu["inner"]:
has_name = decl.get("name")
if has_name == None: continue
hp = has_prefix(decl, prefixes)
if hp:
out_decl = parse_decl(decl)
if out_decl:
decls.append(out_decl)
for decl in decls:
try:
if decl["kind"] == "func": out = bindgen_func(decl)
elif decl["kind"] == "struct": out = bindgen_struct(decl)
elif decl["kind"] == "enum": out = bindgen_enum(decl)
elif decl["kind"] == "typedef": out = bindgen_typedef(decl)
else: sys.exit("invalid decl kind", decl)
except IndexError:
print(f"// ERROR: generating {decl['name']} {decl['type']}")
continue
print(out)
if __name__ == "__main__":
import argparse
import sys
parser = argparse.ArgumentParser(description='generate bindings for a c file using clang')
parser.add_argument('filename')
parser.add_argument('--prefixes', nargs='+', help = 'generate declarations with these prefixes')
args = parser.parse_args()
if args.filename.endswith(".c") or args.filename.endswith(".cpp"):
print("warning: for some reason clang doesn't like c and c++ files, the file to generate bindings for need to be a header")
bindgen_to_stdout(args.filename, args.prefixes)

50
tools/lcompile.c Normal file
View File

@@ -0,0 +1,50 @@
#include "../src/core/core.c"
#define LC_USE_CUSTOM_ARENA
#define LC_Arena MA_Arena
#define LC__PushSizeNonZeroed MA__PushSizeNonZeroed
#define LC__PushSize MA__PushSize
#define LC_InitArena MA_Init
#define LC_DeallocateArena MA_DeallocateArena
#define LC_BootstrapArena MA_Bootstrap
#define LC_TempArena MA_Temp
#define LC_BeginTemp MA_BeginTemp
#define LC_EndTemp MA_EndTemp
#define LC_String S8_String
#define LIB_COMPILER_IMPLEMENTATION
#include "../lib_compiler.h"
int main(int argc, char **argv) {
bool colored = LC_EnableTerminalColors();
MA_Arena arena = {0};
S8_List dirs = {0};
CmdParser p = MakeCmdParser(&arena, argc, argv, "I'm a tool that compiles lc packages - for example: ./lc.exe <package>");
p.require_one_standalone_arg = true;
AddList(&p, &dirs, "dirs", "additional directories where I can find packages!");
if (!ParseCmd(&arena, &p))
return 0;
IO_Assert(p.args.node_count == 1);
S8_String package = p.args.first->string;
S8_String path_to_package = S8_ChopLastSlash(package);
path_to_package = S8_Copy(&arena, path_to_package);
package = S8_SkipToLastSlash(package);
package = S8_Copy(&arena, package);
LC_Lang *lang = LC_LangAlloc();
lang->use_colored_terminal_output = colored;
LC_LangBegin(lang);
LC_RegisterPackageDir("pkgs");
LC_RegisterPackageDir(path_to_package.str);
S8_For(it, dirs) { LC_RegisterPackageDir(it->string.str); }
LC_Intern name = LC_InternStrLen(package.str, (int)package.len);
LC_ASTRefList packages = LC_ResolvePackageByName(name);
if (lang->errors) return 1;
S8_String code = LC_GenerateUnityBuild(packages);
OS_WriteFile(S8_Lit("output.c"), code);
}

BIN
tools/nasm.exe Normal file

Binary file not shown.

BIN
tools/ndisasm.exe Normal file

Binary file not shown.