Example #1
0
 def __str__(self):
     self.parse()
     contents = StringIO()
     for (line_type, components) in self._contents:
         if line_type == 'blank':
             contents.write("%s\n" % (components[0]))
         elif line_type == 'all_comment':
             contents.write("%s\n" % (components[0]))
         elif line_type == 'hostname':
             (hostname, tail) = components
             contents.write("%s%s\n" % (hostname, tail))
     # Ensure trailing newline
     contents = contents.getvalue()
     if not contents.endswith("\n"):
         contents += "\n"
     return contents
Example #2
0
def generate_jai_bindings():
    header_filename = "raylib/include/raylib.h"
    header = open(header_filename).read()
    native_lib_name = "raylib_native"
    path_to_native_lib = "raylib/lib/raylib"
    output_filename = "raylib.jai"

    ctx["output_file"] = open(output_filename, "w")
    with ctx["output_file"]:

        p("//\n// AUTOGENERATED\n//\n")

        #
        # colors
        #
        for match in re.finditer(r"#define (\w+)\s+CLITERAL\(Color\){([^}]+)}",
                                 header):
            color_name = match.group(1)
            values = match.group(2)
            p(f"{color_name} :: Color.{{ {values} }};")

        #
        #  function pointers aren't parsed by regexes yet, so this is the only thing "by hand"
        #
        p("\nTraceLogCallback :: #type (logType: s32, text: *u8, args: ..*u8);\n"
          )

        #
        # enums
        #
        for match in re.finditer(r"typedef enum {([^}]*)} (\w+);", header):
            enum_id = match.group(2).strip()
            if enum_id == "bool":
                continue  # skip the C compat bool definition

            enum_contents = match.group(1).strip()\
                .replace("=", "::")\
                .replace(",", ";")

            enum_contents = re.sub(r"//.*$", "", enum_contents)
            # TODO: the above removes the last comment in an enum body...we could probably retain them

            if not enum_contents.endswith(";"):
                enum_contents = enum_contents.rstrip() + ";"

            enum_type = "enum_flags" if enum_id in enum_flags else "enum"

            p(f"{enum_id} :: {enum_type} {{\n    {enum_contents}\n}}\n")

        #
        # aliases
        #
        for match in re.finditer(r"typedef struct (\w+) (\w+);", header):
            struct_id = match.group(2)
            p(f"{struct_id} :: struct {{ /* only used as a pointer in this header */ }}\n"
              )

        for match in re.finditer(r"typedef (\w+) (\w+);", header):
            if match.group(1) == "struct":
                continue  # handled by loop above

            aliased_struct = match.group(1)
            struct_id = match.group(2)

            p(f"{struct_id} :: {aliased_struct};\n")

        #
        # structs
        #
        for match in re.finditer(r"typedef struct (\w+) {([^}]*)}", header):
            identifier = match.group(1)

            struct_contents = StringIO()
            for line in replace_types(match.group(2).strip()).split("\n"):
                field_m = re.search(r"(.*?)((\w+|, )+)(\[\d+\])?;", line)
                if field_m is None: continue

                field_type = replace_types(field_m.group(1).strip())
                pointer_count = 0
                if field_type.endswith(" **"):
                    pointer_count = 2
                    field_type = field_type[:-3]
                if field_type.endswith(" *"):
                    pointer_count = 1
                    field_type = field_type[:-2]
                field_id = field_m.group(2).strip()

                pointer_char = "*" * pointer_count

                field_type = struct_field_replacements.get(identifier, {}).get(
                    field_id, field_type)

                p(f"    {field_id}: {pointer_char}{field_type};",
                  file=struct_contents)

            extra = extra_type_code.get(identifier, None)
            if extra is not None:
                p(extra, file=struct_contents)

            p(f"{identifier} :: struct {{\n{struct_contents.getvalue()}}}\n")

        #
        # functions
        #
        for match in re.finditer(r"RLAPI (.*?)(\w+)\(([^\)]*)\);", header):
            return_type = match.group(1).strip()
            func_name = match.group(2)
            args = match.group(3)

            arg_contents = StringIO()
            if args != "void":
                for arg in args.split(","):
                    tokens = arg.strip().split(" ")
                    arg_name = tokens[-1]
                    arg_type = replace_types(" ".join(tokens[:-1]))
                    pointer_count = 0
                    if arg_name.startswith("**"):
                        pointer_count = 2
                        arg_name = arg_name[2:]
                    if arg_name.startswith("*"):
                        pointer_count = 1
                        arg_name = arg_name[1:]
                    pointer_char = "*" * pointer_count

                    if arg_name == "...":
                        p(f"args: ..*u8", file=arg_contents, end="")
                    else:
                        p(f"{arg_name}: {pointer_char}{arg_type}, ",
                          file=arg_contents,
                          end="")

            arg_contents = arg_contents.getvalue()
            if arg_contents.endswith(", "):
                arg_contents = arg_contents[:-2]

            replacement_string = function_replacements.get(func_name, None)
            if replacement_string != None:
                func_decl = replacement_string
            else:
                if return_type == "void":
                    return_type_string = ""
                else:
                    return_type = replace_types(return_type)
                    if return_type.endswith(" **"):
                        return_type = "**" + return_type[:-3]
                    elif return_type.endswith(" *"):
                        return_type = "*" + return_type[:-2]

                    return_type_string = "-> " + return_type
                func_decl = f"({arg_contents}) {return_type_string}"

            p(f"{func_name} :: {func_decl} #foreign {native_lib_name};")

        p(extra_code)

        #
        # native library
        #
        p("\n#scope_file // ---------------\n")
        p("#if OS == .WINDOWS {")
        p("""    #foreign_system_library "user32";""")
        p("""    #foreign_system_library "gdi32";""")
        p("""    #foreign_system_library "shell32";""")
        p("""    #foreign_system_library "winmm";""")
        p(f"    {native_lib_name} :: #foreign_library,no_dll \"{path_to_native_lib}\";"
          )
        p("}")

    print(
        f"Wrote Jai bindings file '{output_filename}' from C header '{header_filename}'."
    )