summaryrefslogtreecommitdiff
path: root/src/script_to_header.py
blob: e62984ec8b781c7cc6a0f3b9e2b3a668d892fd79 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import sys
from os.path import exists

RPC_DICT = {"remote" : "GODOT_METHOD_RPC_MODE_REMOTE", "remotesync" : "GODOT_METHOD_RPC_MODE_REMOTESYNC", \
            "master" : "GODOT_METHOD_RPC_MODE_MASTER", "mastersync" : "GODOT_METHOD_RPC_MODE_MASTERSYNC", \
            "puppet" : "GODOT_METHOD_RPC_MODE_PUPPET", "puppetsync" : "GODOT_METHOD_RPC_MODE_PUPPETSYNC"}

def script_to_gdn(filename):
    if not exists(filename) or not filename.endswith(".gd"):
        return
    class_name = filename[:-3]
    new_file_base = class_name.lower()
    header_name = class_name.upper() + "_H"
    base_class_name = "Node"
    class_vars = [] # {export bool, onready bool, type str, varname str, initialvalue}
    funcs = [] # {net type, return type, name, [args], [content]} args = [name, type], content = func content lines list

    script = open(filename, "r")
    template_h = open("gdn_header_template", "r")
    template_c = open("gdn_src_template", "r")

    header_file_text = template_h.read(); template_h.close();
    src_file_text = template_c.read(); template_c.close();

    lines = script.readlines()
    for I in range(len(lines)):
        line = lines[I]
        if line.startswith("extends"):
             base_class_name = line.split(" ")[-1].strip();
        
        if line.startswith("var") or line.startswith("export var") or line.startswith("const") or line.startswith("onready var"):
            class_vars.append( [ line.startswith("export"), line.startswith("onready"), line.split(":")[1].split('=')[0].strip(), line.split(":")[0].split(" ")[-1], "" if "=" not in line else line.split("=")[-1].strip() ])
        
        if line.startswith("func") or line.startswith("remote") or line.startswith("master") or line.startswith("puppet"):
            functype = line[0:line.index(" ")]
            
            args = line[line.index("(")+1 : line.index(")")].split(",")
            for i, arg in enumerate(args):
                if arg == "":
                    args = []
                    break
                args[i] = [arg.split(":")[0].strip(), arg.split(":")[1].strip()]
            
            returntype = "void"
            if "->" in line:
                returntype = line[line.index("->")+1:line.index(":")].strip()
            
            funcname = line[ line[0:line.index("(")].rindex(" ") : int(line.index("(")) ].strip()
            
            content = []
            I+=1
            line = lines[I]
            while line.startswith('\t'):
                content.append(line)
                I+=1
                if I != len(lines):
                    line = lines[I]
                else:
                    line = "EOF"
            I-=1

            funcs.append( [functype, returntype, funcname, args, content] )
    script.close()

    header_file_text = header_file_text.replace("{HEADER_NAME}", header_name).replace("{BASE_CLASS_NAME}", base_class_name).replace("{CLASS_NAME}", class_name)
    
    var_text = ""
    for var in class_vars:
        var_text += '\t' + var[2] + " " + var[3] + ";\n" #    type varname;
    header_file_text = header_file_text.replace("{VARS}", var_text)
    
    func_text = ""
    for func in funcs:
        func_text += '\t' + func[1] + " " + func[2] + "(" #    type functionname(
        for i,arg in enumerate(func[3]):
            func_text += arg[1] + " " + arg[0]
            if i != len(func[3])-1:
                func_text += ", "
        func_text += ");\n"
    header_file_text = header_file_text.replace("{FUNCS}", func_text)
    #print(header_file_text)
    with open(new_file_base+".h", "w") as f:
        f.write(header_file_text)

    #SOURCE CODE:
    src_file_text = src_file_text.replace("{CLASS_NAME}", class_name).replace("{NEW_FILE_BASE}",new_file_base)
    
    reg_vars = ""
    vars_init = ""
    vars_ready = ""
    for var in class_vars:
        if var[0]: #export
            reg_vars += "\tregister_property<"+class_name+", "+var[2]+">(\""+var[3]+"\", &"+class_name+"::"+var[3]+", "+var[2]+"("+var[4]+"));\n"
        elif var[1]: #onready
            vars_ready += "\t"+var[3]+" = "+var[4]+";\n"
        else:
            vars_init += "\t"+var[3]+" = "+var[4]+";\n"
    reg_vars = reg_vars[:-1]
    reg_methods = ""
    src_func_text = ""
    for func in funcs:
        reg_methods += "\tregister_method(\"" + func[2]+"\", &"+class_name+"::"+func[2]
        if func[0] != "func":
            reg_methods += ", " + RPC_DICT[func[0]]
        reg_methods += ");\n"
        
        src_func_text += func[1] + " " + class_name + "::" + func[2] + "(" #returntype ClassName::functionname(
        for i,arg in enumerate(func[3]):
            src_func_text += arg[1] + " " + arg[0]
            if i != len(func[3])-1:
                src_func_text += ", "
        src_func_text += ") {\n"
        if func[2] == "_ready":
            src_func_text += vars_ready
        src_func_text += "//" + "//".join(func[4]) #join content (commented out)
        src_func_text += "}\n\n"

    src_file_text = src_file_text.replace("{INIT_VARS}", vars_init).replace("{REGISTER_METHODS}",reg_methods).replace("{REGISTER_VARS}", reg_vars).replace("{FULL_FUNCS}", src_func_text)

    with open(new_file_base+".cpp", "w") as f:
        f.write(src_file_text)

if __name__ == "__main__":
    n = len(sys.argv)
    if n != 2:
        quit()
    script_to_gdn(sys.argv[1])