raiguard/odin-wayland

git clone https://git.raiguard.me/raiguard/odin-wayland

Caleb HeuerCodegen ID types and interface literalsf425641

trunk
2.6 KiB87 linesraw
1package codegen
2
3import "core:encoding/xml"
4import "core:flags"
5import "core:fmt"
6import "core:io"
7import "core:os"
8import "core:strings"
9
10// This program functions as a "script" and does not run for very long. Therefore we do not free any memory, ever!
11// Don't run ASAN on this program! :)
12// TODO: We really ought to manage our memory a bit.
13
14main :: proc() {
15    f: struct {
16        source: string `args:"pos=0,required" usage:"Path to directory containing wayland XML specifications."`,
17        dest: string `args:"pos=1,required" usage:"Path to directory in which to place generated code."`,
18    }
19    flags.parse_or_exit(&f, os.args)
20
21    if !os.exists(f.source) {
22        fmt.eprintfln("Source directory '{}' does not exist.", f.source)
23        os.exit(1)
24    }
25
26    source_walker := os.walker_create(f.source)
27    defer os.walker_destroy(&source_walker)
28
29	protocols: map[string]Protocol // Keyed by Protocol.name
30	num_interfaces: int
31	max_num_events: int
32
33    for info in os.walker_walk(&source_walker) {
34        if info.type == .Directory || os.ext(info.fullpath) != ".xml" {
35            continue
36        }
37
38        fmt.println(info.fullpath)
39
40        doc, doc_err := xml.load_from_file(info.fullpath)
41        if doc_err != nil {
42            // No need to print because the XML library does that for us.
43            continue
44        }
45
46        p := parser_make(doc)
47        protocol, parse_err := parse_protocol(&p)
48        if parse_err != nil {
49            fmt.eprintfln("Error parsing '{}': {}", info.name, parse_err)
50            continue
51        }
52        protocol.file_name = strings.clone(info.name)
53        protocols[protocol.name] = protocol
54
55        num_interfaces += len(protocol.interfaces)
56        for interface in protocol.interfaces {
57	        max_num_events = max(max_num_events, len(interface.events))
58        }
59        // fmt.printfln("%#v", protocol)
60    }
61    fmt.println(num_interfaces, "interfaces")
62    fmt.println(max_num_events, "max events")
63
64    if !os.exists(f.dest) {
65	    os.make_directory(f.dest)
66    }
67
68    // Iterate over each protocol again and generate a file from it.
69    for protocol_name, protocol in protocols {
70	    // Don't care about allocator errors.
71	    file_path, _ := os.join_path({f.dest, fmt.tprint("protocol_", protocol_name, ".gen.odin", sep="")}, context.allocator)
72	    file, file_err := os.create(file_path)
73	    if file_err != nil {
74		    fmt.eprintfln("Error creating '{}': {}", file_path, file_err)
75		    continue
76	    }
77
78		gen_header(file, protocol)
79		gen_imports(file, protocol)
80
81		for interface in protocol.interfaces {
82			gen_interface(file, protocol, interface)
83		}
84
85	    os.close(file)
86    }
87}