summaryrefslogtreecommitdiffstats
path: root/src/tools/vppapigen/vppapigen_json.py
blob: 7239d1ea732ad1ca204bbd7a2b94d89b03c1a7f4 (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
128
129
130
131
132
133
134
135
# JSON generation
import json
import sys
import os

process_imports = True


def walk_imports(s):
    r = []
    for e in s:
        r.append(str(e))
    return r


def walk_counters(s, pathset):
    r = []
    for e in s:
        r2 = {"name": e.name, "elements": e.block}
        r.append(r2)

    r3 = []
    for p in pathset:
        r3.append(p.paths)

    return r, r3


def walk_enums(s):
    r = []
    for e in s:
        d = []
        d.append(e.name)
        for b in e.block:
            d.append(b)
        d.append({"enumtype": e.enumtype})
        r.append(d)
    return r


def walk_services(s):
    r = {}
    for e in s:
        d = {"reply": e.reply}
        if e.stream:
            d["stream"] = True
        if e.stream_message:
            d["stream_msg"] = e.stream_message
        if e.events:
            d["events"] = e.events
        r[e.caller] = d
    return r


def walk_defs(s, is_message=False):
    r = []
    for t in s:
        d = []
        d.append(t.name)
        for b in t.block:
            if b.type == "Option":
                continue
            if b.type == "Field":
                if b.limit:
                    d.append([b.fieldtype, b.fieldname, b.limit])
                else:
                    d.append([b.fieldtype, b.fieldname])
            elif b.type == "Array":
                if b.lengthfield:
                    d.append([b.fieldtype, b.fieldname, b.length, b.lengthfield])
                else:
                    d.append([b.fieldtype, b.fieldname, b.length])
            elif b.type == "Union":
                pass
            else:
                raise ValueError("Error in processing array type %s" % b)

        if is_message and t.crc:
            c = {}
            c["crc"] = "{0:#0{1}x}".format(t.crc, 10)
            c["options"] = t.options
            if t.comment:
                c["comment"] = t.comment
            d.append(c)

        r.append(d)
    return r


#
# Plugin entry point
#


def contents_to_c_string(contents):
    # Escape backslashes and double quotes
    contents = contents.replace("\\", "\\\\").replace('"', '\\"')
    # Replace newlines with \n
    contents = contents.replace("\n", "\\n")
    return '"' + contents + '"'


def run(output_dir, apifilename, s):
    if not output_dir:
        sys.stderr.write("Missing --outputdir argument")
        return None

    basename = os.path.basename(apifilename)
    filename_json_repr = os.path.join(output_dir + "/" + basename + "_json.h")
    filename, _ = os.path.splitext(basename)
    modulename = filename.replace(".", "_")

    j = {}

    j["types"] = walk_defs([o for o in s["types"] if o.__class__.__name__ == "Typedef"])
    j["messages"] = walk_defs(s["Define"], True)
    j["unions"] = walk_defs([o for o in s["types"] if o.__class__.__name__ == "Union"])
    j["enums"] = walk_enums([o for o in s["types"] if o.__class__.__name__ == "Enum"])
    j["enumflags"] = walk_enums(
        [o for o in s["types"] if o.__class__.__name__ == "EnumFlag"]
    )
    j["services"] = walk_services(s["Service"])
    j["options"] = s["Option"]
    j["aliases"] = {
        o.name: o.alias for o in s["types"] if o.__class__.__name__ == "Using"
    }
    j["vl_api_version"] = hex(s["file_crc"])
    j["imports"] = walk_imports(i for i in s["Import"])
    j["counters"], j["paths"] = walk_counters(s["Counters"], s["Paths"])
    r = json.dumps(j, indent=4, separators=(",", ": "))
    c_string = contents_to_c_string(r)
    with open(filename_json_repr, "w", encoding="UTF-8") as f:
        print(f"const char *json_api_repr_{modulename} = {c_string};", file=f)
    # return json.dumps(j, indent=4, separators=(",", ": "))
    return r