raiguard/odin-wayland

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

Caleb HeuerGenerate interface descriptions27d1580

trunk
4.7 KiB181 linesraw
1package codegen
2
3import "core:fmt"
4import "core:os"
5import "core:strings"
6import "core:unicode/utf8"
7
8string_iterate_words :: proc(content: ^string) -> (word: string, new_paragraph: bool, cond: bool) {
9	num_newlines := 0
10	word_start := -1
11	word_end := len(content)
12	for r, i in content {
13		if strings.is_space(r) {
14			if word_start >= 0 {
15				word_end = i
16				break
17			}
18			if r == '\n' {
19				num_newlines += 1
20			}
21			continue
22		}
23		if word_start < 0 {
24			word_start = i
25		}
26	}
27
28	if word_start == -1 {
29		return "", false, false
30	}
31
32	word = content[word_start:word_end]
33	content^ = content[word_end:]
34	return word, num_newlines > 1, true
35}
36
37gen_normalized_text :: proc(file: ^os.File, content: string, prefix := "") {
38	content := content
39	width := WIDTH - utf8.rune_count(prefix)
40
41	column_rune_i := 0
42	for word, new_paragraph in string_iterate_words(&content) {
43		word_rune_width := utf8.rune_count(word)
44		if new_paragraph {
45			fmt.fprint(file, "\n\n")
46			column_rune_i = 0
47		} else if column_rune_i > 0 && column_rune_i + word_rune_width > width {
48			fmt.fprint(file, "\n")
49			column_rune_i = 0
50		}
51		if column_rune_i == 0 && prefix != "" {
52			fmt.fprint(file, prefix)
53		}
54		fmt.fprintf(file, "{} ", word)
55		column_rune_i += word_rune_width + 1
56	}
57	fmt.fprint(file, "\n")
58}
59
60gen_description :: proc(file: ^os.File, description: Description) {
61	if description.summary == "" && description.body == "" {
62		return
63	}
64
65	fmt.fprintln(file, BLOCK_COMMENT_BEGIN)
66	if description.summary != "" {
67		gen_normalized_text(file, description.summary)
68		fmt.fprintln(file)
69	}
70	if description.body != "" {
71		gen_normalized_text(file, description.body)
72	}
73	fmt.fprintln(file, BLOCK_COMMENT_END)
74}
75
76gen_header :: proc(file: ^os.File, protocol: Protocol) {
77    fmt.fprintln(
78	    file,
79	    BLOCK_COMMENT_BEGIN,
80	    BIG_BLOCK_SEPARATOR,
81	    CODEGEN_HEADER,
82	    BIG_BLOCK_SEPARATOR,
83	    "",
84		protocol.file_name,
85		"",
86		sep="\n"
87	)
88	gen_normalized_text(file, protocol.copyright)
89	fmt.fprintln(file, "", BIG_BLOCK_SEPARATOR, sep="\n")
90
91    if protocol.description.summary != "" || protocol.description.body != "" {
92	    fmt.fprint(file, "\n")
93	    if protocol.description.summary != "" {
94		    gen_normalized_text(file, protocol.description.body)
95	    }
96	    if protocol.description.body != "" {
97		    gen_normalized_text(file, protocol.description.body)
98	    }
99	    fmt.fprint(file, "\n")
100	    fmt.fprintln(file, BIG_BLOCK_SEPARATOR)
101    }
102    fmt.fprintln(file, BLOCK_COMMENT_END, "\n")
103}
104
105gen_imports :: proc(file: ^os.File, protocol: Protocol) {
106	fmt.fprintln(
107		file,
108		"""
109		#+build linux
110		package wayland
111
112		import "base:intrinsics"
113		import "core:fmt"
114		import "core:log"
115		import "core:io"
116
117		""",
118	)
119}
120
121gen_interface :: proc(file: ^os.File, protocol: Protocol, interface: Interface) {
122	fmt.fprintln(file, BIG_SEPARATOR)
123	fmt.fprintln(file, "// ", strings.to_upper_snake_case(interface.name), "\n", sep="")
124
125	gen_description(file, interface.description)
126
127	interface_name := strings.to_ada_case(interface.name)
128	fmt.fprintln(file, interface_name, "_ID :: distinct Object_ID", sep="")
129	screaming_interface_name := strings.to_upper_snake_case(interface.name)
130	fmt.fprintln(file, screaming_interface_name, "_INTERFACE_NAME :: \"", interface.name, "\"", sep="")
131	fmt.fprintln(file, screaming_interface_name, "_INTERFACE_VERSION :: ", interface.version, sep="")
132	fmt.fprintln(file)
133
134	if len(interface.requests) > 0 {
135		fmt.fprintln(file, SMALL_SEPARATOR, "// REQUESTS", "", sep="\n")
136		fmt.fprintln(file, interface_name, "_Request :: enum Opcode {", sep="")
137		for request, i in interface.requests {
138			fmt.fprint(file, "\t", strings.to_ada_case(request.name), " = ", i, ",", sep="")
139			if request.description.summary != "" {
140				 fmt.fprint(file, " //", request.description.summary)
141			}
142			fmt.fprintln(file)
143		}
144		fmt.fprintln(file, "}", "", sep="\n")
145		for request in interface.requests {
146			gen_request(file, protocol, interface, request)
147		}
148	}
149
150	if len(interface.events) > 0 {
151		fmt.fprintln(file, SMALL_SEPARATOR, "// EVENTS", "", sep="\n")
152	}
153
154	fmt.fprintln(file)
155}
156
157gen_request :: proc(file: ^os.File, protocol: Protocol, interface: Interface, request: Message) {
158	if request.description.summary != "" || request.description.body != "" {
159		fmt.fprintln(file, BLOCK_COMMENT_BEGIN)
160		if request.description.summary != "" {
161			gen_normalized_text(file, request.description.summary)
162			fmt.fprint(file, "\n")
163		}
164		if request.description.body != "" {
165			gen_normalized_text(file, request.description.body)
166		}
167		fmt.fprintln(file, BLOCK_COMMENT_END)
168	}
169
170	fmt.fprintln(file, REQUIRE_RESULTS_ATTRIBUTE)
171	fmt.fprintln(
172		file,
173		strings.to_snake_case(interface.name),
174		"_",
175		strings.to_snake_case(request.name),
176		" :: proc(session: ^Session) {}",
177		sep=""
178	)
179
180	fmt.fprintln(file)
181}