vxx2 / vlib / v3 / gen / c / cleanc.v
7173 lines · 6919 sloc · 247.75 KB · 073a7c9674c038f990d84c2707a980d998445c5e
Raw
1module c
2
3import os
4import strings
5import v3.flat
6import v3.types
7
8// FlatGen emits flat gen output used by c.
9pub struct FlatGen {
10mut:
11 sb strings.Builder
12 indent int
13 a &flat.FlatAst = unsafe { nil }
14 used_fns map[string]bool
15 used_fn_names []string
16 test_files map[string]bool
17 str_lits []string
18 str_lit_ids map[string]int
19 global_types map[string]types.Type
20 enum_vals map[string]int
21 defers []flat.NodeId
22 fn_defers []flat.NodeId
23 fn_defer_counts map[int]string
24 defer_capture_names []string
25 defer_capture_types map[string]types.Type
26 interfaces map[string][]string
27 const_vals map[string]flat.NodeId
28 const_modules map[string]string
29 const_init_order []string
30 global_modules map[string]string
31 global_inits map[string]flat.NodeId // qualified global name -> initializer value node
32 global_init_order []string // qualified global names, in declaration order
33 iface_impls map[string][]string // interface name -> implementing concrete type names
34 iface_type_ids map[string]int // "${iface}::${concrete}" -> 1-based type id
35 module_init_fns []string // C names of module-level `init()` fns, in source order
36 module_init_fn_modules map[string]string // C init fn name -> V module name
37 module_imports map[string][]string // module -> imported modules
38 c_directives []CDirective
39 inlined_c_structs map[string]bool
40 inlined_c_fns map[string]bool
41 inlined_c_declared_fns map[string]bool
42 c_flags []string
43 libc_compat_fns map[string]bool
44 tc &types.TypeChecker = unsafe { nil }
45 has_builtins bool
46 tmp_count int
47 line_start bool
48 field_name_set map[string]bool // every struct field's C name (lazy) — for const/field collision checks
49 modules map[string]string // alias -> full module name
50 fn_ptr_types map[string]string // fn_ptr:ret|params -> typedef name
51 fixed_array_ret_wrappers map[string]bool // bare fixed-array c_type name -> has a return wrapper struct
52 emitted_fixed_array_typedefs map[string]bool // bare fixed-array typedefs already written (shared across passes)
53 fn_decl_param_types map[string][]types.Type
54 fn_decl_ret_types map[string]types.Type // fn decl name (and qualified variants) -> return type
55 struct_decl_infos map[string]StructDeclInfo
56 struct_decl_short_infos map[string]StructDeclInfo
57 const_runtime_inits []string
58 const_runtime_init_modules []string
59 runtime_inits []string
60 runtime_init_modules []string
61 compiler_vroot string
62 c99_mode bool
63 cur_fn_name string
64 cur_param_names []string
65 cur_param_type_values []types.Type
66 cur_param_types map[string]types.Type
67 cur_mut_params map[string]bool
68 cur_fn_ret types.Type = types.Type(types.void_)
69 cur_fn_ret_is_optional bool
70 cur_fn_ret_base types.Type = types.Type(types.void_)
71 // in_return is true only while generating a `return` statement's value, so a bare
72 // generic literal (`return Box{...}`) may adopt `cur_fn_ret`'s concrete instance —
73 // but a literal in a local decl / argument elsewhere in the body does not.
74 in_return bool
75 expected_expr_type types.Type = types.Type(types.void_)
76 expected_enum string
77 needed_optional_types map[string]string
78 emitted_optional_types map[string]bool
79 emitted_fns map[string]bool
80 array_method_cache map[string]string
81 param_types_cache map[string][]types.Type // (name|fallback) -> resolved param types
82 embedded_fields_by_type map[string][]types.StructField // type name -> its embedded fields (usually empty)
83 param_types_by_short map[string][]types.Type // method short-name suffix -> param types (fallback index)
84 spawn_wrapper_names map[string]string
85 spawn_wrapper_defs []string
86 callback_wrapper_names map[string]string
87 callback_wrapper_defs []string
88 parallel_used bool
89}
90
91struct FixedArrayTypedefInfo {
92 arr types.ArrayFixed
93 module string
94}
95
96struct CDirective {
97 module string
98 text string
99 before_import bool
100}
101
102struct CInlineHeader {
103 text string
104 preserved_directives []string
105 preserved_c_fns []string
106 preserved_c_structs []string
107}
108
109// was_parallel reports whether the last fn codegen actually ran across threads.
110pub fn (g &FlatGen) was_parallel() bool {
111 return g.parallel_used
112}
113
114pub fn (g &FlatGen) c_flags() []string {
115 return g.c_flags.clone()
116}
117
118// set_c99_mode configures whether generated C should support strict C99 builds.
119pub fn (mut g FlatGen) set_c99_mode(enabled bool) {
120 g.c99_mode = enabled
121}
122
123// new creates a FlatGen value for c.
124pub fn FlatGen.new() FlatGen {
125 return FlatGen{
126 sb: strings.new_builder(4096)
127 used_fns: map[string]bool{}
128 test_files: map[string]bool{}
129 str_lit_ids: map[string]int{}
130 global_types: map[string]types.Type{}
131 enum_vals: map[string]int{}
132 interfaces: map[string][]string{}
133 const_vals: map[string]flat.NodeId{}
134 const_modules: map[string]string{}
135 const_init_order: []string{}
136 global_modules: map[string]string{}
137 global_inits: map[string]flat.NodeId{}
138 global_init_order: []string{}
139 iface_impls: map[string][]string{}
140 iface_type_ids: map[string]int{}
141 module_init_fns: []string{}
142 module_init_fn_modules: map[string]string{}
143 module_imports: map[string][]string{}
144 c_directives: []CDirective{}
145 inlined_c_structs: map[string]bool{}
146 inlined_c_fns: map[string]bool{}
147 inlined_c_declared_fns: map[string]bool{}
148 c_flags: []string{}
149 libc_compat_fns: map[string]bool{}
150 modules: map[string]string{}
151 fn_ptr_types: map[string]string{}
152 fixed_array_ret_wrappers: map[string]bool{}
153 emitted_fixed_array_typedefs: map[string]bool{}
154 fn_decl_param_types: map[string][]types.Type{}
155 fn_decl_ret_types: map[string]types.Type{}
156 struct_decl_infos: map[string]StructDeclInfo{}
157 struct_decl_short_infos: map[string]StructDeclInfo{}
158 cur_param_names: []string{}
159 cur_param_type_values: []types.Type{}
160 cur_param_types: map[string]types.Type{}
161 cur_mut_params: map[string]bool{}
162 needed_optional_types: map[string]string{}
163 emitted_optional_types: map[string]bool{}
164 emitted_fns: map[string]bool{}
165 array_method_cache: map[string]string{}
166 param_types_cache: map[string][]types.Type{}
167 embedded_fields_by_type: map[string][]types.StructField{}
168 param_types_by_short: map[string][]types.Type{}
169 spawn_wrapper_names: map[string]string{}
170 spawn_wrapper_defs: []string{}
171 callback_wrapper_names: map[string]string{}
172 callback_wrapper_defs: []string{}
173 str_lits: []string{}
174 defers: []flat.NodeId{}
175 fn_defers: []flat.NodeId{}
176 fn_defer_counts: map[int]string{}
177 defer_capture_names: []string{}
178 defer_capture_types: map[string]types.Type{}
179 const_runtime_inits: []string{}
180 const_runtime_init_modules: []string{}
181 runtime_inits: []string{}
182 runtime_init_modules: []string{}
183 compiler_vroot: ''
184 line_start: true
185 }
186}
187
188// gen supports gen handling for FlatGen.
189pub fn (mut g FlatGen) gen(a &flat.FlatAst) string {
190 tc := types.TypeChecker.new(a)
191 return g.gen_with_used(a, map[string]bool{}, &tc)
192}
193
194// gen_with_used emits with used output for c.
195pub fn (mut g FlatGen) gen_with_used(a &flat.FlatAst, used_fns map[string]bool, tc &types.TypeChecker) string {
196 return g.gen_with_used_options(a, used_fns, tc, false)
197}
198
199pub fn (mut g FlatGen) gen_with_used_test_options(a &flat.FlatAst, used_fns map[string]bool, tc &types.TypeChecker, no_parallel bool, test_files []string) string {
200 g.test_files = map[string]bool{}
201 for file in test_files {
202 g.test_files[file] = true
203 }
204 return g.gen_with_used_options(a, used_fns, tc, no_parallel)
205}
206
207// gen_with_used_options emits with used options output for c.
208pub fn (mut g FlatGen) gen_with_used_options(a &flat.FlatAst, used_fns map[string]bool, tc &types.TypeChecker, no_parallel bool) string {
209 g.a = a
210 g.used_fns = used_fns.clone()
211 g.used_fn_names = []string{}
212 g.str_lits = []string{}
213 g.defers = []flat.NodeId{}
214 g.fn_defers = []flat.NodeId{}
215 g.fn_defer_counts = map[int]string{}
216 g.defer_capture_names = []string{}
217 g.defer_capture_types = map[string]types.Type{}
218 g.const_runtime_inits = []string{}
219 g.const_runtime_init_modules = []string{}
220 g.runtime_inits = []string{}
221 g.runtime_init_modules = []string{}
222 g.compiler_vroot = ''
223 g.str_lit_ids = map[string]int{}
224 g.global_types = map[string]types.Type{}
225 g.enum_vals = map[string]int{}
226 g.interfaces = map[string][]string{}
227 g.const_vals = map[string]flat.NodeId{}
228 g.const_modules = map[string]string{}
229 g.const_init_order = []string{}
230 g.global_modules = map[string]string{}
231 g.global_inits = map[string]flat.NodeId{}
232 g.global_init_order = []string{}
233 g.iface_impls = map[string][]string{}
234 g.iface_type_ids = map[string]int{}
235 g.module_init_fns = []string{}
236 g.module_init_fn_modules = map[string]string{}
237 g.module_imports = map[string][]string{}
238 g.c_directives = []CDirective{}
239 g.inlined_c_structs = map[string]bool{}
240 g.inlined_c_fns = map[string]bool{}
241 g.inlined_c_declared_fns = map[string]bool{}
242 g.c_flags = []string{}
243 g.libc_compat_fns = map[string]bool{}
244 g.modules = map[string]string{}
245 g.fn_ptr_types = map[string]string{}
246 g.fixed_array_ret_wrappers = map[string]bool{}
247 g.emitted_fixed_array_typedefs = map[string]bool{}
248 g.fn_decl_param_types = map[string][]types.Type{}
249 g.fn_decl_ret_types = map[string]types.Type{}
250 g.struct_decl_infos = map[string]StructDeclInfo{}
251 g.struct_decl_short_infos = map[string]StructDeclInfo{}
252 g.cur_param_names = []string{}
253 g.cur_param_type_values = []types.Type{}
254 g.cur_param_types = map[string]types.Type{}
255 g.cur_mut_params = map[string]bool{}
256 g.needed_optional_types = map[string]string{}
257 g.emitted_optional_types = map[string]bool{}
258 g.emitted_fns = map[string]bool{}
259 g.array_method_cache = map[string]string{}
260 g.param_types_cache = map[string][]types.Type{}
261 g.embedded_fields_by_type = map[string][]types.StructField{}
262 g.param_types_by_short = map[string][]types.Type{}
263 g.spawn_wrapper_names = map[string]string{}
264 g.spawn_wrapper_defs = []string{}
265 g.callback_wrapper_names = map[string]string{}
266 g.callback_wrapper_defs = []string{}
267 g.parallel_used = false
268 g.tc = unsafe { tc }
269 if g.tc.a == unsafe { nil } {
270 g.tc.collect(a)
271 }
272 g.has_builtins = g.tc.has_builtins
273 g.collect_gen_info()
274 g.precompute_embedded_fields()
275 g.precompute_param_type_index()
276 g.collect_interface_impls()
277 g.preseed_struct_fn_ptr_types()
278 g.preseed_global_fn_ptr_types()
279 g.preseed_c_extern_fn_ptr_types()
280 // Decide fixed-array return wrappers before generating function bodies, so
281 // signatures, returns and call sites all agree on the wrapped types.
282 g.populate_fixed_array_ret_wrappers()
283 const_code := g.precompute_consts()
284 orig_sb := g.sb
285 orig_line_start := g.line_start
286 g.sb = strings.new_builder(4096)
287 g.line_start = true
288 g.gen_fns_dispatch(no_parallel)
289 fn_code := g.sb.str()
290 // `.str()` copies out of the builder; free the emptied backing array under -gc none.
291 unsafe { g.sb.free() }
292 g.sb = orig_sb
293 g.line_start = orig_line_start
294 g.c99_feature_test_macros()
295 g.emit_preserved_c_directives()
296 g.preamble()
297 g.emit_c_directives()
298 g.enum_decls()
299 g.type_alias_decls()
300 g.type_forward_decls()
301 // Forward-declare multi-return structs before fn-ptr typedefs, which may name a
302 // multi-return as a by-value return type (full bodies come after struct_decls).
303 g.multi_return_forward_decls()
304 // Bare typedefs for primitive-element fixed arrays and wrapper structs for
305 // fixed-array return types, before fn-ptr typedefs (which may name a fixed
306 // array in param or return position) and the function declarations.
307 g.fixed_array_early_typedefs()
308 g.fn_ptr_typedefs()
309 g.struct_decls()
310 g.fixed_array_typedefs()
311 g.multi_return_typedefs()
312 g.optional_typedefs()
313 g.c_extern_forward_decls()
314 g.builtin_abi_decls()
315 g.global_decls()
316 g.forward_decls()
317 g.enum_str_forward_decls()
318 g.callback_wrapper_decls()
319 g.spawn_wrapper_decls()
320 g.register_interface_strings()
321 g.string_literals()
322 g.interface_method_stubs()
323 g.enum_str_defs()
324 g.sb.write_string(const_code)
325 // The final builder now owns a copy of the const code.
326 unsafe { const_code.free() }
327 if g.const_runtime_inits.len > 0 || g.runtime_inits.len > 0 || g.module_init_fns.len > 0
328 || g.global_inits.len > 0 {
329 g.writeln('void _vinit() {')
330 mut emitted_const := []bool{len: g.const_runtime_inits.len}
331 mut emitted_runtime := []bool{len: g.runtime_inits.len}
332 init_fns := g.module_init_fn_map()
333 for mod in g.ordered_startup_modules(init_fns) {
334 g.emit_runtime_inits_for_module(mod, mut emitted_const, mut emitted_runtime)
335 if init_fn := init_fns[mod] {
336 g.writeln('\t${init_fn}();')
337 }
338 }
339 g.emit_remaining_runtime_inits(mut emitted_const, mut emitted_runtime)
340 g.writeln('}')
341 g.writeln('')
342 }
343 g.sb.write_string(fn_code)
344 // The final builder now owns a copy of the function code.
345 unsafe { fn_code.free() }
346 result := g.sb.str()
347 // Keep only the returned C string, not the builder's copied backing array.
348 unsafe { g.sb.free() }
349 return result
350}
351
352// node_kind_id supports node kind id handling for c.
353fn node_kind_id(node flat.Node) int {
354 mut kind_id := node.kind_id
355 if kind_id == 0 && int(node.kind) != 0 {
356 kind_id = int(node.kind)
357 }
358 return kind_id
359}
360
361// collect_gen_info updates collect gen info state for c.
362fn (mut g FlatGen) collect_gen_info() {
363 g.collect_c_flags_from_directives()
364 mut cur_module := 'main'
365 mut cur_file := ''
366 mut seen_import_in_file := false
367 for node_idx in 0 .. g.a.nodes.len {
368 node := g.a.nodes[node_idx]
369 kind_id := node_kind_id(node)
370 if kind_id == 77 {
371 cur_file = node.value
372 g.note_compiler_source_file(node.value)
373 cur_module = 'main'
374 g.tc.cur_module = cur_module
375 g.tc.cur_file = cur_file
376 seen_import_in_file = false
377 continue
378 }
379 if kind_id == 73 {
380 cur_module = node.value
381 g.tc.cur_file = cur_file
382 g.tc.cur_module = cur_module
383 continue
384 }
385 if kind_id == 61 {
386 full_name := qualify_name_in_module(cur_module, node.value)
387 mut ptypes := []types.Type{}
388 g.tc.cur_file = cur_file
389 g.tc.cur_module = cur_module
390 for i in 0 .. node.children_count {
391 child := g.a.child_node(&node, i)
392 if node_kind_id(child) == 75 {
393 raw_pt := g.tc.parse_type(child.typ)
394 pt := raw_pt
395 ptypes << raw_pt
396 if pt is types.FnType {
397 ct := g.tc.c_type(raw_pt)
398 g.resolve_fn_ptr_type(ct)
399 }
400 }
401 }
402 ptypes = g.fn_param_types_with_implicit_veb_ctx(node, ptypes)
403 g.register_fn_decl_param_types(node.value, full_name, ptypes)
404 g.register_fn_decl_ret_type(node.value, full_name, node.typ)
405 // Module-level `init()` functions run once at startup. Collect their C
406 // names so _vinit can invoke them (V semantics).
407 if node.value == 'init' && ptypes.len == 0 {
408 init_cname := qualified_fn_name_in_module(cur_module, 'init')
409 if init_cname !in g.module_init_fns {
410 g.module_init_fns << init_cname
411 }
412 g.module_init_fn_modules[init_cname] = cur_module
413 }
414 continue
415 }
416 if g.collect_c_directive(cur_module, node, cur_file, !seen_import_in_file) {
417 continue
418 }
419 if node.kind == .directive && node.value == 'flag' {
420 continue
421 }
422 if node.kind == .directive && node.value == 'pkgconfig' {
423 continue
424 }
425 if kind_id == 62 {
426 full_name := qualify_name_in_module(cur_module, node.value)
427 g.register_struct_decl_info(node.value, full_name, cur_module, node)
428 continue
429 }
430 if kind_id == 64 {
431 g.tc.cur_file = cur_file
432 g.tc.cur_module = cur_module
433 for i in 0 .. node.children_count {
434 f := g.a.child_node(&node, i)
435 if f.value.starts_with('C.') {
436 continue
437 }
438 mut ft := g.tc.parse_type(f.typ)
439 if ft is types.Void && f.children_count > 0 {
440 ft = g.tc.resolve_type(g.a.child(f, 0))
441 }
442 qname := qualify_name_in_module(cur_module, f.value)
443 g.global_types[qname] = ft
444 g.global_modules[f.value] = cur_module
445 g.global_modules[qname] = cur_module
446 if f.children_count > 0 {
447 val_id := g.a.child(f, 0)
448 if int(val_id) >= 0 {
449 g.global_inits[qname] = val_id
450 g.global_init_order << qname
451 }
452 }
453 g.tc.file_scope.insert(f.value, ft)
454 if qname != f.value {
455 g.tc.file_scope.insert(qname, ft)
456 }
457 }
458 continue
459 }
460 if kind_id == 67 {
461 is_flag := node.typ == 'flag'
462 mut val := 0
463 enum_name := qualify_name_in_module(cur_module, node.value)
464 for i in 0 .. node.children_count {
465 f := g.a.child_node(&node, i)
466 if f.children_count > 0 {
467 if enum_val := g.enum_field_expr_value(g.a.child(f, 0)) {
468 val = enum_val
469 }
470 }
471 if is_flag {
472 g.enum_vals['${enum_name}.${f.value}'] = 1 << val
473 val++
474 } else {
475 g.enum_vals['${enum_name}.${f.value}'] = val
476 val++
477 }
478 }
479 continue
480 }
481 if kind_id == 70 {
482 iface_name := qualify_name_in_module(cur_module, node.value)
483 g.interfaces[iface_name] = g.tc.interface_abstract_method_names(iface_name)
484 continue
485 }
486 if kind_id == 65 {
487 for i in 0 .. node.children_count {
488 f := g.a.child_node(&node, i)
489 if node_kind_id(f) == 66 && f.children_count > 0 {
490 qname := g.const_storage_name(cur_module, f.value)
491 g.const_vals[qname] = g.a.child(f, 0)
492 g.const_modules[qname] = cur_module
493 if (cur_module.len == 0 || cur_module == 'main' || cur_module == 'builtin')
494 && f.value !in g.const_vals {
495 g.const_vals[f.value] = g.a.child(f, 0)
496 g.const_modules[f.value] = cur_module
497 }
498 }
499 }
500 continue
501 }
502 if kind_id == 72 {
503 seen_import_in_file = true
504 alias := node.typ.clone()
505 mod_name := node.value.clone()
506 if alias.len > 0 && mod_name.len > 0 {
507 g.modules[alias] = mod_name
508 }
509 if cur_module.len > 0 && mod_name.len > 0 {
510 dep_module := mod_name
511 if cur_module !in g.module_imports {
512 g.module_imports[cur_module] = []string{}
513 }
514 if dep_module !in g.module_imports[cur_module] {
515 g.module_imports[cur_module] << dep_module
516 }
517 }
518 continue
519 }
520 }
521 g.modules['strings'] = 'strings'
522 g.collect_const_init_order_from_files()
523}
524
525fn (mut g FlatGen) collect_c_flags_from_directives() {
526 mut cur_file := ''
527 for node in g.a.nodes {
528 kind_id := node_kind_id(node)
529 if kind_id == 77 {
530 cur_file = node.value
531 g.note_compiler_source_file(node.value)
532 continue
533 }
534 if node.kind != .directive || node.typ.len == 0 {
535 continue
536 }
537 if node.value == 'flag' {
538 flag := c_flag_arg(node.typ, g.compiler_vroot, cur_file)
539 if flag.len > 0 && flag !in g.c_flags {
540 g.c_flags << flag
541 }
542 continue
543 }
544 if node.value == 'pkgconfig' {
545 for flag in c_pkgconfig_flags(node.typ) {
546 if flag.len > 0 && flag !in g.c_flags {
547 g.c_flags << flag
548 }
549 }
550 }
551 }
552}
553
554fn (mut g FlatGen) collect_c_directive(module_name string, node flat.Node, source_file string, before_import bool) bool {
555 if node.kind != .directive {
556 return false
557 }
558 if node.value in ['include', 'insert'] {
559 if node.typ.len == 0 {
560 return true
561 }
562 include_arg := c_include_arg(node.typ, g.compiler_vroot, source_file)
563 if include_arg.len == 0 {
564 return true
565 }
566 // These helper headers are superseded by the inline compiler helpers emitted in
567 // builtin_abi_decls(); also including them would redefine the helpers.
568 if include_arg.contains('prealloc_atomics.h') || include_arg.contains('filelock_helpers.h')
569 || include_arg.contains('stdatomic') {
570 return true
571 }
572 include_dirs := c_flag_include_dirs(g.c_flags)
573 if header := c_inline_header_text(include_arg, g.compiler_vroot, source_file, include_dirs) {
574 header_text := header.text
575 g.collect_inlined_c_structs(header_text)
576 g.collect_inlined_c_fns(header_text)
577 g.collect_inlined_c_declared_fns(header_text)
578 g.collect_preserved_c_fns(header.preserved_c_fns)
579 g.collect_preserved_c_structs(header.preserved_c_structs)
580 for directive in header.preserved_directives {
581 g.add_c_directive(module_name, directive, before_import)
582 }
583 if header_text.len > 0 {
584 g.add_c_directive(module_name, header_text, before_import)
585 }
586 } else if c_should_preserve_uninlined_include(include_arg) {
587 g.collect_preserved_c_fns(c_preserved_system_include_declared_fns(include_arg))
588 g.collect_preserved_c_structs(c_preserved_system_include_struct_names(include_arg))
589 g.add_c_directive(module_name, '#include ${include_arg}', before_import)
590 }
591 return true
592 }
593 if node.value in ['define', 'undef', 'ifdef', 'ifndef', 'if', 'elif', 'else', 'endif', 'pragma',
594 'error', 'warning'] {
595 g.add_c_directive(module_name, c_preprocessor_directive_line(node.value, node.typ),
596 before_import)
597 return true
598 }
599 return false
600}
601
602fn c_inline_header_text(include_arg string, vroot string, source_file string, include_dirs []string) ?CInlineHeader {
603 if replacement := c_system_include_replacement(include_arg) {
604 return CInlineHeader{
605 text: replacement
606 }
607 }
608 mut seen := map[string]bool{}
609 for path in c_include_file_paths(include_arg, vroot, source_file, include_dirs) {
610 if header := c_inline_header_file(path, vroot, include_dirs, mut seen) {
611 return header
612 }
613 }
614 return none
615}
616
617fn c_inline_header_file(path string, vroot string, include_dirs []string, mut seen map[string]bool) ?CInlineHeader {
618 if path.len == 0 || !os.exists(path) {
619 return none
620 }
621 real_path := os.real_path(path)
622 if seen[real_path] {
623 return CInlineHeader{}
624 }
625 seen[real_path] = true
626 text := os.read_file(real_path) or { return none }
627 return c_inline_header_file_text(text, vroot, real_path, include_dirs, mut seen)
628}
629
630fn c_inline_header_file_text(text string, vroot string, source_file string, include_dirs []string, mut seen map[string]bool) CInlineHeader {
631 mut lines := []string{}
632 mut preserved_directives := []string{}
633 mut preserved_c_fns := []string{}
634 mut preserved_c_structs := []string{}
635 mut include_context := []string{}
636 mut include_prefix := []string{}
637 for line in text.split_into_lines() {
638 clean := line.trim_space()
639 if c_directive_name(clean) == 'include' {
640 include_arg := c_include_arg(c_directive_arg(clean), vroot, source_file)
641 if replacement := c_system_include_replacement(include_arg) {
642 lines << replacement
643 continue
644 }
645 mut inlined := false
646 for path in c_include_file_paths(include_arg, vroot, source_file, include_dirs) {
647 if nested := c_inline_header_file(path, vroot, include_dirs, mut seen) {
648 if nested.text.len > 0 {
649 lines << nested.text
650 }
651 preserved_directives << nested.preserved_directives
652 preserved_c_fns << nested.preserved_c_fns
653 preserved_c_structs << nested.preserved_c_structs
654 inlined = true
655 break
656 }
657 }
658 if !inlined && c_should_preserve_uninlined_include(include_arg) {
659 preserved_directives << c_preserved_nested_include_directive(include_arg,
660 include_context, include_prefix)
661 preserved_c_fns << c_preserved_system_include_declared_fns(include_arg)
662 preserved_c_structs << c_preserved_system_include_struct_names(include_arg)
663 }
664 continue
665 }
666 lines << line
667 c_update_nested_include_context(clean, line, mut include_context)
668 c_update_nested_include_prefix(clean, line, mut include_prefix)
669 }
670 return CInlineHeader{
671 text: lines.join('\n')
672 preserved_directives: preserved_directives
673 preserved_c_fns: preserved_c_fns
674 preserved_c_structs: preserved_c_structs
675 }
676}
677
678fn c_update_nested_include_context(clean string, line string, mut context []string) {
679 match c_directive_name(clean) {
680 'if', 'ifdef', 'ifndef', 'elif', 'else' {
681 context << line
682 }
683 'endif' {
684 for context.len > 0 {
685 name := c_directive_name(context[context.len - 1].trim_space())
686 context.delete_last()
687 if name in ['if', 'ifdef', 'ifndef'] {
688 break
689 }
690 }
691 }
692 else {}
693 }
694}
695
696fn c_update_nested_include_prefix(clean string, line string, mut prefix []string) {
697 match c_directive_name(clean) {
698 'define', 'undef' {
699 prefix << line
700 }
701 else {
702 prefix.clear()
703 }
704 }
705}
706
707fn c_preserved_nested_include_directive(include_arg string, context []string, prefix []string) string {
708 if context.len == 0 && prefix.len == 0 {
709 return '#include ${include_arg}'
710 }
711 mut lines := context.clone()
712 lines << prefix
713 lines << '#include ${include_arg}'
714 for _ in 0 .. c_nested_include_context_depth(context) {
715 lines << '#endif'
716 }
717 return lines.join('\n')
718}
719
720fn c_nested_include_context_depth(context []string) int {
721 mut depth := 0
722 for line in context {
723 if c_directive_name(line.trim_space()) in ['if', 'ifdef', 'ifndef'] {
724 depth++
725 }
726 }
727 return depth
728}
729
730fn c_flag_include_dirs(flags []string) []string {
731 mut dirs := []string{}
732 for flag in flags {
733 tokens := flag.fields()
734 mut i := 0
735 for i < tokens.len {
736 tok := tokens[i]
737 mut dir := ''
738 if tok == '-I' {
739 if i + 1 < tokens.len {
740 dir = tokens[i + 1]
741 i++
742 }
743 } else if tok.starts_with('-I') && tok.len > 2 {
744 dir = tok[2..]
745 }
746 if dir.len > 0 && dir !in dirs {
747 dirs << dir
748 }
749 i++
750 }
751 }
752 return dirs
753}
754
755fn c_system_include_replacement(include_arg string) ?string {
756 match include_arg.trim_space() {
757 '<stdint.h>' {
758 return c_stdint_header_text()
759 }
760 else {
761 return none
762 }
763 }
764}
765
766fn c_should_preserve_uninlined_include(include_arg string) bool {
767 clean := include_arg.trim_space()
768 if clean.len == 0 {
769 return false
770 }
771 if clean[0] == `<` {
772 return !c_headerless_system_include_is_handled(clean)
773 }
774 return true
775}
776
777fn c_preserved_system_include_declared_fns(include_arg string) []string {
778 match include_arg.trim_space() {
779 '<bcrypt.h>' {
780 return ['BCryptGenRandom']
781 }
782 '<dlfcn.h>' {
783 return ['dlopen', 'dlsym', 'dlclose', 'dlerror']
784 }
785 '<mach/mach_time.h>' {
786 return ['mach_absolute_time', 'mach_timebase_info']
787 }
788 else {
789 return []string{}
790 }
791 }
792}
793
794fn c_preserved_system_include_struct_names(include_arg string) []string {
795 match include_arg.trim_space() {
796 '<mach/mach_time.h>' {
797 return ['mach_timebase_info_data_t']
798 }
799 '<X11/Xlib.h>', '<X11/Xutil.h>', '<X11/Xresource.h>', '<X11/XKBlib.h>',
800 '<X11/extensions/XInput2.h>', '<X11/Xcursor/Xcursor.h>' {
801 return c_x11_preserved_struct_names.clone()
802 }
803 else {
804 return []string{}
805 }
806 }
807}
808
809const c_x11_preserved_struct_names = [
810 'Display',
811 'Screen',
812 'Visual',
813 'XButtonEvent',
814 'XClientMessageData',
815 'XClientMessageEvent',
816 'XCrossingEvent',
817 'XcursorImage',
818 'XDestroyWindowEvent',
819 'XEvent',
820 'XFocusChangeEvent',
821 'XGenericEventCookie',
822 'XIEventMask',
823 'XIRawEvent',
824 'XIValuatorState',
825 'XkbDescRec',
826 'XkbKeyAliasRec',
827 'XkbKeyNameRec',
828 'XkbNamesRec',
829 'XKeyEvent',
830 'XMotionEvent',
831 'XPropertyEvent',
832 'XrmValue',
833 'XSelectionClearEvent',
834 'XSelectionEvent',
835 'XSelectionRequestEvent',
836 'XSetWindowAttributes',
837 'XSizeHints',
838 'XVisualInfo',
839 'XWindowAttributes',
840]
841
842fn c_headerless_system_include_is_handled(include_arg string) bool {
843 if include_arg.len < 3 || include_arg[0] != `<` || include_arg[include_arg.len - 1] != `>` {
844 return false
845 }
846 name := include_arg[1..include_arg.len - 1]
847 return name in c_headerless_handled_system_headers
848}
849
850const c_headerless_handled_system_headers = {
851 'arpa/inet.h': true
852 'conio.h': true
853 'dirent.h': true
854 'errno.h': true
855 'execinfo.h': true
856 'fcntl.h': true
857 'float.h': true
858 'io.h': true
859 'math.h': true
860 'netdb.h': true
861 'netinet/in.h': true
862 'netinet/tcp.h': true
863 'poll.h': true
864 'process.h': true
865 'pthread.h': true
866 'pthread_np.h': true
867 'semaphore.h': true
868 'signal.h': true
869 'stdarg.h': true
870 'stdatomic.h': true
871 'stdbool.h': true
872 'stddef.h': true
873 'stdint.h': true
874 'stdio.h': true
875 'stdlib.h': true
876 'string.h': true
877 'synchapi.h': true
878 'sys/epoll.h': true
879 'sys/event.h': true
880 'sys/file.h': true
881 'sys/ioctl.h': true
882 'sys/mman.h': true
883 'sys/ptrace.h': true
884 'sys/random.h': true
885 'sys/resource.h': true
886 'sys/select.h': true
887 'sys/sendfile.h': true
888 'sys/socket.h': true
889 'sys/stat.h': true
890 'sys/statvfs.h': true
891 'sys/syscall.h': true
892 'sys/sysctl.h': true
893 'sys/syslimits.h': true
894 'sys/time.h': true
895 'sys/types.h': true
896 'sys/uio.h': true
897 'sys/utime.h': true
898 'sys/utsname.h': true
899 'sys/wait.h': true
900 'termios.h': true
901 'time.h': true
902 'unistd.h': true
903 'utime.h': true
904 'wchar.h': true
905 'windows.h': true
906 'winsock2.h': true
907 'ws2tcpip.h': true
908}
909
910fn c_stdint_header_text() string {
911 return '#if !defined(__V_HEADERLESS_STDINT_H) && !defined(_STDINT_H) && !defined(_STDINT_H_) && !defined(_STDINT) && !defined(_STDINT_H_INCLUDED) && !defined(_GCC_STDINT_H) && !defined(_MSC_STDINT_H_)
912#define __V_HEADERLESS_STDINT_H
913typedef signed char int8_t;
914typedef short int16_t;
915typedef int int32_t;
916typedef long long int64_t;
917typedef unsigned char uint8_t;
918typedef unsigned short uint16_t;
919typedef unsigned int uint32_t;
920typedef unsigned long long uint64_t;
921#ifndef INT8_MIN
922#define INT8_MIN (-128)
923#endif
924#ifndef INT16_MIN
925#define INT16_MIN (-32767 - 1)
926#endif
927#ifndef INT32_MIN
928#define INT32_MIN (-2147483647 - 1)
929#endif
930#ifndef INT64_MIN
931#define INT64_MIN (-9223372036854775807LL - 1)
932#endif
933#ifndef INT8_MAX
934#define INT8_MAX 127
935#endif
936#ifndef INT16_MAX
937#define INT16_MAX 32767
938#endif
939#ifndef INT32_MAX
940#define INT32_MAX 2147483647
941#endif
942#ifndef INT64_MAX
943#define INT64_MAX 9223372036854775807LL
944#endif
945#ifndef UINT8_MAX
946#define UINT8_MAX 255U
947#endif
948#ifndef UINT16_MAX
949#define UINT16_MAX 65535U
950#endif
951#ifndef UINT32_MAX
952#define UINT32_MAX 4294967295U
953#endif
954#ifndef UINT64_MAX
955#define UINT64_MAX 18446744073709551615ULL
956#endif
957#ifndef INT32_C
958#define INT32_C(c) c
959#endif
960#ifndef UINT32_C
961#define UINT32_C(c) c ## U
962#endif
963#ifndef INT64_C
964#define INT64_C(c) c ## LL
965#endif
966#ifndef UINT64_C
967#define UINT64_C(c) c ## ULL
968#endif
969#endif'
970}
971
972fn (mut g FlatGen) collect_inlined_c_structs(text string) {
973 for line in text.split_into_lines() {
974 clean := line.trim_space()
975 mut rest := ''
976 if clean.starts_with('typedef struct ') {
977 rest = clean['typedef struct '.len..]
978 } else if clean.starts_with('typedef union ') {
979 rest = clean['typedef union '.len..]
980 } else if clean.starts_with('struct ') {
981 rest = clean['struct '.len..]
982 } else if clean.starts_with('union ') {
983 rest = clean['union '.len..]
984 } else {
985 continue
986 }
987 tag := c_header_struct_tag(rest)
988 if tag.len > 0 {
989 g.inlined_c_structs[tag] = true
990 }
991 }
992 for alias in c_typedef_struct_aliases(text) {
993 g.inlined_c_structs[alias] = true
994 }
995 for alias in c_typedef_union_aliases(text) {
996 g.inlined_c_structs[alias] = true
997 }
998}
999
1000fn (mut g FlatGen) collect_inlined_c_fns(text string) {
1001 mut pending_static := false
1002 for line in text.split_into_lines() {
1003 clean := line.trim_space()
1004 if clean.len == 0 {
1005 continue
1006 }
1007 if clean.starts_with('static ') {
1008 name := c_header_fn_name(clean)
1009 if name.len > 0 {
1010 g.inlined_c_fns[name] = true
1011 pending_static = false
1012 } else {
1013 pending_static = c_static_fn_prefix_can_continue(clean)
1014 }
1015 continue
1016 }
1017 if pending_static {
1018 name := c_header_fn_name(clean)
1019 if name.len > 0 {
1020 g.inlined_c_fns[name] = true
1021 pending_static = false
1022 continue
1023 }
1024 if clean.ends_with(';') || clean.contains('{') || clean.starts_with('#') {
1025 pending_static = false
1026 }
1027 }
1028 }
1029}
1030
1031fn (mut g FlatGen) collect_inlined_c_declared_fns(text string) {
1032 for line in text.split_into_lines() {
1033 name := c_header_declared_fn_name(line.trim_space())
1034 if name.len > 0 {
1035 g.inlined_c_declared_fns[name] = true
1036 }
1037 }
1038}
1039
1040fn (mut g FlatGen) collect_preserved_c_fns(names []string) {
1041 for name in names {
1042 g.inlined_c_declared_fns[name] = true
1043 }
1044}
1045
1046fn (mut g FlatGen) collect_preserved_c_structs(names []string) {
1047 for name in names {
1048 g.inlined_c_structs[name] = true
1049 }
1050}
1051
1052fn c_static_fn_prefix_can_continue(line string) bool {
1053 return line in ['static', 'static inline', 'static __inline', 'static __inline__']
1054 || line.starts_with('static inline ') || line.starts_with('static __inline ')
1055 || line.starts_with('static __inline__ ')
1056}
1057
1058fn c_header_struct_tag(rest string) string {
1059 mut end := 0
1060 for end < rest.len {
1061 c := rest[end]
1062 if (c >= `a` && c <= `z`) || (c >= `A` && c <= `Z`) || (c >= `0` && c <= `9`) || c == `_` {
1063 end++
1064 continue
1065 }
1066 break
1067 }
1068 return rest[..end]
1069}
1070
1071fn c_typedef_struct_aliases(text string) []string {
1072 return c_typedef_aggregate_aliases(text, 'struct')
1073}
1074
1075fn c_typedef_union_aliases(text string) []string {
1076 return c_typedef_aggregate_aliases(text, 'union')
1077}
1078
1079fn c_typedef_aggregate_aliases(text string, kind string) []string {
1080 mut aliases := []string{}
1081 prefix := 'typedef ${kind}'
1082 mut start := 0
1083 for start < text.len {
1084 rel_idx := text[start..].index(prefix) or { break }
1085 idx := start + rel_idx
1086 mut pos := idx + prefix.len
1087 if pos < text.len && c_ident_char(text[pos]) {
1088 start = pos + 1
1089 continue
1090 }
1091 for pos < text.len && text[pos].is_space() {
1092 pos++
1093 }
1094 if pos < text.len && text[pos] != `{` {
1095 tag := c_header_struct_tag(text[pos..])
1096 if tag.len == 0 {
1097 start = pos + 1
1098 continue
1099 }
1100 pos += tag.len
1101 for pos < text.len && text[pos].is_space() {
1102 pos++
1103 }
1104 }
1105 if pos >= text.len || text[pos] != `{` {
1106 start = pos + 1
1107 continue
1108 }
1109 close_idx := c_matching_brace_end(text, pos)
1110 if close_idx < 0 {
1111 break
1112 }
1113 semi_rel_idx := text[close_idx + 1..].index_u8(`;`)
1114 if semi_rel_idx < 0 {
1115 break
1116 }
1117 semi_idx := close_idx + 1 + semi_rel_idx
1118 for alias in c_typedef_declarator_aliases(text[close_idx + 1..semi_idx]) {
1119 aliases << alias
1120 }
1121 start = semi_idx + 1
1122 }
1123 return aliases
1124}
1125
1126fn c_matching_brace_end(text string, open_idx int) int {
1127 mut depth := 0
1128 for i in open_idx .. text.len {
1129 if text[i] == `{` {
1130 depth++
1131 } else if text[i] == `}` {
1132 depth--
1133 if depth == 0 {
1134 return i
1135 }
1136 }
1137 }
1138 return -1
1139}
1140
1141fn c_typedef_declarator_aliases(decl string) []string {
1142 mut aliases := []string{}
1143 for part in decl.split(',') {
1144 alias := c_last_ident(part)
1145 if alias.len > 0 {
1146 aliases << alias
1147 }
1148 }
1149 return aliases
1150}
1151
1152fn c_last_ident(text string) string {
1153 mut end := text.len
1154 for end > 0 && !c_ident_char(text[end - 1]) {
1155 end--
1156 }
1157 mut start := end
1158 for start > 0 && c_ident_char(text[start - 1]) {
1159 start--
1160 }
1161 if start == end {
1162 return ''
1163 }
1164 return text[start..end]
1165}
1166
1167fn c_header_fn_name(line string) string {
1168 paren := line.index_u8(`(`)
1169 if paren < 0 {
1170 return ''
1171 }
1172 mut end := paren
1173 for end > 0 && line[end - 1].is_space() {
1174 end--
1175 }
1176 mut start := end
1177 for start > 0 && c_ident_char(line[start - 1]) {
1178 start--
1179 }
1180 if start == end {
1181 return ''
1182 }
1183 name := line[start..end]
1184 if name in ['if', 'for', 'while', 'switch'] {
1185 return ''
1186 }
1187 return name
1188}
1189
1190fn c_header_declared_fn_name(line string) string {
1191 if line.len == 0 || line[0] == `#` || !line.ends_with(';') || !line.contains('(') {
1192 return ''
1193 }
1194 if line.starts_with('typedef ') || line.contains('(*') || line.contains('=')
1195 || line.contains('{') || line.contains('}') {
1196 return ''
1197 }
1198 for prefix in ['return ', 'if ', 'if(', 'for ', 'for(', 'while ', 'while(', 'switch ', 'switch(',
1199 'case ', 'do ', 'else '] {
1200 if line.starts_with(prefix) {
1201 return ''
1202 }
1203 }
1204 paren := line.index_u8(`(`)
1205 mut end := paren
1206 for end > 0 && line[end - 1].is_space() {
1207 end--
1208 }
1209 mut start := end
1210 for start > 0 && c_ident_char(line[start - 1]) {
1211 start--
1212 }
1213 if start == 0 {
1214 return ''
1215 }
1216 return c_header_fn_name(line)
1217}
1218
1219fn c_ident_char(ch u8) bool {
1220 return (ch >= `a` && ch <= `z`) || (ch >= `A` && ch <= `Z`)
1221 || (ch >= `0` && ch <= `9`) || ch == `_`
1222}
1223
1224fn c_include_file_path(include_arg string, vroot string, source_file string) string {
1225 clean := include_arg.trim_space()
1226 if clean.len < 2 {
1227 return ''
1228 }
1229 if clean[0] == `<` {
1230 return ''
1231 }
1232 mut path := ''
1233 if clean[0] == `"` && clean[clean.len - 1] == `"` {
1234 path = clean[1..clean.len - 1]
1235 } else {
1236 path = clean
1237 }
1238 path = c_resolve_pseudo_paths(path, vroot, source_file)
1239 if path.len == 0 || os.is_abs_path(path) {
1240 return path
1241 }
1242 if source_file.len == 0 {
1243 return path
1244 }
1245 return os.join_path_single(os.dir(source_file), path)
1246}
1247
1248fn c_include_file_paths(include_arg string, vroot string, source_file string, include_dirs []string) []string {
1249 clean := include_arg.trim_space()
1250 if clean.len < 2 {
1251 return []string{}
1252 }
1253 mut raw_path := clean
1254 mut search_source_dir := true
1255 if clean[0] == `"` && clean[clean.len - 1] == `"` {
1256 raw_path = clean[1..clean.len - 1]
1257 } else if clean[0] == `<` && clean[clean.len - 1] == `>` {
1258 raw_path = clean[1..clean.len - 1]
1259 search_source_dir = false
1260 }
1261 mut paths := []string{}
1262 if search_source_dir {
1263 first := c_include_file_path(include_arg, vroot, source_file)
1264 if first.len > 0 {
1265 paths << first
1266 }
1267 }
1268 resolved_path := c_resolve_pseudo_paths(raw_path, vroot, source_file)
1269 if os.is_abs_path(resolved_path) {
1270 if resolved_path !in paths {
1271 paths << resolved_path
1272 }
1273 return paths
1274 }
1275 for dir in include_dirs {
1276 if dir.len == 0 {
1277 continue
1278 }
1279 path := os.join_path_single(dir, resolved_path)
1280 if path !in paths {
1281 paths << path
1282 }
1283 }
1284 return paths
1285}
1286
1287fn (mut g FlatGen) add_c_directive(module_name string, text string, before_import bool) {
1288 if text.len == 0 {
1289 return
1290 }
1291 g.c_directives << CDirective{
1292 module: module_name
1293 text: text
1294 before_import: before_import
1295 }
1296}
1297
1298fn c_preprocessor_directive_line(name string, raw string) string {
1299 clean := raw.trim_space()
1300 if clean.len == 0 {
1301 return '#${name}'
1302 }
1303 return '#${name} ${clean}'
1304}
1305
1306// note_compiler_source_file supports note compiler source file handling for FlatGen.
1307fn (mut g FlatGen) note_compiler_source_file(path string) {
1308 if g.compiler_vroot.len > 0 || path.len == 0 {
1309 return
1310 }
1311 mut full_path := path
1312 if !os.is_abs_path(full_path) {
1313 full_path = os.abs_path(full_path)
1314 }
1315 full_path = os.real_path(full_path)
1316 normalized := full_path.replace('\\', '/')
1317 suffix := '/cmd/v/v.v'
1318 if normalized.ends_with(suffix) {
1319 g.compiler_vroot = normalized[..normalized.len - suffix.len]
1320 return
1321 }
1322 vlib_idx := normalized.index('/vlib/') or { return }
1323 if vlib_idx > 0 {
1324 g.compiler_vroot = normalized[..vlib_idx]
1325 }
1326}
1327
1328// collect_const_init_order_from_files converts collect const init order from files data for c.
1329fn (mut g FlatGen) collect_const_init_order_from_files() {
1330 mut seen := map[string]bool{}
1331 g.const_init_order = []string{}
1332 for node in g.a.nodes {
1333 if node_kind_id(node) != 77 || node.children_count == 0 {
1334 continue
1335 }
1336 mut cur_module := 'main'
1337 for i in 0 .. node.children_count {
1338 child := g.a.child_node(&node, i)
1339 kind_id := node_kind_id(child)
1340 if kind_id == 73 {
1341 cur_module = child.value
1342 continue
1343 }
1344 if kind_id != 65 {
1345 continue
1346 }
1347 for j in 0 .. child.children_count {
1348 field := g.a.child_node(child, j)
1349 if node_kind_id(field) != 66 || field.children_count == 0 {
1350 continue
1351 }
1352 qname := g.const_storage_name(cur_module, field.value)
1353 if qname in g.const_vals && !seen[qname] {
1354 seen[qname] = true
1355 g.const_init_order << qname
1356 }
1357 }
1358 }
1359 }
1360}
1361
1362// ordered_module_init_fns supports ordered module init fns handling for FlatGen.
1363fn (g &FlatGen) ordered_module_init_fns() []string {
1364 module_to_init := g.module_init_fn_map()
1365 mut result := []string{}
1366 mut visiting := map[string]bool{}
1367 mut visited := map[string]bool{}
1368 for init_fn in g.module_init_fns {
1369 mod := g.module_init_fn_modules[init_fn] or { '' }
1370 g.visit_module_init(mod, module_to_init, mut visiting, mut visited, mut result)
1371 }
1372 return result
1373}
1374
1375fn (g &FlatGen) module_init_fn_map() map[string]string {
1376 mut module_to_init := map[string]string{}
1377 for init_fn in g.module_init_fns {
1378 mod := g.module_init_fn_modules[init_fn] or { '' }
1379 module_to_init[mod] = init_fn
1380 }
1381 return module_to_init
1382}
1383
1384fn (g &FlatGen) ordered_startup_modules(module_to_init map[string]string) []string {
1385 mut module_order := []string{}
1386 for init_fn in g.module_init_fns {
1387 mod := g.module_init_fn_modules[init_fn] or { '' }
1388 if mod !in module_order {
1389 module_order << mod
1390 }
1391 }
1392 for mod in g.const_runtime_init_modules {
1393 if mod !in module_order {
1394 module_order << mod
1395 }
1396 }
1397 for mod in g.runtime_init_modules {
1398 if mod !in module_order {
1399 module_order << mod
1400 }
1401 }
1402 mut startup_modules := map[string]bool{}
1403 for mod in module_order {
1404 startup_modules[mod] = true
1405 }
1406 for mod, _ in module_to_init {
1407 startup_modules[mod] = true
1408 }
1409 mut result := []string{}
1410 mut visiting := map[string]bool{}
1411 mut visited := map[string]bool{}
1412 for mod in module_order {
1413 g.visit_startup_module(mod, startup_modules, mut visiting, mut visited, mut result)
1414 }
1415 return result
1416}
1417
1418fn (g &FlatGen) visit_startup_module(mod string, startup_modules map[string]bool, mut visiting map[string]bool, mut visited map[string]bool, mut result []string) {
1419 if mod in visited || mod in visiting {
1420 return
1421 }
1422 visiting[mod] = true
1423 for dep in g.module_imports[mod] or { []string{} } {
1424 dep_module := g.startup_dependency_module(dep, startup_modules)
1425 g.visit_startup_module(dep_module, startup_modules, mut visiting, mut visited, mut result)
1426 }
1427 visiting.delete(mod)
1428 visited[mod] = true
1429 if mod in startup_modules {
1430 result << mod
1431 }
1432}
1433
1434fn (g &FlatGen) startup_dependency_module(dep string, startup_modules map[string]bool) string {
1435 if dep in startup_modules || dep in g.module_imports {
1436 return dep
1437 }
1438 short := startup_module_key(dep)
1439 if short in startup_modules || short in g.module_imports {
1440 return short
1441 }
1442 return dep
1443}
1444
1445fn (mut g FlatGen) emit_runtime_inits_for_module(mod string, mut emitted_const []bool, mut emitted_runtime []bool) {
1446 for i, ri in g.const_runtime_inits {
1447 if !emitted_const[i] && i < g.const_runtime_init_modules.len
1448 && g.const_runtime_init_modules[i] == mod {
1449 g.writeln(ri)
1450 emitted_const[i] = true
1451 }
1452 }
1453 for i, ri in g.runtime_inits {
1454 if !emitted_runtime[i] && i < g.runtime_init_modules.len && g.runtime_init_modules[i] == mod {
1455 g.writeln(ri)
1456 emitted_runtime[i] = true
1457 }
1458 }
1459}
1460
1461fn (mut g FlatGen) emit_remaining_runtime_inits(mut emitted_const []bool, mut emitted_runtime []bool) {
1462 for i, ri in g.const_runtime_inits {
1463 if !emitted_const[i] {
1464 g.writeln(ri)
1465 emitted_const[i] = true
1466 }
1467 }
1468 for i, ri in g.runtime_inits {
1469 if !emitted_runtime[i] {
1470 g.writeln(ri)
1471 emitted_runtime[i] = true
1472 }
1473 }
1474}
1475
1476fn (mut g FlatGen) queue_const_runtime_init(line string) {
1477 g.const_runtime_inits << line
1478 g.const_runtime_init_modules << g.tc.cur_module
1479}
1480
1481fn (mut g FlatGen) queue_runtime_init(line string) {
1482 g.runtime_inits << line
1483 g.runtime_init_modules << g.tc.cur_module
1484}
1485
1486// visit_module_init updates visit module init state for FlatGen.
1487fn (g &FlatGen) visit_module_init(mod string, module_to_init map[string]string, mut visiting map[string]bool, mut visited map[string]bool, mut result []string) {
1488 if mod in visited || mod in visiting {
1489 return
1490 }
1491 visiting[mod] = true
1492 for dep in g.module_imports[mod] or { []string{} } {
1493 dep_module := startup_module_key(dep)
1494 g.visit_module_init(dep_module, module_to_init, mut visiting, mut visited, mut result)
1495 }
1496 visiting.delete(mod)
1497 visited[mod] = true
1498 if init_fn := module_to_init[mod] {
1499 result << init_fn
1500 }
1501}
1502
1503fn (g &FlatGen) ordered_c_directives() []string {
1504 mut directives_by_module := map[string][]CDirective{}
1505 mut module_order := []string{}
1506 for directive in g.c_directives {
1507 if directive.module !in directives_by_module {
1508 directives_by_module[directive.module] = []CDirective{}
1509 module_order << directive.module
1510 }
1511 directives_by_module[directive.module] << directive
1512 }
1513 mut result := []string{}
1514 mut visiting := map[string]bool{}
1515 mut visited := map[string]bool{}
1516 for mod in module_order {
1517 g.visit_c_directive_module(mod, directives_by_module, mut visiting, mut visited, mut result)
1518 }
1519 return dedupe_top_level_c_includes(result)
1520}
1521
1522fn (mut g FlatGen) emit_c_directives() {
1523 mut emitted := false
1524 for directive in g.ordered_c_directives() {
1525 if c_contains_preserved_system_include_directive(directive) {
1526 continue
1527 }
1528 g.writeln(directive)
1529 emitted = true
1530 }
1531 if emitted {
1532 g.writeln('')
1533 }
1534}
1535
1536fn (mut g FlatGen) emit_preserved_c_directives() {
1537 mut emitted := false
1538 directives := g.ordered_c_directives()
1539 for i, directive in directives {
1540 if !c_contains_preserved_system_include_directive(directive) {
1541 continue
1542 }
1543 if directive.contains('\n') {
1544 g.emit_preserved_c_directive(directive)
1545 emitted = true
1546 continue
1547 }
1548 prefix := c_lifted_include_context_prefix(directives, i)
1549 for line in prefix {
1550 g.writeln(line)
1551 emitted = true
1552 }
1553 g.emit_preserved_c_directive(directive)
1554 emitted = true
1555 for _ in 0 .. c_lifted_include_context_depth(prefix) {
1556 g.writeln('#endif')
1557 }
1558 }
1559 if emitted {
1560 g.writeln('')
1561 }
1562}
1563
1564fn (mut g FlatGen) emit_preserved_c_directive(directive string) {
1565 if c_preserved_directive_needs_mach_panic_alias(directive) {
1566 g.writeln('#define panic mach_panic')
1567 g.writeln(directive)
1568 g.writeln('#undef panic')
1569 return
1570 }
1571 g.writeln(directive)
1572}
1573
1574fn c_preserved_directive_needs_mach_panic_alias(directive string) bool {
1575 for line in directive.split_into_lines() {
1576 clean := line.trim_space()
1577 if clean == '#include <mach/mach.h>' || clean == '#include <mach/mach_time.h>' {
1578 return true
1579 }
1580 }
1581 return false
1582}
1583
1584fn c_lifted_include_context_prefix(directives []string, include_index int) []string {
1585 mut prefix := []string{}
1586 for i := include_index - 1; i >= 0; i-- {
1587 clean := directives[i].trim_space()
1588 if c_is_preserved_system_include_directive(clean) {
1589 continue
1590 }
1591 if !c_is_liftable_include_context_directive(clean) {
1592 break
1593 }
1594 prefix << directives[i]
1595 }
1596 prefix.reverse_in_place()
1597 return prefix
1598}
1599
1600fn c_lifted_include_context_depth(prefix []string) int {
1601 mut depth := 0
1602 for directive in prefix {
1603 clean := directive.trim_space()
1604 if clean.starts_with('#ifdef') || clean.starts_with('#ifndef') || clean.starts_with('#if ') {
1605 depth++
1606 }
1607 }
1608 return depth
1609}
1610
1611fn c_is_liftable_include_context_directive(directive string) bool {
1612 clean := directive.trim_space()
1613 if clean.len == 0 || clean.contains('\n') || clean.starts_with('#endif') {
1614 return false
1615 }
1616 return clean.starts_with('#define') || clean.starts_with('#undef')
1617 || clean.starts_with('#ifdef') || clean.starts_with('#ifndef') || clean.starts_with('#if ')
1618 || clean.starts_with('#elif') || clean.starts_with('#else')
1619}
1620
1621fn c_is_preserved_system_include_directive(directive string) bool {
1622 clean := directive.trim_space()
1623 return clean.starts_with('#include <') && clean.ends_with('>') && !clean.contains('\n')
1624}
1625
1626fn c_contains_preserved_system_include_directive(directive string) bool {
1627 if c_is_preserved_system_include_directive(directive) {
1628 return true
1629 }
1630 for line in directive.split_into_lines() {
1631 if c_is_preserved_system_include_directive(line) {
1632 return true
1633 }
1634 }
1635 return false
1636}
1637
1638fn (g &FlatGen) visit_c_directive_module(mod string, directives_by_module map[string][]CDirective, mut visiting map[string]bool, mut visited map[string]bool, mut result []string) {
1639 if mod in visited || mod in visiting {
1640 return
1641 }
1642 visiting[mod] = true
1643 directives := directives_by_module[mod] or { []CDirective{} }
1644 for directive in directives {
1645 if directive.before_import {
1646 result << directive.text
1647 }
1648 }
1649 for dep in g.module_imports[mod] or { []string{} } {
1650 if dep in directives_by_module {
1651 g.visit_c_directive_module(dep, directives_by_module, mut visiting, mut visited, mut
1652 result)
1653 }
1654 }
1655 visiting.delete(mod)
1656 visited[mod] = true
1657 for directive in directives {
1658 if !directive.before_import {
1659 result << directive.text
1660 }
1661 }
1662}
1663
1664fn dedupe_top_level_c_includes(directives []string) []string {
1665 mut result := []string{}
1666 mut seen_includes := map[string]bool{}
1667 mut depth := 0
1668 for directive in directives {
1669 clean := directive.trim_space()
1670 if depth == 0 && c_directive_name(clean) == 'include' {
1671 if clean in seen_includes {
1672 continue
1673 }
1674 seen_includes[clean] = true
1675 }
1676 result << directive
1677 name := c_directive_name(clean)
1678 if name in ['if', 'ifdef', 'ifndef'] {
1679 depth++
1680 } else if name == 'endif' && depth > 0 {
1681 depth--
1682 }
1683 }
1684 return result
1685}
1686
1687fn c_directive_name(text string) string {
1688 if text.len == 0 || text[0] != `#` {
1689 return ''
1690 }
1691 body := text[1..].trim_space()
1692 if body.len == 0 {
1693 return ''
1694 }
1695 idx := body.index_u8(` `)
1696 if idx < 0 {
1697 return body
1698 }
1699 return body[..idx]
1700}
1701
1702fn c_directive_arg(text string) string {
1703 if text.len == 0 || text[0] != `#` {
1704 return ''
1705 }
1706 body := text[1..].trim_space()
1707 mut idx := 0
1708 for idx < body.len && !body[idx].is_space() {
1709 idx++
1710 }
1711 if idx >= body.len {
1712 return ''
1713 }
1714 return body[idx..].trim_space()
1715}
1716
1717fn c_include_arg(raw string, vroot string, source_file string) string {
1718 mut clean := c_directive_arg_for_target(raw.trim_space()) or { return '' }
1719 clean = c_resolve_pseudo_paths(clean.trim_space(), vroot, source_file)
1720 if clean.len == 0 {
1721 return ''
1722 }
1723 if clean[0] == `<` {
1724 end := clean.index_u8(`>`)
1725 if end > 0 {
1726 return clean[..end + 1]
1727 }
1728 return clean
1729 }
1730 if clean[0] == `"` {
1731 mut i := 1
1732 for i < clean.len {
1733 if clean[i] == `"` {
1734 return clean[..i + 1]
1735 }
1736 i++
1737 }
1738 }
1739 hash := clean.index_u8(`#`)
1740 if hash > 0 {
1741 return clean[..hash].trim_space()
1742 }
1743 return clean
1744}
1745
1746fn c_flag_arg(raw string, vroot string, source_file string) string {
1747 clean := c_directive_arg_for_target(raw.trim_space()) or { return '' }
1748 if clean.len == 0 {
1749 return ''
1750 }
1751 resolved := c_resolve_pseudo_paths(clean, vroot, source_file)
1752 return c_resolve_relative_flag_paths(resolved, source_file)
1753}
1754
1755// c_resolve_relative_flag_paths rewrites relative path arguments in a `#flag`
1756// directive (e.g. `-I ./thirdparty`, or a bare `./foo.c`) to absolute paths,
1757// resolved against the directory of the source file that carried the directive.
1758// V1 does the same: a project's `#flag` paths are relative to its own module dir,
1759// not to the compiler's build/working directory.
1760fn c_resolve_relative_flag_paths(flag string, source_file string) string {
1761 if source_file.len == 0 || !flag.contains('/') {
1762 return flag
1763 }
1764 base_dir := os.dir(source_file)
1765 if base_dir.len == 0 {
1766 return flag
1767 }
1768 mut out := []string{}
1769 for tok in flag.fields() {
1770 out << c_resolve_flag_path_token(tok, base_dir)
1771 }
1772 return out.join(' ')
1773}
1774
1775fn c_resolve_flag_path_token(tok string, base_dir string) string {
1776 for prefix in ['-I', '-L'] {
1777 if tok.starts_with(prefix) && tok.len > prefix.len {
1778 path := tok[prefix.len..]
1779 if c_flag_path_is_relative(path) {
1780 return prefix + os.real_path(os.join_path_single(base_dir, path))
1781 }
1782 return tok
1783 }
1784 }
1785 if !tok.starts_with('-') && c_flag_path_is_relative(tok) {
1786 return os.real_path(os.join_path_single(base_dir, tok))
1787 }
1788 return tok
1789}
1790
1791fn c_flag_path_is_relative(p string) bool {
1792 if p.len == 0 || os.is_abs_path(p) {
1793 return false
1794 }
1795 return p.starts_with('./') || p.starts_with('../') || p.contains('/')
1796}
1797
1798fn c_directive_arg_for_target(raw string) ?string {
1799 parts := raw.fields()
1800 if parts.len == 0 {
1801 return none
1802 }
1803 if c_flag_has_target_prefix(parts[0]) {
1804 if !c_flag_target_enabled(parts[0]) || parts.len < 2 {
1805 return none
1806 }
1807 return parts[1..].join(' ')
1808 }
1809 return raw
1810}
1811
1812fn c_resolve_pseudo_paths(raw string, vroot string, source_file string) string {
1813 mut result := raw
1814 if result.contains('@VEXEROOT') && vroot.len > 0 {
1815 result = result.replace('@VEXEROOT', vroot)
1816 }
1817 if result.contains('@VROOT') {
1818 result = result.replace('@VROOT', '@VMODROOT')
1819 }
1820 if result.contains('@VMODROOT') {
1821 result = result.replace('@VMODROOT', c_vmod_root_for_file(source_file))
1822 }
1823 if result.contains('@DIR') {
1824 dir := if source_file.len > 0 { os.dir(source_file) } else { os.getwd() }
1825 result = result.replace('@DIR', os.real_path(dir))
1826 }
1827 return result
1828}
1829
1830fn c_vmod_root_for_file(source_file string) string {
1831 mut dir := if source_file.len > 0 { os.dir(source_file) } else { os.getwd() }
1832 if dir.len == 0 {
1833 dir = os.getwd()
1834 }
1835 for {
1836 if os.exists(os.join_path(dir, 'v.mod')) {
1837 return os.real_path(dir)
1838 }
1839 parent := os.dir(dir)
1840 if parent == dir || parent.len == 0 {
1841 return os.real_path(dir)
1842 }
1843 dir = parent
1844 }
1845 return os.real_path(dir)
1846}
1847
1848fn c_pkgconfig_flags(raw string) []string {
1849 name := raw.trim_space()
1850 if name.len == 0 {
1851 return []string{}
1852 }
1853 // The package name comes straight from source text and is interpolated into a
1854 // shell command, so reject anything that is not a plain pkg-config name/flag to
1855 // avoid command injection (e.g. `#pkgconfig foo; touch /tmp/pwned`).
1856 if !c_pkgconfig_arg_is_safe(name) {
1857 return []string{}
1858 }
1859 result := os.execute('pkg-config --cflags --libs ${name}')
1860 if result.exit_code != 0 {
1861 return []string{}
1862 }
1863 return result.output.trim_space().fields()
1864}
1865
1866fn c_pkgconfig_arg_is_safe(raw string) bool {
1867 for ch in raw {
1868 if (ch >= `a` && ch <= `z`) || (ch >= `A` && ch <= `Z`) || (ch >= `0` && ch <= `9`) {
1869 continue
1870 }
1871 if ch in [` `, `\t`, `_`, `-`, `.`, `+`, `:`, `/`] {
1872 continue
1873 }
1874 return false
1875 }
1876 return true
1877}
1878
1879fn c_flag_has_target_prefix(target string) bool {
1880 return target in ['darwin', 'macos', 'linux', 'windows', 'freebsd', 'openbsd', 'netbsd',
1881 'solaris', 'wasm32_emscripten']
1882}
1883
1884fn c_flag_target_enabled(target string) bool {
1885 match target {
1886 'darwin', 'macos' {
1887 $if macos {
1888 return true
1889 }
1890 return false
1891 }
1892 'linux' {
1893 $if linux {
1894 return true
1895 }
1896 return false
1897 }
1898 'windows' {
1899 $if windows {
1900 return true
1901 }
1902 return false
1903 }
1904 'freebsd' {
1905 $if freebsd {
1906 return true
1907 }
1908 return false
1909 }
1910 'openbsd' {
1911 $if openbsd {
1912 return true
1913 }
1914 return false
1915 }
1916 'netbsd' {
1917 $if netbsd {
1918 return true
1919 }
1920 return false
1921 }
1922 'solaris' {
1923 $if solaris {
1924 return true
1925 }
1926 return false
1927 }
1928 'wasm32_emscripten' {
1929 $if wasm32_emscripten {
1930 return true
1931 }
1932 return false
1933 }
1934 else {
1935 return true
1936 }
1937 }
1938}
1939
1940// register_fn_decl_param_types updates register fn decl param types state for c.
1941fn (mut g FlatGen) register_fn_decl_param_types(name string, full_name string, ptypes []types.Type) {
1942 if name !in g.fn_decl_param_types {
1943 g.fn_decl_param_types[name] = ptypes.clone()
1944 }
1945 if g.tc.cur_module.len > 0 && g.tc.cur_module != 'main' && g.tc.cur_module != 'builtin' {
1946 dotted_name := '${g.tc.cur_module}.${name}'
1947 if dotted_name !in g.fn_decl_param_types {
1948 g.fn_decl_param_types[dotted_name] = ptypes.clone()
1949 }
1950 }
1951 if full_name !in g.fn_decl_param_types {
1952 g.fn_decl_param_types[full_name] = ptypes.clone()
1953 }
1954}
1955
1956// register_fn_decl_ret_type indexes a fn decl's return type by its name (and qualified
1957// variants), so the return type can be looked up in O(1) instead of scanning all AST
1958// nodes per call (see fn_decl_return_type_for_call_name).
1959fn (mut g FlatGen) register_fn_decl_ret_type(name string, full_name string, ret_typ string) {
1960 rt := g.tc.parse_type(ret_typ)
1961 if name !in g.fn_decl_ret_types {
1962 g.fn_decl_ret_types[name] = rt
1963 }
1964 if g.tc.cur_module.len > 0 && g.tc.cur_module != 'main' && g.tc.cur_module != 'builtin' {
1965 dotted_name := '${g.tc.cur_module}.${name}'
1966 if dotted_name !in g.fn_decl_ret_types {
1967 g.fn_decl_ret_types[dotted_name] = rt
1968 }
1969 }
1970 if full_name !in g.fn_decl_ret_types {
1971 g.fn_decl_ret_types[full_name] = rt
1972 }
1973 cname := c_name(name)
1974 if cname != name && cname !in g.fn_decl_ret_types {
1975 g.fn_decl_ret_types[cname] = rt
1976 }
1977}
1978
1979// register_struct_decl_info updates register struct decl info state for c.
1980fn (mut g FlatGen) register_struct_decl_info(name string, full_name string, module_name string, node flat.Node) {
1981 info := StructDeclInfo{
1982 node: node
1983 module: module_name
1984 full_name: full_name
1985 }
1986 g.struct_decl_infos[full_name] = info
1987 if name !in g.struct_decl_short_infos {
1988 g.struct_decl_short_infos[name] = info
1989 }
1990}
1991
1992// enum_value_for_type supports enum value for type handling for FlatGen.
1993fn (g &FlatGen) enum_value_for_type(type_name string, field_name string) ?int {
1994 if type_name.len == 0 || field_name.len == 0 {
1995 return none
1996 }
1997 key := '${type_name}.${field_name}'
1998 if val := g.enum_vals[key] {
1999 return val
2000 }
2001 if !type_name.contains('.') && g.tc.cur_module.len > 0 && g.tc.cur_module != 'main'
2002 && g.tc.cur_module != 'builtin' {
2003 qkey := '${g.tc.cur_module}.${type_name}.${field_name}'
2004 if val := g.enum_vals[qkey] {
2005 return val
2006 }
2007 }
2008 if !type_name.contains('.') {
2009 mut found := 0
2010 mut ok := false
2011 for ename, val in g.enum_vals {
2012 if !ename.ends_with('.${type_name}.${field_name}') {
2013 continue
2014 }
2015 if ok {
2016 return none
2017 }
2018 found = val
2019 ok = true
2020 }
2021 if ok {
2022 return found
2023 }
2024 }
2025 return none
2026}
2027
2028fn (g &FlatGen) enum_selector_base_name(name string) ?string {
2029 if name in g.tc.enum_names || name in g.tc.flag_enums {
2030 return name
2031 }
2032 qname := g.tc.qualify_name(name)
2033 if qname in g.tc.enum_names || qname in g.tc.flag_enums {
2034 return qname
2035 }
2036 if name.contains('.') || g.tc.cur_file.len == 0 {
2037 return none
2038 }
2039 candidates := g.tc.file_selective_imports['${g.tc.cur_file}\n${name}'] or { return none }
2040 for candidate in candidates {
2041 if candidate in g.tc.enum_names || candidate in g.tc.flag_enums {
2042 return candidate
2043 }
2044 }
2045 return none
2046}
2047
2048// expr_to_string converts expr to string data for c.
2049fn (mut g FlatGen) expr_to_string(id flat.NodeId) string {
2050 orig := g.sb
2051 orig_line_start := g.line_start
2052 g.sb = strings.new_builder(64)
2053 g.line_start = true
2054 g.gen_expr(id)
2055 result := g.sb.str()
2056 g.sb = orig
2057 g.line_start = orig_line_start
2058 return result
2059}
2060
2061// interface_value_to_string captures, as a string, the boxed interface value the direct return
2062// path emits (`(Iface){._typ = N, ._object = ...}`) — so a deferred return can save it into a
2063// temp without dropping `_typ`/`_object`. Mirrors that path: box a concrete value, else (already
2064// boxed by the transform) emit it as-is.
2065fn (mut g FlatGen) interface_value_to_string(id flat.NodeId, expected types.Type) string {
2066 orig := g.sb
2067 orig_line_start := g.line_start
2068 g.sb = strings.new_builder(64)
2069 // Box mid-statement (no leading indent), matching the direct return path.
2070 g.line_start = false
2071 if !g.gen_interface_value_expr(id, expected) {
2072 g.gen_expr(id)
2073 }
2074 result := g.sb.str()
2075 g.sb = orig
2076 g.line_start = orig_line_start
2077 return result
2078}
2079
2080// fixed_array_copy_source_string captures gen_fixed_array_copy_source as a string, so a deferred
2081// optional/fixed-array return can embed the memcpy source when saving the value into a temp.
2082fn (mut g FlatGen) fixed_array_copy_source_string(value_id flat.NodeId, field_type types.Type) string {
2083 orig := g.sb
2084 orig_line_start := g.line_start
2085 g.sb = strings.new_builder(64)
2086 // Emit mid-statement (no leading indent), matching the direct return path.
2087 g.line_start = false
2088 g.gen_fixed_array_copy_source(value_id, field_type)
2089 result := g.sb.str()
2090 g.sb = orig
2091 g.line_start = orig_line_start
2092 return result
2093}
2094
2095// expr_to_string_with_expected_type converts expr to string with expected type data for c.
2096fn (mut g FlatGen) expr_to_string_with_expected_type(id flat.NodeId, expected types.Type) string {
2097 orig := g.sb
2098 orig_line_start := g.line_start
2099 g.sb = strings.new_builder(64)
2100 g.line_start = true
2101 g.gen_expr_with_expected_type(id, expected)
2102 result := g.sb.str()
2103 g.sb = orig
2104 g.line_start = orig_line_start
2105 return result
2106}
2107
2108fn (mut g FlatGen) gen_amp_c_string_literal(id flat.NodeId, node flat.Node) bool {
2109 if node.kind == .char_literal && node.value.starts_with('c:') {
2110 g.gen_expr(id)
2111 return true
2112 }
2113 if node.kind != .char_literal && node.kind != .string_literal {
2114 return false
2115 }
2116 expr := g.expr_to_string(id)
2117 if expr.len >= 2 && expr[0] == `"` && expr[expr.len - 1] == `"` {
2118 g.write(expr)
2119 return true
2120 }
2121 return false
2122}
2123
2124fn (mut g FlatGen) gen_expr_as_string(id flat.NodeId) {
2125 typ := g.usable_expr_type(id)
2126 if g.gen_map_str_expr(id, typ) {
2127 return
2128 }
2129 g.gen_expr(id)
2130}
2131
2132fn (mut g FlatGen) gen_map_str_expr(id flat.NodeId, typ types.Type) bool {
2133 clean := map_str_clean_type(typ)
2134 if clean !is types.Map {
2135 return false
2136 }
2137 node := g.a.nodes[int(id)]
2138 if node.kind == .map_init && typ !is types.Pointer {
2139 tmp := '__map_str_tmp_${g.tmp_count}'
2140 g.tmp_count++
2141 g.write('({ map ${tmp} = ')
2142 g.gen_expr_with_expected_type(id, clean)
2143 g.write(';')
2144 key_kind := map_str_kind(g.tc, clean.key_type)
2145 val_kind := map_str_kind(g.tc, clean.value_type)
2146 fixed_len := map_str_fixed_len(clean.value_type)
2147 g.write(' v3_map_str(${tmp}, ${key_kind}, ${val_kind}, ${fixed_len}); })')
2148 return true
2149 }
2150 g.write('v3_map_str(')
2151 if typ is types.Pointer {
2152 needs_paren := g.a.nodes[int(id)].kind !in [.ident, .selector, .call]
2153 g.write('*')
2154 if needs_paren {
2155 g.write('(')
2156 }
2157 g.gen_expr(id)
2158 if needs_paren {
2159 g.write(')')
2160 }
2161 } else {
2162 g.gen_expr(id)
2163 }
2164 key_kind := map_str_kind(g.tc, clean.key_type)
2165 val_kind := map_str_kind(g.tc, clean.value_type)
2166 fixed_len := map_str_fixed_len(clean.value_type)
2167 g.write(', ${key_kind}, ${val_kind}, ${fixed_len})')
2168 return true
2169}
2170
2171fn map_str_clean_type(typ types.Type) types.Type {
2172 clean := types.unwrap_pointer(typ)
2173 if clean is types.Alias {
2174 return clean.base_type
2175 }
2176 return clean
2177}
2178
2179fn map_str_kind(tc &types.TypeChecker, typ types.Type) int {
2180 clean := if typ is types.Alias { typ.base_type } else { typ }
2181 if clean is types.String {
2182 return 1
2183 }
2184 if clean is types.Rune {
2185 return 4
2186 }
2187 if clean is types.ISize || clean is types.Char {
2188 return 2
2189 }
2190 if clean is types.USize {
2191 return 3
2192 }
2193 if clean is types.Primitive {
2194 if clean.props.has(.float) {
2195 return if tc.c_type(types.Type(clean)) == 'float' { 8 } else { 5 }
2196 }
2197 name := types.Type(clean).name()
2198 if name in ['i8', 'i16', 'i32', 'i64', 'int'] {
2199 return 2
2200 }
2201 if name in ['u8', 'byte'] {
2202 return 3
2203 }
2204 if name in ['u16', 'u32', 'u64'] {
2205 return 3
2206 }
2207 if name == 'bool' {
2208 return 7
2209 }
2210 }
2211 if fixed := array_fixed_type(clean) {
2212 elem := if fixed.elem_type is types.Alias {
2213 fixed.elem_type.base_type
2214 } else {
2215 fixed.elem_type
2216 }
2217 if elem is types.Primitive && elem.props.has(.float) {
2218 return if tc.c_type(types.Type(elem)) == 'float' { 9 } else { 6 }
2219 }
2220 }
2221 return 0
2222}
2223
2224fn map_str_fixed_len(typ types.Type) int {
2225 if fixed := array_fixed_type(typ) {
2226 if fixed.len > 0 {
2227 return fixed.len
2228 }
2229 if fixed.len_expr.len > 0 && fixed.len_expr.int().str() == fixed.len_expr {
2230 return fixed.len_expr.int()
2231 }
2232 }
2233 return 0
2234}
2235
2236// gen_cast_from_mut_param_address emits pointer casts for `¶m` where `param`
2237// is a mutable V parameter already represented as a C pointer.
2238fn (mut g FlatGen) gen_cast_from_mut_param_address(id flat.NodeId, ct string) bool {
2239 node := g.a.nodes[int(id)]
2240 if node.kind != .prefix || node.op != .amp || node.children_count != 1 {
2241 return false
2242 }
2243 child_id := g.a.child(&node, 0)
2244 child := g.a.nodes[int(child_id)]
2245 if child.kind != .ident || !g.current_param_is_mut(child.value) {
2246 return false
2247 }
2248 param_type := g.current_param_type(child.value) or { return false }
2249 if param_type !is types.Pointer {
2250 return false
2251 }
2252 g.write('(${ct})(')
2253 g.gen_expr(child_id)
2254 g.write(')')
2255 return true
2256}
2257
2258// gen_expr_with_expected_type emits expr with expected type output for c.
2259fn (mut g FlatGen) gen_expr_with_expected_type(id flat.NodeId, expected types.Type) {
2260 old_expected := g.expected_expr_type
2261 old_expected_enum := g.expected_enum
2262 g.expected_expr_type = expected
2263 if expected is types.Enum {
2264 g.expected_enum = expected.name
2265 }
2266 node := g.a.nodes[int(id)]
2267 if node.kind == .dump_expr {
2268 if node.children_count > 0 {
2269 g.gen_expr_with_expected_type(g.a.child(&node, 0), expected)
2270 } else {
2271 g.write('0')
2272 }
2273 g.expected_expr_type = old_expected
2274 g.expected_enum = old_expected_enum
2275 return
2276 }
2277 mut actual := g.usable_expr_type(id)
2278 if node.kind == .ident {
2279 if param_type := g.current_param_type(node.value) {
2280 actual = param_type
2281 }
2282 }
2283 if expected is types.String && g.gen_map_str_expr(id, actual) {
2284 g.expected_expr_type = old_expected
2285 g.expected_enum = old_expected_enum
2286 return
2287 }
2288 if _ := fn_type_from(expected) {
2289 if g.gen_callback_fn_value_for_expected_type(id, expected) {
2290 g.expected_expr_type = old_expected
2291 g.expected_enum = old_expected_enum
2292 return
2293 }
2294 if call_name := g.callback_direct_fn_value_name(id, expected) {
2295 g.write(g.callback_c_fn_name(call_name))
2296 g.expected_expr_type = old_expected
2297 g.expected_enum = old_expected_enum
2298 return
2299 }
2300 }
2301 if expected is types.Array && node.kind == .array_literal {
2302 g.gen_array_literal_value(node, expected.elem_type)
2303 g.expected_expr_type = old_expected
2304 g.expected_enum = old_expected_enum
2305 return
2306 }
2307 if expected !is types.Pointer && expected !is types.Void && expected !is types.OptionType
2308 && expected !is types.ResultType && actual is types.Pointer
2309 && g.type_names_match(actual.base_type, expected) {
2310 needs_paren := node.kind !in [.ident, .selector, .call, .index]
2311 g.write('*')
2312 if needs_paren {
2313 g.write('(')
2314 }
2315 g.gen_expr(id)
2316 if needs_paren {
2317 g.write(')')
2318 }
2319 g.expected_expr_type = old_expected
2320 g.expected_enum = old_expected_enum
2321 return
2322 }
2323 if g.gen_interface_value_expr(id, expected) {
2324 g.expected_expr_type = old_expected
2325 g.expected_enum = old_expected_enum
2326 return
2327 }
2328 if g.gen_sum_value_expr(id, expected) {
2329 g.expected_expr_type = old_expected
2330 g.expected_enum = old_expected_enum
2331 return
2332 }
2333 g.gen_expr(id)
2334 g.expected_expr_type = old_expected
2335 g.expected_enum = old_expected_enum
2336}
2337
2338// gen_sum_value_expr emits sum value expr output for c.
2339fn (mut g FlatGen) gen_sum_value_expr(id flat.NodeId, expected types.Type) bool {
2340 sum_type0 := if expected is types.Alias { expected.base_type } else { expected }
2341 if sum_type0 !is types.SumType {
2342 return false
2343 }
2344 sum_type := sum_type0 as types.SumType
2345 raw_actual0 := g.sum_cast_actual_type(id)
2346 raw_actual_type := if raw_actual0 is types.Alias { raw_actual0.base_type } else { raw_actual0 }
2347 if raw_actual_type is types.SumType {
2348 return false
2349 }
2350 if declared := g.selector_declared_type(id) {
2351 declared0 := if declared is types.Alias { declared.base_type } else { declared }
2352 if declared0 is types.SumType && g.type_names_match(declared0, sum_type0) {
2353 return false
2354 }
2355 }
2356 actual0 := raw_actual0
2357 actual_type := if actual0 is types.Alias { actual0.base_type } else { actual0 }
2358 if actual_type is types.SumType {
2359 return false
2360 }
2361 sum_name := g.resolve_sum_name(sum_type.name)
2362 variant := g.resolve_variant(sum_name, actual_type.name())
2363 variants := g.tc.sum_types[sum_name] or { return false }
2364 if variant !in variants {
2365 return false
2366 }
2367 ct := g.tc.c_type(sum_type0)
2368 idx := g.sum_type_index(sum_name, variant)
2369 field := g.sum_field_name(variant)
2370 if g.variant_references_sum(variant, sum_name) {
2371 inner_ct := g.tc.c_type(g.tc.parse_type(variant))
2372 g.write('(${ct}){.typ = ${idx}, .${field} = (${inner_ct}*)memdup((${inner_ct}[]){')
2373 g.gen_expr(id)
2374 g.write('}, sizeof(${inner_ct}))}')
2375 return true
2376 }
2377 g.write('(${ct}){.typ = ${idx}, .${field} = ')
2378 g.gen_expr(id)
2379 g.write('}')
2380 return true
2381}
2382
2383fn (g &FlatGen) sum_cast_actual_type(id flat.NodeId) types.Type {
2384 mut actual_type := g.tc.resolve_type(id)
2385 if int(id) < 0 || int(id) >= g.a.nodes.len {
2386 return actual_type
2387 }
2388 node := g.a.nodes[int(id)]
2389 if node.kind == .ident {
2390 if param_type := g.current_param_type(node.value) {
2391 return param_type
2392 }
2393 if param_type := g.cur_param_types[node.value] {
2394 return param_type
2395 }
2396 }
2397 return actual_type
2398}
2399
2400// gen_sum_cast_expr emits sum cast expr output for c.
2401fn (mut g FlatGen) gen_sum_cast_expr(target_type types.SumType, inner_id flat.NodeId) {
2402 inner := g.a.nodes[int(inner_id)]
2403 actual_type := g.sum_cast_actual_type(inner_id)
2404 actual_clean := types.unwrap_pointer(actual_type)
2405 variant_name0 := if inner.kind == .struct_init {
2406 inner.value
2407 } else {
2408 actual_clean.name()
2409 }
2410 variant_name := g.resolve_variant(target_type.name, variant_name0)
2411 idx := g.sum_type_index(target_type.name, variant_name)
2412 field := g.sum_field_name(variant_name)
2413 ct := g.tc.c_type(target_type)
2414 variant_type := g.tc.parse_type(variant_name)
2415 variant_is_pointer_arg := actual_type is types.Pointer
2416 && g.type_names_match(actual_type.base_type, variant_type)
2417 if g.variant_references_sum(variant_name, target_type.name) {
2418 inner_ct := g.tc.c_type(variant_type)
2419 if variant_is_pointer_arg {
2420 g.write('(${ct}){.typ = ${idx}, .${field} = ')
2421 if g.pointer_variant_arg_needs_heap_copy(inner) {
2422 g.write('(${inner_ct}*)memdup(')
2423 g.gen_expr(inner_id)
2424 g.write(', sizeof(${inner_ct}))')
2425 } else {
2426 g.gen_expr(inner_id)
2427 }
2428 g.write('}')
2429 } else if inner.kind == .struct_init
2430 && g.resolve_sum_name(inner.value) == g.resolve_sum_name(target_type.name) {
2431 g.write('(${ct}){')
2432 for si in 0 .. inner.children_count {
2433 sf := g.a.child_node(&inner, si)
2434 if si > 0 {
2435 g.write(', ')
2436 }
2437 g.write('.${c_name(sf.value)} = ')
2438 g.gen_lowered_sum_field_value(target_type.name, sf)
2439 }
2440 g.write('}')
2441 } else if inner.kind == .struct_init {
2442 g.write('(${ct}){.typ = ${idx}, .${field} = (${inner_ct}*)memdup(&(${inner_ct}){')
2443 for si in 0 .. inner.children_count {
2444 sf := g.a.child_node(&inner, si)
2445 if si > 0 {
2446 g.write(', ')
2447 }
2448 g.write('.${c_name(sf.value)} = ')
2449 g.gen_expr(g.a.child(sf, 0))
2450 }
2451 g.write('}, sizeof(${inner_ct}))}')
2452 } else {
2453 g.write('(${ct}){.typ = ${idx}, .${field} = (${inner_ct}*)memdup((${inner_ct}[]){')
2454 g.gen_expr(inner_id)
2455 g.write('}, sizeof(${inner_ct}))}')
2456 }
2457 } else {
2458 g.write('(${ct}){.typ = ${idx}, .${field} = ')
2459 if variant_is_pointer_arg {
2460 g.write('*')
2461 }
2462 g.gen_expr(inner_id)
2463 g.write('}')
2464 }
2465}
2466
2467// pointer_variant_arg_needs_heap_copy supports pointer_variant_arg_needs_heap_copy handling in c.
2468fn (g &FlatGen) pointer_variant_arg_needs_heap_copy(node flat.Node) bool {
2469 if node.kind != .prefix || node.op != .amp || node.children_count == 0 {
2470 return false
2471 }
2472 child_id := g.a.child(&node, 0)
2473 child := g.a.nodes[int(child_id)]
2474 if child.kind != .ident {
2475 return false
2476 }
2477 if _ := g.current_param_type(child.value) {
2478 return true
2479 }
2480 if child.value in g.cur_param_types {
2481 return true
2482 }
2483 if _ := g.tc.cur_scope.lookup(child.value) {
2484 return true
2485 }
2486 return false
2487}
2488
2489// selector_declared_type supports selector declared type handling for FlatGen.
2490fn (g &FlatGen) selector_declared_type(id flat.NodeId) ?types.Type {
2491 if int(id) < 0 || int(id) >= g.a.nodes.len {
2492 return none
2493 }
2494 node := g.a.nodes[int(id)]
2495 if node.kind != .selector || node.children_count == 0 {
2496 return none
2497 }
2498 base_id := g.a.child(&node, 0)
2499 base_type0 := types.unwrap_pointer(g.tc.resolve_type(base_id))
2500 base_type := if base_type0 is types.Alias { base_type0.base_type } else { base_type0 }
2501 if base_type is types.Struct {
2502 return g.struct_field_type(base_type.name, node.value)
2503 }
2504 return none
2505}
2506
2507fn (g &FlatGen) c_typedef_cast_call_name(node flat.Node) string {
2508 if node.kind != .call || node.children_count == 0 {
2509 return ''
2510 }
2511 callee := g.a.child_node(&node, 0)
2512 match callee.kind {
2513 .ident {
2514 if callee.value.contains('__') {
2515 return callee.value
2516 }
2517 }
2518 .selector {
2519 if callee.children_count > 0 {
2520 base := g.a.child_node(callee, 0)
2521 if base.kind == .ident && base.value == 'C' {
2522 return callee.value
2523 }
2524 }
2525 }
2526 else {}
2527 }
2528
2529 return ''
2530}
2531
2532// gen_expr_with_possible_enum_type emits expr with possible enum type output for c.
2533fn (mut g FlatGen) gen_expr_with_possible_enum_type(id flat.NodeId, expected types.Type) {
2534 if expected is types.Enum {
2535 g.gen_expr_with_expected_type(id, expected)
2536 return
2537 }
2538 g.gen_expr(id)
2539}
2540
2541fn (g &FlatGen) expected_expr_is_optional_struct() bool {
2542 if g.expected_expr_type is types.Struct {
2543 return g.expected_expr_type.name.starts_with('Optional')
2544 }
2545 return false
2546}
2547
2548fn (mut g FlatGen) type_name_c_type(type_name string) string {
2549 if _ := g.tc.cur_scope.lookup(type_name) {
2550 return c_name(type_name)
2551 }
2552 if type_name.starts_with('fn_ptr:') {
2553 return g.resolve_fn_ptr_type(type_name)
2554 }
2555 t := g.tc.parse_type(type_name)
2556 return g.tc.c_type(t)
2557}
2558
2559fn (mut g FlatGen) sizeof_target(value string) string {
2560 if value.starts_with('fn_ptr:') {
2561 return g.resolve_fn_ptr_type(value)
2562 }
2563 if fixed_target := c_fixed_array_typedef_sizeof_target(value) {
2564 return fixed_target
2565 }
2566 if value.contains('.') {
2567 parts := value.split('.')
2568 if parts.len > 1 {
2569 if g.cur_scope_has_local_name(parts[0]) {
2570 return sizeof_selector_target(parts[0], parts[1..])
2571 }
2572 if global := g.sizeof_global_selector_base(parts[0]) {
2573 return sizeof_selector_target(global, parts[1..])
2574 }
2575 }
2576 }
2577 if fixed := array_fixed_type(g.tc.parse_type(value)) {
2578 c_elem, dims := g.fixed_array_decl_parts(fixed)
2579 return '${c_elem}${dims}'
2580 }
2581 return g.type_name_c_type(value)
2582}
2583
2584fn c_fixed_array_typedef_sizeof_target(value string) ?string {
2585 if !value.starts_with('Array_fixed_') {
2586 return none
2587 }
2588 payload := value['Array_fixed_'.len..]
2589 if !payload.contains('_') {
2590 return none
2591 }
2592 elem := payload.all_before_last('_')
2593 len := payload.all_after_last('_')
2594 if elem.len == 0 || len.len == 0 {
2595 return none
2596 }
2597 return '${elem}[${len}]'
2598}
2599
2600fn sizeof_selector_target(base string, fields []string) string {
2601 mut expr := c_name(base)
2602 for field in fields {
2603 expr += '.${c_field_name(field)}'
2604 }
2605 return expr
2606}
2607
2608fn (g &FlatGen) cur_scope_has_local_name(name string) bool {
2609 mut scope := g.tc.cur_scope
2610 for scope != unsafe { nil } && scope != g.tc.file_scope {
2611 for existing in scope.names {
2612 if existing == name {
2613 return true
2614 }
2615 }
2616 scope = scope.parent
2617 }
2618 return false
2619}
2620
2621fn (g &FlatGen) sizeof_global_selector_base(name string) ?string {
2622 if name.len == 0 || name.contains('.') {
2623 return none
2624 }
2625 current_qname := qualify_name_in_module(g.tc.cur_module, name)
2626 if current_qname in g.global_types {
2627 return current_qname
2628 }
2629 if mod := g.global_modules[name] {
2630 if mod.len == 0 || mod == 'main' || mod == 'builtin' || mod == g.tc.cur_module {
2631 return if mod.len > 0 && mod != 'main' && mod != 'builtin' {
2632 '${mod}.${name}'
2633 } else {
2634 name
2635 }
2636 }
2637 }
2638 return none
2639}
2640
2641// optional_none_type supports optional none type handling for FlatGen.
2642fn (mut g FlatGen) optional_none_type(id flat.NodeId) types.Type {
2643 if g.expected_expr_type is types.OptionType || g.expected_expr_type is types.ResultType {
2644 return g.expected_expr_type
2645 }
2646 if typ := g.tc.expr_type(id) {
2647 if typ is types.OptionType || typ is types.ResultType {
2648 return typ
2649 }
2650 }
2651 if g.cur_fn_ret_is_optional {
2652 return g.cur_fn_ret
2653 }
2654 return types.Type(types.OptionType{
2655 base_type: types.Type(types.void_)
2656 })
2657}
2658
2659// array_index_info supports array index info handling for c.
2660fn array_index_info(t types.Type) (bool, bool, types.Array) {
2661 if t is types.Array {
2662 return true, false, t
2663 }
2664 if t is types.Alias {
2665 base := t.base_type
2666 if base is types.Array {
2667 return true, false, base
2668 }
2669 }
2670 if t is types.Pointer {
2671 base := t.base_type
2672 if base is types.Array {
2673 return true, true, base
2674 }
2675 if base is types.Alias {
2676 alias_base := base.base_type
2677 if alias_base is types.Array {
2678 return true, true, alias_base
2679 }
2680 }
2681 }
2682 return false, false, types.Array{}
2683}
2684
2685// valid_node_id supports valid node id handling for FlatGen.
2686fn (g &FlatGen) valid_node_id(id flat.NodeId) bool {
2687 return g.a != unsafe { nil } && int(id) >= 0 && int(id) < g.a.nodes.len
2688}
2689
2690// const_storage_name supports const storage name handling for FlatGen.
2691fn (g &FlatGen) const_storage_name(module_name string, name string) string {
2692 if module_name.len > 0 && module_name != 'main' && module_name != 'builtin'
2693 && !name.contains('.') {
2694 return '${module_name}.${name}'
2695 }
2696 return name
2697}
2698
2699// const_primary_name supports const primary name handling for FlatGen.
2700fn (g &FlatGen) const_primary_name(name string) string {
2701 mod := if name in g.const_modules { g.const_modules[name] } else { '' }
2702 qname := g.const_storage_name(mod, name)
2703 if qname != name && qname in g.const_vals {
2704 return qname
2705 }
2706 return name
2707}
2708
2709// is_const_alias_name reports whether is const alias name applies in c.
2710fn (g &FlatGen) is_const_alias_name(name string) bool {
2711 return g.const_primary_name(name) != name
2712}
2713
2714// const_ref_name supports const ref name handling for FlatGen.
2715fn (g &FlatGen) const_ref_name(name string) string {
2716 if !name.contains('.') && !name.contains('__') {
2717 cur_qname := g.const_storage_name(g.tc.cur_module, name)
2718 if cur_qname in g.const_vals {
2719 return cur_qname
2720 }
2721 if name in g.const_vals {
2722 mod := g.const_modules[name] or { '' }
2723 if mod.len == 0 || mod == g.tc.cur_module
2724 || (g.tc.cur_module in ['', 'main', 'builtin'] && mod in ['', 'main', 'builtin']) {
2725 return g.const_primary_name(name)
2726 }
2727 }
2728 return ''
2729 }
2730 if name in g.const_vals {
2731 return g.const_primary_name(name)
2732 }
2733 if name.contains('.') {
2734 if name in g.const_vals {
2735 return g.const_primary_name(name)
2736 }
2737 }
2738 sep := if name.contains('.') {
2739 '.'
2740 } else if name.contains('__') {
2741 '__'
2742 } else {
2743 return ''
2744 }
2745 short_name := name.all_after_last(sep)
2746 if short_name !in g.const_vals {
2747 return ''
2748 }
2749 resolved := g.const_primary_name(short_name)
2750 mod := if resolved in g.const_modules { g.const_modules[resolved] } else { '' }
2751 if mod.len == 0 {
2752 return resolved
2753 }
2754 ref_mod := name.all_before_last(sep)
2755 if ref_mod == mod || ref_mod == mod.all_after_last('.') {
2756 return resolved
2757 }
2758 return ''
2759}
2760
2761// const_ref_name_from_node converts const ref name from node data for c.
2762fn (g &FlatGen) const_ref_name_from_node(node flat.Node) string {
2763 if node.kind == .ident {
2764 return g.const_ref_name(node.value)
2765 }
2766 if node.kind == .selector && node.children_count > 0 {
2767 base := g.a.child_node(&node, 0)
2768 if base.kind == .ident {
2769 return g.const_ref_name('${base.value}.${node.value}')
2770 }
2771 }
2772 return ''
2773}
2774
2775// const_expr_to_string converts const expr to string data for c.
2776fn (mut g FlatGen) const_expr_to_string(id flat.NodeId, seen []string) string {
2777 if int(id) < 0 || int(id) >= g.a.nodes.len {
2778 return '0'
2779 }
2780 node := g.a.nodes[int(id)]
2781 return match node.kind {
2782 .ident, .selector {
2783 const_name := g.const_ref_name_from_node(node)
2784 if const_name.len > 0 && const_name !in seen {
2785 mut next_seen := seen.clone()
2786 next_seen << const_name
2787 old_module := g.tc.cur_module
2788 if mod := g.const_modules[const_name] {
2789 g.tc.cur_module = mod
2790 }
2791 dep_expr := g.const_expr_to_string(g.const_vals[const_name], next_seen)
2792 g.tc.cur_module = old_module
2793 if dep_expr.trim_space().len > 0 {
2794 return dep_expr
2795 }
2796 }
2797 g.expr_to_string(id)
2798 }
2799 .infix {
2800 lhs := g.const_expr_to_string(g.a.child(&node, 0), seen)
2801 rhs := g.const_expr_to_string(g.a.child(&node, 1), seen)
2802 '(${lhs}) ${g.op_str(node.op)} (${rhs})'
2803 }
2804 .prefix {
2805 child := g.const_expr_to_string(g.a.child(&node, 0), seen)
2806 '${g.op_str(node.op)}(${child})'
2807 }
2808 .paren {
2809 child := g.const_expr_to_string(g.a.child(&node, 0), seen)
2810 '(${child})'
2811 }
2812 .cast_expr {
2813 target_type := g.tc.parse_type(node.value)
2814 mut ct := g.tc.c_type(target_type)
2815 if ct.starts_with('fn_ptr:') {
2816 ct = g.resolve_fn_ptr_type(ct)
2817 }
2818 if node.value in g.interfaces || g.tc.qualify_name(node.value) in g.interfaces {
2819 return '(${ct}){0}'
2820 }
2821 if target_type is types.SumType {
2822 inner_id := g.a.child(&node, 0)
2823 inner := g.a.nodes[int(inner_id)]
2824 variant_name0 := if inner.kind == .struct_init {
2825 inner.value
2826 } else {
2827 g.tc.resolve_type(inner_id).name()
2828 }
2829 variant_name := g.resolve_variant(target_type.name, variant_name0)
2830 idx := g.sum_type_index(target_type.name, variant_name)
2831 field := g.sum_field_name(variant_name)
2832 inner_val := g.const_expr_to_string(inner_id, seen)
2833 inner_ct := g.tc.c_type(g.tc.parse_type(variant_name))
2834 payload := if inner_val.trim_space().len == 0 { '0' } else { inner_val }
2835 return '(${ct}){.typ = ${idx}, .${field} = (${inner_ct}[]){${payload}}}'
2836 }
2837 if target_type !is types.Primitive && target_type !is types.Char
2838 && target_type !is types.Rune && target_type !is types.ISize
2839 && target_type !is types.USize && target_type !is types.Pointer
2840 && target_type !is types.Enum {
2841 return g.expr_to_string(id)
2842 }
2843 child0 := g.const_expr_to_string(g.a.child(&node, 0), seen)
2844 child := if child0.trim_space().len == 0 { '0' } else { child0 }
2845 '(${ct})(${child})'
2846 }
2847 .array_literal {
2848 mut parts := []string{}
2849 for i in 0 .. node.children_count {
2850 parts << g.const_expr_to_string(g.a.child(&node, i), seen)
2851 }
2852 '{${parts.join(', ')}}'
2853 }
2854 .struct_init {
2855 ct := g.struct_init_c_type_name(node.value)
2856 sum_name := g.resolve_sum_name(node.value)
2857 is_sum_literal := sum_name in g.tc.sum_types
2858 mut parts := []string{}
2859 for i in 0 .. node.children_count {
2860 field := g.a.child_node(&node, i)
2861 if field.kind == .field_init && field.children_count > 0 {
2862 val_id := g.a.child(field, 0)
2863 val_node := g.a.nodes[int(val_id)]
2864 val := if field.value.len == 0 {
2865 const_val := g.const_expr_to_string(val_id, seen)
2866 if const_val.trim_space().len > 0 {
2867 const_val
2868 } else {
2869 if ftyp := g.struct_field_type_at(node.value, i) {
2870 g.expr_to_string_with_expected_type(val_id, ftyp)
2871 } else {
2872 g.expr_to_string(val_id)
2873 }
2874 }
2875 } else if is_sum_literal && field.value != 'typ' {
2876 mut variant := ''
2877 if field.typ.starts_with('&') {
2878 variant = field.typ[1..]
2879 } else if field.typ.len > 0 {
2880 variant = field.typ
2881 } else {
2882 for v in g.tc.sum_types[sum_name] {
2883 if g.sum_field_name(v) == field.value {
2884 variant = v
2885 break
2886 }
2887 }
2888 }
2889 variant = g.resolve_variant(sum_name, variant)
2890 inner_ct := g.tc.c_type(g.tc.parse_type(variant))
2891 const_val := g.const_expr_to_string(val_id, seen)
2892 payload := if const_val.trim_space().len > 0 {
2893 const_val
2894 } else {
2895 g.expr_to_string_with_expected_type(val_id, g.tc.parse_type(variant))
2896 }
2897 '(${inner_ct}[]){${payload}}'
2898 } else if ftyp := g.struct_field_type(node.value, field.value) {
2899 if val_node.kind == .enum_val {
2900 g.expr_to_string_with_expected_type(val_id, ftyp)
2901 } else {
2902 const_val := g.const_expr_to_string(val_id, seen)
2903 if const_val.trim_space().len > 0 {
2904 const_val
2905 } else {
2906 g.expr_to_string_with_expected_type(val_id, ftyp)
2907 }
2908 }
2909 } else {
2910 const_val := g.const_expr_to_string(val_id, seen)
2911 if const_val.trim_space().len > 0 {
2912 const_val
2913 } else {
2914 g.expr_to_string(val_id)
2915 }
2916 }
2917 if field.value.len == 0 {
2918 parts << val
2919 } else {
2920 parts << '.${c_name(field.value)} = ${val}'
2921 }
2922 } else {
2923 parts << g.const_expr_to_string(g.a.child(&node, i), seen)
2924 }
2925 }
2926 '(${ct}){${parts.join(', ')}}'
2927 }
2928 .string_literal {
2929 '{"${c_escape(node.value)}", ${node.value.len}, 1}'
2930 }
2931 .int_literal, .float_literal, .bool_literal, .char_literal, .enum_val, .sizeof_expr {
2932 g.expr_to_string(id)
2933 }
2934 .offsetof_expr {
2935 ct := g.sizeof_target(node.value)
2936 'offsetof(${ct}, ${c_name(node.typ)})'
2937 }
2938 else {
2939 g.expr_to_string(id)
2940 }
2941 }
2942}
2943
2944// const_ident_c_name converts const ident c name data for c.
2945fn (g &FlatGen) const_ident_c_name(name string) string {
2946 if name.contains('.') {
2947 return c_name(name)
2948 }
2949 mod := if name in g.const_modules { g.const_modules[name] } else { '' }
2950 if mod.len > 0 && mod != 'main' && mod != 'builtin' {
2951 return c_name('${mod}.${name}')
2952 }
2953 if (mod == '' || mod == 'main') && name in g.const_modules {
2954 return c_name('main.${name}')
2955 }
2956 return c_name(name)
2957}
2958
2959// fixed_array_len_expr supports fixed array len expr handling for FlatGen.
2960fn (mut g FlatGen) fixed_array_len_expr(type_name string, fallback int) string {
2961 if type_name.len > 0 {
2962 typ := g.tc.parse_type(type_name)
2963 if typ is types.ArrayFixed {
2964 return g.fixed_array_len_value(typ)
2965 }
2966 }
2967 mut raw_len := ''
2968 if type_name.starts_with('[') {
2969 idx := type_name.index_u8(`]`)
2970 if idx > 1 {
2971 raw_len = type_name[1..idx]
2972 }
2973 } else if type_name.contains('[') && type_name.ends_with(']') {
2974 idx := type_name.index_u8(`[`)
2975 if idx >= 0 && idx < type_name.len - 1 {
2976 raw_len = type_name[idx + 1..type_name.len - 1]
2977 }
2978 }
2979 return g.fixed_array_len_raw(raw_len, fallback)
2980}
2981
2982// fixed_array_len_value supports fixed array len value handling for FlatGen.
2983fn (mut g FlatGen) fixed_array_len_value(arr types.ArrayFixed) string {
2984 // Prefer the evaluated integer length: a const-expression size (`[segs + 1]f32`)
2985 // otherwise reaches the raw fallback and is c_name-mangled into garbage.
2986 if v := g.tc.fixed_array_len_value(arr) {
2987 return v.str()
2988 }
2989 return g.fixed_array_len_raw(arr.len_expr, arr.len)
2990}
2991
2992// fixed_array_len_is_zero supports fixed array len is zero handling for FlatGen.
2993fn (mut g FlatGen) fixed_array_len_is_zero(arr types.ArrayFixed) bool {
2994 if value := g.tc.fixed_array_len_value(arr) {
2995 return value == 0
2996 }
2997 return g.fixed_array_len_value(arr).trim_space() == '0'
2998}
2999
3000// fixed_array_len_raw supports fixed array len raw handling for FlatGen.
3001fn (mut g FlatGen) fixed_array_len_raw(raw_len string, fallback int) string {
3002 if raw_len.len == 0 {
3003 return '${fallback}'
3004 }
3005 // A literal or const-expression size (`8`, `SEGS + 1`, `1 << 2`, `8 >>> 1`) folds to an
3006 // integer; emit that literal so the C dimension is always valid — `>>>` has no C form,
3007 // so a digit-leading expression like `8 >>> 1` must not be passed through raw — and a
3008 // non-numeric expr isn't c_name-mangled (`SEGS_+_1`) into an undeclared identifier.
3009 if v := g.tc.const_int_value(raw_len, []string{}) {
3010 return v.str()
3011 }
3012 clean_len := raw_len.replace('_', '')
3013 if clean_len.len > 0 && clean_len[0] >= `0` && clean_len[0] <= `9` {
3014 return clean_len
3015 }
3016 const_name := g.const_ref_name(raw_len)
3017 if const_name.len > 0 {
3018 expr := g.const_expr_to_string(g.const_vals[const_name], []string{})
3019 if expr.trim_space().len > 0 {
3020 return expr
3021 }
3022 return g.const_ident_c_name(const_name)
3023 }
3024 return c_name(raw_len)
3025}
3026
3027fn (mut g FlatGen) fixed_array_decl_parts(arr types.ArrayFixed) (string, string) {
3028 len_expr := g.fixed_array_len_value(arr)
3029 if arr.elem_type is types.ArrayFixed {
3030 base_ct, suffix := g.fixed_array_decl_parts(arr.elem_type)
3031 return base_ct, '[${len_expr}]${suffix}'
3032 }
3033 return g.tc.c_type(arr.elem_type), '[${len_expr}]'
3034}
3035
3036// infix_can_skip_child_parens reports whether a child infix operand needs no
3037// surrounding parentheses. For associative logical chains (`||`, `&&`) a child of
3038// the same operator is safe unparenthesised; this keeps long lowered chains (e.g.
3039// a `match` over hundreds of enum values → `a || b || c || ...`) from nesting
3040// parentheses past the C compiler's bracket-depth limit.
3041fn infix_can_skip_child_parens(parent_op flat.Op, child_op flat.Op) bool {
3042 return (parent_op == .logical_or && child_op == .logical_or)
3043 || (parent_op == .logical_and && child_op == .logical_and)
3044}
3045
3046// assoc_infix_chain_len counts how many same-operator infix nodes hang off the left
3047// spine of `node` (its nesting depth). Capped early since only "very deep" matters.
3048fn (g &FlatGen) assoc_infix_chain_len(node flat.Node) int {
3049 op := node.op
3050 mut cur := node
3051 mut depth := 0
3052 for {
3053 if cur.children_count < 1 {
3054 break
3055 }
3056 lhs_id := g.a.child(&cur, 0)
3057 if !g.valid_node_id(lhs_id) {
3058 break
3059 }
3060 lhs := g.a.nodes[int(lhs_id)]
3061 if lhs.kind == .infix && lhs.op == op {
3062 depth++
3063 if depth > 101 {
3064 break
3065 }
3066 cur = lhs
3067 } else {
3068 break
3069 }
3070 }
3071 return depth
3072}
3073
3074// gen_assoc_infix_chain emits a left-nested `||`/`&&` chain iteratively, producing the
3075// same flat `a || b || c …` C as the recursive path but without growing the stack per
3076// link (a big match's condition chain can be hundreds deep).
3077fn (mut g FlatGen) gen_assoc_infix_chain(node flat.Node) {
3078 op := node.op
3079 op_s := g.op_str(op)
3080 mut operands := []flat.NodeId{cap: 256}
3081 mut cur := node
3082 for {
3083 operands << g.a.child(&cur, 1)
3084 lhs_id := g.a.child(&cur, 0)
3085 lhs := g.a.nodes[int(lhs_id)]
3086 if lhs.kind == .infix && lhs.op == op && g.valid_node_id(g.a.child(&lhs, 0)) {
3087 cur = lhs
3088 } else {
3089 operands << lhs_id
3090 break
3091 }
3092 }
3093 for i := operands.len - 1; i >= 0; i-- {
3094 if i != operands.len - 1 {
3095 g.write(' ${op_s} ')
3096 }
3097 oid := operands[i]
3098 onode := g.a.nodes[int(oid)]
3099 if onode.kind == .infix && !infix_can_skip_child_parens(op, onode.op) {
3100 g.write('(')
3101 g.gen_expr(oid)
3102 g.write(')')
3103 } else {
3104 g.gen_expr(oid)
3105 }
3106 }
3107}
3108
3109// gen_expr emits expr output for c.
3110fn (mut g FlatGen) gen_expr(id flat.NodeId) {
3111 if int(id) < 0 {
3112 g.write('0')
3113 return
3114 }
3115 node := g.a.nodes[int(id)]
3116 match node.kind {
3117 .int_literal {
3118 v := node.value.replace('_', '')
3119 if v.starts_with('0o') {
3120 g.write('0${v[2..]}')
3121 } else {
3122 g.write(v)
3123 }
3124 }
3125 .float_literal {
3126 g.write(node.value.replace('_', ''))
3127 }
3128 .bool_literal {
3129 g.write(node.value)
3130 }
3131 .char_literal {
3132 v := node.value
3133 if v.starts_with('c:') {
3134 cv := v[2..]
3135 g.write('"${cv}"')
3136 } else if v.len == 0 {
3137 g.write("' '")
3138 } else if v.len == 1 {
3139 if v[0] == `\\` {
3140 g.write("'\\\\'")
3141 } else if v[0] == `'` {
3142 g.write("'\\''")
3143 } else {
3144 g.write("'${v}'")
3145 }
3146 } else if v.starts_with('\\') {
3147 g.write("'${v}'")
3148 } else {
3149 runes := v.runes()
3150 if runes.len == 0 {
3151 g.write('0')
3152 } else {
3153 g.write(int(runes[0]).str())
3154 }
3155 }
3156 }
3157 .string_literal {
3158 sid := g.intern_string(node.value)
3159 g.write('_str_${sid}')
3160 }
3161 .string_interp {
3162 g.gen_string_interp(node)
3163 }
3164 .dump_expr {
3165 if node.children_count > 0 {
3166 g.gen_expr(g.a.child(&node, 0))
3167 } else {
3168 g.write('0')
3169 }
3170 }
3171 .ident {
3172 if c_fn_name := g.test_user_main_fn_value_c_name(id, node) {
3173 g.write(c_fn_name)
3174 return
3175 }
3176 looked_up := g.tc.cur_scope.lookup(node.value) or { types.Type(types.void_) }
3177 is_local := looked_up !is types.Void
3178 const_name := if !is_local { g.const_ref_name(node.value) } else { '' }
3179 if const_name.len > 0 {
3180 g.write(g.const_ident_c_name(const_name))
3181 } else if node.value in g.global_modules {
3182 mod := g.global_modules[node.value]
3183 if mod.len > 0 && mod != 'main' && mod != 'builtin' {
3184 g.write(c_name('${mod}.${node.value}'))
3185 } else {
3186 g.write(c_name(node.value))
3187 }
3188 } else {
3189 g.write(c_name(node.value))
3190 }
3191 }
3192 .enum_val {
3193 if node.value in g.enum_vals {
3194 eval := g.enum_vals[node.value]
3195 g.write('${eval}')
3196 return
3197 }
3198 if node.typ.len > 0 {
3199 short_name := node.value.trim_left('.').all_after_last('.')
3200 if eval := g.enum_value_for_type(node.typ, short_name) {
3201 g.write('${eval}')
3202 return
3203 }
3204 }
3205 if g.expected_enum.len > 0 {
3206 ekey := '${g.expected_enum}.${node.value}'
3207 if ekey in g.enum_vals {
3208 eval := g.enum_vals[ekey]
3209 g.write('${eval}')
3210 return
3211 }
3212 if !g.expected_enum.contains('.') && g.tc.cur_module.len > 0
3213 && g.tc.cur_module != 'main' && g.tc.cur_module != 'builtin' {
3214 qkey := '${g.tc.cur_module}.${g.expected_enum}.${node.value}'
3215 if qkey in g.enum_vals {
3216 eval := g.enum_vals[qkey]
3217 g.write('${eval}')
3218 return
3219 }
3220 }
3221 }
3222 for ename, eval in g.enum_vals {
3223 if ename.ends_with('.${node.value}') {
3224 g.write('${eval}')
3225 return
3226 }
3227 }
3228 g.write('0')
3229 }
3230 .call {
3231 // A call to a fixed-array-returning function yields the wrapper struct;
3232 // unwrap `.ret_arr` so the result behaves as the array value everywhere
3233 // (indexing, arg passing, memcpy into a destination).
3234 ret_t := g.declared_call_return_type(id)
3235 if ret_t is types.ArrayFixed && g.tc.c_type(ret_t) in g.fixed_array_ret_wrappers {
3236 g.write('(')
3237 g.gen_call(id, node)
3238 g.write(').ret_arr')
3239 } else {
3240 g.gen_call(id, node)
3241 }
3242 }
3243 .spawn_expr {
3244 g.gen_spawn_expr(node)
3245 }
3246 .infix {
3247 // A very long left-nested `||`/`&&` chain (e.g. from a big match condition or
3248 // a `!in [...]` over many values) would recurse once per link and overflow the
3249 // stack; emit those iteratively. Only pathologically long chains take this path,
3250 // so ordinary code keeps the existing per-node generation unchanged.
3251 if (node.op == .logical_or || node.op == .logical_and)
3252 && g.assoc_infix_chain_len(node) > 100 {
3253 g.gen_assoc_infix_chain(node)
3254 return
3255 }
3256 lhs_id := g.a.child(&node, 0)
3257 rhs_id := g.a.child(&node, 1)
3258 old_expected_enum := g.expected_enum
3259 lhs_type := g.usable_expr_type(lhs_id)
3260 rhs_type := g.usable_expr_type(rhs_id)
3261 if node.op == .arrow && lhs_type is types.Channel {
3262 elem_ct := g.tc.c_type(lhs_type.elem_type)
3263 g.write('sync__Channel__push(')
3264 g.gen_expr(lhs_id)
3265 g.write(', &(${elem_ct}[]){')
3266 g.gen_expr_with_expected_type(rhs_id, lhs_type.elem_type)
3267 g.write('})')
3268 g.expected_enum = old_expected_enum
3269 return
3270 }
3271 if g.gen_array_infix_eq(node, lhs_id, rhs_id, lhs_type, rhs_type) {
3272 g.expected_enum = old_expected_enum
3273 return
3274 }
3275 if lhs_type is types.String || rhs_type is types.String {
3276 if g.gen_string_infix_fallback(node, lhs_id, rhs_id) {
3277 g.expected_enum = old_expected_enum
3278 return
3279 }
3280 }
3281 if lhs_type is types.Enum {
3282 g.expected_enum = lhs_type.name
3283 } else if rhs_type is types.Enum {
3284 g.expected_enum = rhs_type.name
3285 }
3286 if lhs_type is types.Struct {
3287 op_name := match node.op {
3288 .minus { '__minus' }
3289 .plus { '__plus' }
3290 .eq { '__eq' }
3291 .ne { '__ne' }
3292 .lt { '__lt' }
3293 .gt { '__gt' }
3294 .le { '__le' }
3295 .ge { '__ge' }
3296 else { '' }
3297 }
3298
3299 if op_name.len > 0 {
3300 method_name := '${lhs_type.name}${op_name}'
3301 if method_name in g.tc.fn_param_types {
3302 panic('internal error: struct operator overload reached C backend after transform: ${lhs_type.name} op=${node.op}')
3303 }
3304 }
3305 g.gen_expr(lhs_id)
3306 g.write(' ${g.op_str(node.op)} ')
3307 g.gen_expr_with_possible_enum_type(rhs_id, lhs_type)
3308 } else {
3309 lhs_node := g.a.nodes[int(lhs_id)]
3310 rhs_node := g.a.nodes[int(rhs_id)]
3311 if lhs_node.kind == .infix && !infix_can_skip_child_parens(node.op, lhs_node.op) {
3312 g.write('(')
3313 g.gen_expr_with_possible_enum_type(lhs_id, rhs_type)
3314 g.write(')')
3315 } else {
3316 g.gen_expr_with_possible_enum_type(lhs_id, rhs_type)
3317 }
3318 g.write(' ${g.op_str(node.op)} ')
3319 if rhs_node.kind == .infix && !infix_can_skip_child_parens(node.op, rhs_node.op) {
3320 g.write('(')
3321 g.gen_expr_with_possible_enum_type(rhs_id, lhs_type)
3322 g.write(')')
3323 } else {
3324 g.gen_expr_with_possible_enum_type(rhs_id, lhs_type)
3325 }
3326 }
3327 g.expected_enum = old_expected_enum
3328 }
3329 .prefix {
3330 child_id := g.a.child(&node, 0)
3331 child := g.a.nodes[int(child_id)]
3332 if node.op == .arrow {
3333 child_type := g.usable_expr_type(child_id)
3334 if child_type is types.Channel {
3335 elem_ct := g.tc.c_type(child_type.elem_type)
3336 tmp := g.tmp_name()
3337 g.write('({${elem_ct} ${tmp} = (${elem_ct}){0}; sync__Channel__pop(')
3338 g.gen_expr(child_id)
3339 g.write(', &${tmp}); ${tmp};})')
3340 return
3341 }
3342 }
3343 if node.op == .mul && child.kind == .ident {
3344 if typ := g.current_param_type(child.value) {
3345 if typ !is types.Pointer {
3346 g.gen_expr(child_id)
3347 return
3348 }
3349 } else if typ := g.cur_param_types[child.value] {
3350 if typ !is types.Pointer {
3351 g.gen_expr(child_id)
3352 return
3353 }
3354 }
3355 }
3356 if node.op == .amp && g.gen_amp_c_string_literal(child_id, child) {
3357 return
3358 } else if node.op == .amp && child.kind == .struct_init {
3359 g.gen_heap_struct_init(child)
3360 } else if node.op == .amp && child.kind == .assoc {
3361 g.gen_heap_assoc_expr(child)
3362 } else if node.op == .amp && child.kind == .cast_expr {
3363 target_type := g.tc.parse_type(child.value)
3364 ct := g.cast_c_type(target_type)
3365 cast_arg := g.a.child_node(&child, 0)
3366 if cast_arg.kind == .nil_literal {
3367 g.write('(${ct}*)NULL')
3368 return
3369 }
3370 if target_type is types.SumType {
3371 g.write('(${ct}*)memdup(&')
3372 g.gen_sum_cast_expr(target_type, g.a.child(&child, 0))
3373 g.write(', sizeof(${ct}))')
3374 return
3375 }
3376 g.write('(${ct}*)(')
3377 g.gen_expr(g.a.child(&child, 0))
3378 g.write(')')
3379 } else if node.op == .amp && child.kind == .call {
3380 fn_child := g.a.child_node(&child, 0)
3381 if fn_child.kind == .selector {
3382 base_child := g.a.child_node(fn_child, 0)
3383 if base_child.kind == .ident && base_child.value == 'C' {
3384 c_struct_prefix := if fn_child.value.len > 0 && fn_child.value[0] >= `a`
3385 && fn_child.value[0] <= `z` && !fn_child.value.ends_with('_t') {
3386 'struct '
3387 } else {
3388 ''
3389 }
3390 g.write('(${c_struct_prefix}${fn_child.value}*)(')
3391 if child.children_count > 1 {
3392 g.gen_expr(g.a.child(&child, 1))
3393 } else {
3394 g.write('0')
3395 }
3396 g.write(')')
3397 } else {
3398 g.write(g.op_str(node.op))
3399 g.gen_expr(child_id)
3400 }
3401 } else {
3402 g.write(g.op_str(node.op))
3403 g.gen_expr(child_id)
3404 }
3405 } else {
3406 g.write(g.op_str(node.op))
3407 g.gen_expr(child_id)
3408 }
3409 }
3410 .in_expr {
3411 // NOTE: range membership, inline-array-literal membership, dynamic- and
3412 // fixed-array membership, and `!in` negation are lowered by the
3413 // transformer (transform.transform_in_expr). Map membership stays as an
3414 // in_expr so each backend can lower it directly.
3415 lhs_id := g.a.child(&node, 0)
3416 rhs_id := g.a.child(&node, 1)
3417 rhs := g.a.nodes[int(rhs_id)]
3418 rhs_type := g.usable_expr_type(rhs_id)
3419 clean_rhs := types.unwrap_pointer(rhs_type)
3420 if clean_rhs is types.Map {
3421 c_key := g.tc.c_type(clean_rhs.key_type)
3422 is_ptr := rhs_type is types.Pointer
3423 if is_ptr {
3424 g.write('map__exists(')
3425 } else {
3426 g.write('map__exists(&')
3427 }
3428 g.gen_expr(rhs_id)
3429 g.write(', &(${c_key}[]){')
3430 g.gen_expr(lhs_id)
3431 g.write('})')
3432 } else if rhs.kind == .array_literal {
3433 if rhs.children_count == 0 {
3434 g.write('false')
3435 } else {
3436 lhs_type := g.usable_expr_type(lhs_id)
3437 g.write('(')
3438 for i in 0 .. rhs.children_count {
3439 if i > 0 {
3440 g.write(' || ')
3441 }
3442 elem_id := g.a.child(&rhs, i)
3443 elem_type := g.usable_expr_type(elem_id)
3444 if lhs_type is types.String || elem_type is types.String {
3445 g.write('string__eq(')
3446 g.gen_expr(lhs_id)
3447 g.write(', ')
3448 g.gen_expr(elem_id)
3449 g.write(')')
3450 } else {
3451 g.gen_expr(lhs_id)
3452 g.write(' == ')
3453 g.gen_expr(elem_id)
3454 }
3455 }
3456 g.write(')')
3457 }
3458 } else if clean_rhs is types.Array {
3459 fn_name := array_membership_fn_name(clean_rhs.elem_type, false)
3460 g.write('${fn_name}(')
3461 // A `mut []T` param (or any `&[]T`) is a pointer in C; the membership
3462 // helper takes the array by value, so dereference it first.
3463 if rhs_type is types.Pointer {
3464 g.write('*')
3465 }
3466 g.gen_expr(rhs_id)
3467 g.write(', ')
3468 g.gen_expr(lhs_id)
3469 g.write(')')
3470 } else if clean_rhs is types.ArrayFixed {
3471 fn_name := array_membership_fn_name(clean_rhs.elem_type, true)
3472 len_expr := g.fixed_array_len_value(clean_rhs)
3473 g.write('${fn_name}(')
3474 g.gen_expr(rhs_id)
3475 g.write(', ${len_expr}, ')
3476 g.gen_expr(lhs_id)
3477 g.write(')')
3478 } else if clean_rhs is types.Struct && clean_rhs.name == 'array' {
3479 lhs_type := g.usable_expr_type(lhs_id)
3480 fn_name := array_membership_fn_name(lhs_type, false)
3481 g.write('${fn_name}(')
3482 g.gen_expr(rhs_id)
3483 g.write(', ')
3484 g.gen_expr(lhs_id)
3485 g.write(')')
3486 } else {
3487 panic('internal error: non-map membership reached C backend in ${g.cur_fn_name}: rhs=${rhs_type.name()} kind=${rhs.kind} value=${rhs.value}')
3488 }
3489 }
3490 .postfix {
3491 g.gen_expr(g.a.child(&node, 0))
3492 g.write(g.op_str(node.op))
3493 }
3494 .paren {
3495 g.write('(')
3496 g.gen_expr(g.a.child(&node, 0))
3497 g.write(')')
3498 }
3499 .selector {
3500 base_id := g.a.child(&node, 0)
3501 base := g.a.nodes[int(base_id)]
3502 base_type0 := g.tc.resolve_type(base_id)
3503 if base_type0 is types.Channel && node.value in ['closed', 'len'] {
3504 if node.value == 'closed' {
3505 g.write('(atomic_load_u16(&')
3506 g.gen_expr(base_id)
3507 g.write('->closed) != 0)')
3508 } else {
3509 g.write('sync__Channel__len(')
3510 g.gen_expr(base_id)
3511 g.write(')')
3512 }
3513 return
3514 }
3515 base_is_local := if base.kind == .ident {
3516 (g.tc.cur_scope.lookup(base.value) or { types.Type(types.void_) }) !is types.Void
3517 } else {
3518 false
3519 }
3520 // A method used as a value (e.g. `game.draw` passed as a callback) rather
3521 // than a field access — bind the receiver and yield a wrapper function.
3522 if g.gen_method_value_closure(base_id, base_type0, node.value) {
3523 return
3524 }
3525 enum_selector_qbase := if base.kind == .ident && base.value != 'C' && !base_is_local {
3526 g.enum_selector_base_name(base.value) or { '' }
3527 } else {
3528 ''
3529 }
3530 if base.kind == .ident && base.value == 'C' {
3531 g.write(c_winapi_wide_export_name(node.value))
3532 } else if enum_selector_qbase.len > 0 {
3533 ekey := '${enum_selector_qbase}.${node.value}'
3534 if eval := g.enum_vals[ekey] {
3535 g.write('${eval}')
3536 } else {
3537 g.write('0')
3538 }
3539 } else if base_type0 is types.String && node.value == 'len' {
3540 g.gen_expr(base_id)
3541 g.write('.len')
3542 } else if types.unwrap_pointer(base_type0) is types.Array && node.value == 'len' {
3543 needs_paren := base.kind !in [.ident, .selector, .call]
3544 if needs_paren {
3545 g.write('(')
3546 }
3547 g.gen_expr(base_id)
3548 if needs_paren {
3549 g.write(')')
3550 }
3551 if base_type0 is types.Pointer {
3552 g.write('->len')
3553 } else {
3554 g.write('.len')
3555 }
3556 } else if base.kind == .call && base.children_count == 2
3557 && g.c_typedef_cast_call_name(base).len > 0 {
3558 cast_name := g.c_typedef_cast_call_name(base)
3559 cast_arg_id := g.a.child(&base, 1)
3560 g.write('((${c_name(cast_name)}*)')
3561 g.gen_expr(cast_arg_id)
3562 g.write(')->${c_name(node.value)}')
3563 } else if base.kind == .cast_expr && base.children_count > 0
3564 && (base.value.starts_with('C.') || base.value.contains('__')) {
3565 cast_child_id := g.a.child(&base, 0)
3566 cast_name := if base.value.starts_with('C.') { base.value[2..] } else { base.value }
3567 g.write('((${c_name(cast_name)}*)')
3568 g.gen_expr(cast_child_id)
3569 g.write(')->${c_name(node.value)}')
3570 } else if base.kind == .cast_expr && base.children_count > 0 {
3571 needs_paren := base.kind !in [.ident, .selector]
3572 if needs_paren {
3573 g.write('(')
3574 }
3575 g.gen_expr(base_id)
3576 if needs_paren {
3577 g.write(')')
3578 }
3579 if node.op == .arrow || base_type0 is types.Pointer {
3580 g.write('->')
3581 } else {
3582 g.write('.')
3583 }
3584 g.write(c_name(node.value))
3585 } else if node.value == 'len' && base.kind == .ident {
3586 base_type := g.tc.resolve_type(base_id)
3587 if base_type is types.ArrayFixed {
3588 g.write(g.fixed_array_len_value(base_type))
3589 } else {
3590 raw_type := g.tc.cur_scope.lookup(base.value) or { base_type }
3591 g.gen_expr(base_id)
3592 if raw_type is types.Pointer {
3593 g.write('->len')
3594 } else {
3595 g.write('.len')
3596 }
3597 }
3598 } else if base.kind == .ident && !base_is_local && g.has_import_alias(base.value) {
3599 mod := g.import_alias_module(base.value) or { '' }
3600 short_mod := if mod.contains('.') {
3601 mod.all_after_last('.')
3602 } else {
3603 mod
3604 }
3605 // A module-level const is stored under the importing module's full path
3606 // (e.g. `v3.gen.wasm`), matching its function naming. Reference it by that
3607 // exact storage name rather than the short alias, otherwise we'd emit an
3608 // undeclared `wasm__x` for a const defined as `v3__gen__wasm__x`.
3609 full_qname := g.const_storage_name(mod, node.value)
3610 if full_qname in g.const_vals {
3611 g.write(c_name(full_qname))
3612 } else {
3613 g.write(c_name('${short_mod}.${node.value}'))
3614 }
3615 } else if base.kind == .selector && base.children_count > 0
3616 && g.is_module_qualified_enum(base) {
3617 inner_base := g.a.child_node(&base, 0)
3618 mod := g.import_alias_module(inner_base.value) or { inner_base.value }
3619 short_mod := if mod.contains('.') {
3620 mod.all_after_last('.')
3621 } else {
3622 mod
3623 }
3624 qname := '${short_mod}.${base.value}'
3625 if qname in g.tc.enum_names || base.value in g.tc.enum_names {
3626 ekey := '${qname}.${node.value}'
3627 ekey2 := '${base.value}.${node.value}'
3628 if ekey in g.enum_vals {
3629 eval := g.enum_vals[ekey]
3630 g.write('${eval}')
3631 } else if ekey2 in g.enum_vals {
3632 eval := g.enum_vals[ekey2]
3633 g.write('${eval}')
3634 } else {
3635 g.write(c_name('${qname}.${node.value}'))
3636 }
3637 } else {
3638 g.write(c_name('${qname}.${node.value}'))
3639 }
3640 } else if embedded := g.direct_embedded_field_for_selector(base_type0, node.value) {
3641 needs_paren := base.kind !in [.ident, .selector]
3642 if needs_paren {
3643 g.write('(')
3644 }
3645 g.gen_expr(base_id)
3646 if needs_paren {
3647 g.write(')')
3648 }
3649 if node.op == .arrow || base_type0 is types.Pointer {
3650 g.write('->')
3651 } else {
3652 g.write('.')
3653 }
3654 g.write(c_name(embedded.name))
3655 } else if embedded_path := g.embedded_field_path_for_promoted_selector(base_type0,
3656 node.value)
3657 {
3658 needs_paren := base.kind !in [.ident, .selector]
3659 if needs_paren {
3660 g.write('(')
3661 }
3662 g.gen_expr(base_id)
3663 if needs_paren {
3664 g.write(')')
3665 }
3666 mut is_ptr := node.op == .arrow || base_type0 is types.Pointer
3667 for embedded in embedded_path {
3668 op := if is_ptr { '->' } else { '.' }
3669 g.write('${op}${c_name(embedded.name)}')
3670 is_ptr = embedded.typ is types.Pointer
3671 }
3672 final_op := if is_ptr { '->' } else { '.' }
3673 g.write('${final_op}${c_name(node.value)}')
3674 } else {
3675 needs_paren := base.kind !in [.ident, .selector]
3676 if needs_paren {
3677 g.write('(')
3678 }
3679 g.gen_expr(base_id)
3680 if needs_paren {
3681 g.write(')')
3682 }
3683 mut is_ptr := false
3684 if base.kind == .ident {
3685 if typ := g.tc.cur_scope.lookup(base.value) {
3686 is_ptr = typ is types.Pointer
3687 }
3688 } else if base.kind == .selector {
3689 if declared := g.selector_declared_type(base_id) {
3690 is_ptr = declared is types.Pointer
3691 } else {
3692 resolved := g.tc.resolve_type(base_id)
3693 is_ptr = resolved is types.Pointer
3694 }
3695 } else {
3696 resolved := g.tc.resolve_type(base_id)
3697 is_ptr = resolved is types.Pointer
3698 }
3699 if node.op == .arrow || is_ptr {
3700 g.write('->')
3701 } else {
3702 g.write('.')
3703 }
3704 g.write(c_name(node.value))
3705 }
3706 }
3707 .index {
3708 base_id := g.a.child(&node, 0)
3709 base_type := g.tc.resolve_type(base_id)
3710 if node.value == 'range' {
3711 g.gen_slice_expr(node, base_id, base_type)
3712 } else if base_type is types.Map {
3713 c_key := g.value_c_type(base_type.key_type)
3714 c_val := g.value_c_type(base_type.value_type)
3715 g.write('(*(${c_val}*)map__get(&')
3716 g.gen_expr(base_id)
3717 g.write(', &(${c_key}[]){')
3718 g.gen_expr(g.a.child(&node, 1))
3719 g.write('}, &(${c_val}[]){0}))')
3720 } else {
3721 is_fixed_array_index, fixed_is_ptr, _ := fixed_array_index_info(base_type)
3722 if is_fixed_array_index {
3723 if fixed_is_ptr {
3724 g.write('(*')
3725 g.gen_expr(base_id)
3726 g.write(')')
3727 } else {
3728 g.gen_expr(base_id)
3729 }
3730 g.write('[')
3731 g.gen_expr(g.a.child(&node, 1))
3732 g.write(']')
3733 } else {
3734 is_array_index, is_ptr, arr_type := array_index_info(base_type)
3735 if is_array_index {
3736 index_type := if g.expected_expr_type is types.OptionType
3737 || g.expected_expr_type is types.ResultType
3738 || g.expected_expr_is_optional_struct() {
3739 g.expected_expr_type
3740 } else if node.typ.starts_with('?') || node.typ.starts_with('!') {
3741 g.tc.parse_type(node.typ)
3742 } else {
3743 arr_type.elem_type
3744 }
3745 c_elem := g.value_c_type(index_type)
3746 g.write('(*(${c_elem}*)array_get(')
3747 if is_ptr {
3748 g.write('*')
3749 }
3750 g.gen_expr(base_id)
3751 g.write(', ')
3752 g.gen_expr(g.a.child(&node, 1))
3753 g.write('))')
3754 } else if base_type is types.String {
3755 // Parenthesize the base: a smartcast sum variant yields a deref
3756 // like `*v._string`, and `*v._string.str[i]` would bind as
3757 // `*(v._string.str[i])`. `(*v._string).str[i]` is what we want.
3758 g.write('(')
3759 g.gen_expr(base_id)
3760 g.write(').str[')
3761 g.gen_expr(g.a.child(&node, 1))
3762 g.write(']')
3763 } else if base_type is types.Pointer {
3764 ptr_type := base_type
3765 if ptr_type.base_type is types.Void {
3766 g.write('((u8*)')
3767 g.gen_expr(base_id)
3768 g.write(')[')
3769 g.gen_expr(g.a.child(&node, 1))
3770 g.write(']')
3771 } else {
3772 g.gen_expr(base_id)
3773 g.write('[')
3774 g.gen_expr(g.a.child(&node, 1))
3775 g.write(']')
3776 }
3777 } else {
3778 g.gen_expr(base_id)
3779 g.write('[')
3780 g.gen_expr(g.a.child(&node, 1))
3781 g.write(']')
3782 }
3783 }
3784 }
3785 }
3786 .array_init {
3787 raw_init_type := g.tc.parse_type(node.value)
3788 init_type := raw_init_type
3789 if init_type is types.ArrayFixed {
3790 ct := g.tc.c_type(raw_init_type)
3791 g.write('(${ct}){0}')
3792 } else {
3793 c_elem := g.sizeof_target(node.value)
3794 g.write('array_new(sizeof(${c_elem}), 0, 0)')
3795 }
3796 }
3797 .map_init {
3798 g.gen_map_init(id, node)
3799 }
3800 .sql_expr {
3801 panic('internal error: SQL expression reached C backend after transform')
3802 }
3803 .cast_expr {
3804 target_type := g.tc.parse_type(node.value)
3805 mut ct := g.cast_c_type(target_type)
3806 if ct.starts_with('fn_ptr:') {
3807 ct = g.resolve_fn_ptr_type(ct)
3808 }
3809 if node.value in g.interfaces || g.tc.qualify_name(node.value) in g.interfaces {
3810 g.write('(${ct}){0}')
3811 } else if target_type is types.SumType {
3812 g.gen_sum_cast_expr(target_type, g.a.child(&node, 0))
3813 } else if target_type is types.Pointer
3814 && g.gen_cast_from_mut_param_address(g.a.child(&node, 0), ct) {
3815 return
3816 } else {
3817 g.write('(${ct})(')
3818 g.gen_expr(g.a.child(&node, 0))
3819 g.write(')')
3820 }
3821 }
3822 .struct_init {
3823 g.gen_struct_init(node)
3824 }
3825 .if_expr {
3826 g.gen_if_expr(node)
3827 }
3828 .array_literal {
3829 g.write('{')
3830 for i in 0 .. node.children_count {
3831 if i > 0 {
3832 g.write(', ')
3833 }
3834 g.gen_expr(g.a.child(&node, i))
3835 }
3836 g.write('}')
3837 }
3838 .nil_literal {
3839 g.write('NULL')
3840 }
3841 .none_expr {
3842 ct := g.optional_type_name(g.optional_none_type(id))
3843 g.write('(${ct}){.ok = false}')
3844 }
3845 .or_expr {
3846 g.gen_or_expr(node)
3847 }
3848 .block {
3849 if node.children_count > 1 {
3850 g.write('({')
3851 for bi in 0 .. node.children_count - 1 {
3852 g.gen_node(g.a.child(&node, bi))
3853 }
3854 last_id := g.a.child(&node, node.children_count - 1)
3855 last := g.a.nodes[int(last_id)]
3856 if last.kind == .expr_stmt {
3857 g.gen_expr(g.a.child(&last, 0))
3858 } else if last.kind == .if_expr {
3859 g.gen_expr(last_id)
3860 } else {
3861 g.gen_node(last_id)
3862 }
3863 g.write(';})')
3864 } else if node.children_count > 0 {
3865 last_id := g.a.child(&node, 0)
3866 last := g.a.nodes[int(last_id)]
3867 if last.kind == .expr_stmt {
3868 g.gen_expr(g.a.child(&last, 0))
3869 } else {
3870 g.gen_expr(last_id)
3871 }
3872 }
3873 }
3874 .is_expr {
3875 expr_id := g.a.child(&node, 0)
3876 expr_type := g.tc.resolve_type(expr_id)
3877 clean := types.unwrap_pointer(expr_type)
3878 if clean is types.SumType {
3879 idx := g.sum_type_index(clean.name, node.value)
3880 g.write('(')
3881 if expr_type.is_pointer() {
3882 g.gen_expr(expr_id)
3883 g.write('->typ == ${idx}')
3884 } else {
3885 g.gen_expr(expr_id)
3886 g.write('.typ == ${idx}')
3887 }
3888 g.write(')')
3889 } else {
3890 g.write('1')
3891 }
3892 }
3893 .as_expr {
3894 expr_id := g.a.child(&node, 0)
3895 expr_type := g.tc.resolve_type(expr_id)
3896 clean := types.unwrap_pointer(expr_type)
3897 if clean is types.SumType {
3898 qv := g.resolve_variant(clean.name, node.value)
3899 field := g.sum_field_name(qv)
3900 if g.variant_references_sum(qv, clean.name) {
3901 g.write('(*')
3902 if expr_type.is_pointer() {
3903 g.gen_expr(expr_id)
3904 g.write('->${field})')
3905 } else {
3906 g.gen_expr(expr_id)
3907 g.write('.${field})')
3908 }
3909 } else {
3910 if expr_type.is_pointer() {
3911 g.gen_expr(expr_id)
3912 g.write('->${field}')
3913 } else {
3914 g.gen_expr(expr_id)
3915 g.write('.${field}')
3916 }
3917 }
3918 } else {
3919 g.gen_expr(expr_id)
3920 }
3921 }
3922 .sizeof_expr {
3923 g.write('sizeof(${g.sizeof_target(node.value)})')
3924 }
3925 .offsetof_expr {
3926 ct := g.type_name_c_type(node.value)
3927 g.write('offsetof(${ct}, ${c_name(node.typ)})')
3928 }
3929 .assoc {
3930 g.gen_assoc_expr(node)
3931 }
3932 .empty {
3933 g.write('0')
3934 }
3935 else {}
3936 }
3937}
3938
3939fn (mut g FlatGen) gen_string_infix_fallback(node flat.Node, lhs_id flat.NodeId, rhs_id flat.NodeId) bool {
3940 match node.op {
3941 .plus {
3942 g.write('string__plus(')
3943 g.gen_expr_as_string(lhs_id)
3944 g.write(', ')
3945 g.gen_expr_as_string(rhs_id)
3946 g.write(')')
3947 }
3948 .eq {
3949 g.write('string__eq(')
3950 g.gen_expr_as_string(lhs_id)
3951 g.write(', ')
3952 g.gen_expr_as_string(rhs_id)
3953 g.write(')')
3954 }
3955 .ne {
3956 g.write('!string__eq(')
3957 g.gen_expr_as_string(lhs_id)
3958 g.write(', ')
3959 g.gen_expr_as_string(rhs_id)
3960 g.write(')')
3961 }
3962 .lt {
3963 g.write('string__lt(')
3964 g.gen_expr_as_string(lhs_id)
3965 g.write(', ')
3966 g.gen_expr_as_string(rhs_id)
3967 g.write(')')
3968 }
3969 .gt {
3970 g.write('string__lt(')
3971 g.gen_expr_as_string(rhs_id)
3972 g.write(', ')
3973 g.gen_expr_as_string(lhs_id)
3974 g.write(')')
3975 }
3976 .le {
3977 g.write('!string__lt(')
3978 g.gen_expr_as_string(rhs_id)
3979 g.write(', ')
3980 g.gen_expr_as_string(lhs_id)
3981 g.write(')')
3982 }
3983 .ge {
3984 g.write('!string__lt(')
3985 g.gen_expr_as_string(lhs_id)
3986 g.write(', ')
3987 g.gen_expr_as_string(rhs_id)
3988 g.write(')')
3989 }
3990 else {
3991 return false
3992 }
3993 }
3994
3995 return true
3996}
3997
3998fn (mut g FlatGen) gen_array_infix_eq(node flat.Node, lhs_id flat.NodeId, rhs_id flat.NodeId, lhs_type types.Type, rhs_type types.Type) bool {
3999 if node.op !in [.eq, .ne] {
4000 return false
4001 }
4002 if lhs_type is types.Pointer || rhs_type is types.Pointer {
4003 return false
4004 }
4005 lhs_arr := array_like_type(types.unwrap_pointer(lhs_type)) or { return false }
4006 rhs_arr := array_like_type(types.unwrap_pointer(rhs_type)) or { return false }
4007 elem_type := if lhs_arr.elem_type.name() != 'unknown' {
4008 lhs_arr.elem_type
4009 } else {
4010 rhs_arr.elem_type
4011 }
4012 if node.op == .ne {
4013 g.write('!')
4014 }
4015 if elem_type is types.String {
4016 g.write('array_eq_string(')
4017 } else {
4018 g.write('array_eq_raw(')
4019 }
4020 g.gen_array_value_arg(lhs_id, lhs_type)
4021 g.write(', ')
4022 g.gen_array_value_arg(rhs_id, rhs_type)
4023 if elem_type !is types.String {
4024 g.write(', sizeof(${g.tc.c_type(elem_type)})')
4025 }
4026 g.write(')')
4027 return true
4028}
4029
4030fn (mut g FlatGen) gen_array_value_arg(id flat.NodeId, typ types.Type) {
4031 if typ is types.Pointer {
4032 g.write('*')
4033 }
4034 g.gen_expr(id)
4035}
4036
4037fn array_membership_fn_name(elem_type types.Type, fixed bool) string {
4038 prefix := if fixed { 'fixed_array_contains_' } else { 'array_contains_' }
4039 elem_name := elem_type.name()
4040 suffix := match elem_name {
4041 'string' { 'string' }
4042 'u8', 'byte' { 'u8' }
4043 else { 'int' }
4044 }
4045
4046 return prefix + suffix
4047}
4048
4049fn (g &FlatGen) is_module_qualified_enum(base flat.Node) bool {
4050 if base.kind != .selector || base.children_count == 0 {
4051 return false
4052 }
4053 inner_base := g.a.child_node(&base, 0)
4054 if inner_base.kind != .ident || !g.has_import_alias(inner_base.value) {
4055 return false
4056 }
4057 mod := g.import_alias_module(inner_base.value) or { inner_base.value }
4058 short_mod := if mod.contains('.') { mod.all_after_last('.') } else { mod }
4059 qname := '${short_mod}.${base.value}'
4060 return qname in g.tc.enum_names || base.value in g.tc.enum_names
4061}
4062
4063fn (mut g FlatGen) preamble() {
4064 g.writeln('typedef signed char i8;')
4065 g.writeln('typedef short i16;')
4066 g.writeln('typedef int i32;')
4067 g.writeln('typedef long long i64;')
4068 g.writeln('typedef unsigned char u8;')
4069 g.writeln('typedef unsigned char byte;')
4070 g.writeln('typedef unsigned short u16;')
4071 g.writeln('typedef unsigned int u32;')
4072 g.writeln('typedef unsigned long long u64;')
4073 g.writeln('#ifdef _MSC_VER')
4074 g.writeln('#ifdef _WIN64')
4075 g.writeln('typedef unsigned __int64 size_t;')
4076 g.writeln('typedef __int64 ptrdiff_t;')
4077 g.writeln('typedef unsigned __int64 uintptr_t;')
4078 g.writeln('typedef __int64 intptr_t;')
4079 g.writeln('#else')
4080 g.writeln('typedef unsigned int size_t;')
4081 g.writeln('typedef int ptrdiff_t;')
4082 g.writeln('typedef unsigned int uintptr_t;')
4083 g.writeln('typedef int intptr_t;')
4084 g.writeln('#endif')
4085 g.writeln('#else')
4086 g.writeln('typedef __SIZE_TYPE__ size_t;')
4087 g.writeln('typedef __PTRDIFF_TYPE__ ptrdiff_t;')
4088 g.writeln('typedef __UINTPTR_TYPE__ uintptr_t;')
4089 g.writeln('typedef __INTPTR_TYPE__ intptr_t;')
4090 g.writeln('#endif')
4091 g.writeln('#if !defined(_TIME_T) && !defined(_TIME_T_DEFINED) && !defined(__time_t_defined) && !defined(_BSD_TIME_T_DEFINED_) && !defined(_TIME_T_DECLARED)')
4092 g.writeln('typedef long long time_t;')
4093 g.writeln('#endif')
4094 g.writeln('#ifndef __bool_true_false_are_defined')
4095 g.writeln('#ifdef _MSC_VER')
4096 g.writeln('typedef unsigned char bool;')
4097 g.writeln('#else')
4098 g.writeln('typedef _Bool bool;')
4099 g.writeln('#endif')
4100 g.writeln('#define __bool_true_false_are_defined 1')
4101 g.writeln('#endif')
4102 g.writeln('typedef void* voidptr;')
4103 g.writeln('typedef int int_literal;')
4104 g.writeln('typedef double float_literal;')
4105 g.writeln('struct sync__Channel;')
4106 g.writeln('typedef struct sync__Channel* chan;')
4107 g.writeln('#ifndef true')
4108 g.writeln('#define true 1')
4109 g.writeln('#endif')
4110 g.writeln('#ifndef false')
4111 g.writeln('#define false 0')
4112 g.writeln('#endif')
4113 g.headerless_libc_preamble()
4114 g.write_arch_macros()
4115 g.writeln('')
4116 if !g.has_builtins {
4117 g.writeln('typedef struct {')
4118 g.writeln('\tchar* str;')
4119 g.writeln('\tint len;')
4120 g.writeln('\tint is_lit;')
4121 g.writeln('} string;')
4122 g.writeln('')
4123 }
4124 g.writeln('#define elem_size element_size')
4125 g.writeln('#define c_name types__c_name')
4126 if g.has_builtins {
4127 return
4128 }
4129 g.writeln('typedef struct Array { void* data; int len; int cap; int elem_size; } Array;')
4130 g.writeln('')
4131}
4132
4133fn (mut g FlatGen) c99_feature_test_macros() {
4134 if !g.c99_mode {
4135 return
4136 }
4137 g.writeln('#if defined(__linux__) && !defined(_GNU_SOURCE)')
4138 g.writeln('#define _GNU_SOURCE')
4139 g.writeln('#endif')
4140 g.writeln('#if defined(__linux__) && !defined(_POSIX_C_SOURCE)')
4141 g.writeln('#define _POSIX_C_SOURCE 200809L')
4142 g.writeln('#endif')
4143}
4144
4145fn (mut g FlatGen) headerless_libc_preamble() {
4146 g.collect_preserved_c_fns(c_headerless_libc_declared_fns)
4147 g.writeln('#ifndef NULL')
4148 g.writeln('#define NULL ((void*)0)')
4149 g.writeln('#endif')
4150 g.writeln('#ifndef offsetof')
4151 g.writeln('#if defined(_MSC_VER) && !defined(__clang__)')
4152 g.writeln('#define offsetof(type, member) ((size_t)&(((type*)0)->member))')
4153 g.writeln('#else')
4154 g.writeln('#define offsetof(type, member) __builtin_offsetof(type, member)')
4155 g.writeln('#endif')
4156 g.writeln('#endif')
4157 g.writeln('#ifndef UINTPTR_MAX')
4158 g.writeln('#if defined(__LP64__) || defined(_WIN64)')
4159 g.writeln('#define UINTPTR_MAX 18446744073709551615ULL')
4160 g.writeln('#else')
4161 g.writeln('#define UINTPTR_MAX 4294967295U')
4162 g.writeln('#endif')
4163 g.writeln('#endif')
4164 g.writeln('#ifndef EOF')
4165 g.writeln('#define EOF (-1)')
4166 g.writeln('#endif')
4167 g.writeln('#ifndef RAND_MAX')
4168 g.writeln('#define RAND_MAX 2147483647')
4169 g.writeln('#endif')
4170 g.writeln('#ifndef FLT_EPSILON')
4171 g.writeln('#define FLT_EPSILON 1.19209290e-7F')
4172 g.writeln('#endif')
4173 g.writeln('#ifndef DBL_EPSILON')
4174 g.writeln('#define DBL_EPSILON 2.2204460492503131e-16')
4175 g.writeln('#endif')
4176 g.writeln('#ifndef FLT_MAX')
4177 g.writeln('#ifdef __FLT_MAX__')
4178 g.writeln('#define FLT_MAX __FLT_MAX__')
4179 g.writeln('#else')
4180 g.writeln('#define FLT_MAX 3.4028234663852886e+38F')
4181 g.writeln('#endif')
4182 g.writeln('#endif')
4183 g.writeln('#ifndef DBL_MAX')
4184 g.writeln('#ifdef __DBL_MAX__')
4185 g.writeln('#define DBL_MAX __DBL_MAX__')
4186 g.writeln('#else')
4187 g.writeln('#define DBL_MAX 1.7976931348623158e+308')
4188 g.writeln('#endif')
4189 g.writeln('#endif')
4190 g.writeln('#ifndef SEEK_SET')
4191 g.writeln('#define SEEK_SET 0')
4192 g.writeln('#endif')
4193 g.writeln('#ifndef SEEK_CUR')
4194 g.writeln('#define SEEK_CUR 1')
4195 g.writeln('#endif')
4196 g.writeln('#ifndef SEEK_END')
4197 g.writeln('#define SEEK_END 2')
4198 g.writeln('#endif')
4199 g.writeln('#ifndef _IOFBF')
4200 g.writeln('#define _IOFBF 0')
4201 g.writeln('#endif')
4202 g.writeln('#ifndef _IOLBF')
4203 g.writeln('#define _IOLBF 1')
4204 g.writeln('#endif')
4205 g.writeln('#ifndef _IONBF')
4206 g.writeln('#define _IONBF 2')
4207 g.writeln('#endif')
4208 g.headerless_windows_sdk_types()
4209 g.writeln('#if !defined(__FILE_defined) && !defined(_FILE_DEFINED) && !defined(_FILEDEFED) && !defined(__DEFINED_FILE) && !defined(_FILE_DECLARED) && !defined(__FILE_DECLARED)')
4210 g.writeln('typedef struct FILE FILE;')
4211 g.writeln('#endif')
4212 g.writeln('typedef struct DIR DIR;')
4213 g.writeln('#if !defined(_SSIZE_T) && !defined(_SSIZE_T_DEFINED) && !defined(__ssize_t_defined) && !defined(_SSIZE_T_DECLARED)')
4214 g.writeln('typedef intptr_t ssize_t;')
4215 g.writeln('#endif')
4216 g.writeln('extern char** environ;')
4217 g.writeln('char* getenv(const char* name);')
4218 g.writeln('int setenv(const char* name, const char* value, int overwrite);')
4219 g.writeln('void abort(void);')
4220 g.writeln('void* memset(void* s, int c, size_t n);')
4221 g.writeln('void* memcpy(void* dest, const void* src, size_t n);')
4222 g.writeln('void* memmove(void* dest, const void* src, size_t n);')
4223 g.writeln('int memcmp(const void* s1, const void* s2, size_t n);')
4224 g.writeln('size_t strlen(const char* s);')
4225 g.writeln('int strcmp(const char* s1, const char* s2);')
4226 g.writeln('int strncmp(const char* s1, const char* s2, size_t n);')
4227 g.writeln('char* strncpy(char* dest, const char* src, size_t n);')
4228 g.writeln('double floor(double x);')
4229 g.writeln('double ceil(double x);')
4230 g.writeln('float floorf(float x);')
4231 g.writeln('float ceilf(float x);')
4232 g.writeln('double sqrt(double x);')
4233 g.writeln('double pow(double x, double y);')
4234 g.writeln('double ldexp(double x, int exp);')
4235 g.writeln('double fmod(double x, double y);')
4236 g.writeln('double cos(double x);')
4237 g.writeln('double acos(double x);')
4238 g.writeln('double fabs(double x);')
4239 g.writeln('#ifndef _WIN32')
4240 g.writeln('int open(const char* path, int flags, ...);')
4241 g.writeln('ssize_t read(int fd, void* buf, size_t count);')
4242 g.writeln('int fork(void);')
4243 g.writeln('int dup2(int oldfd, int newfd);')
4244 g.writeln('int execlp(const char* file, const char* arg, ...);')
4245 g.writeln('int execvp(const char* file, char* const argv[]);')
4246 g.writeln('void _exit(int status);')
4247 g.writeln('#endif')
4248 g.writeln('int access(const char* path, int mode);')
4249 g.writeln('char* realpath(const char* path, char* resolved_path);')
4250 g.writeln('char* strrchr(const char* s, int c);')
4251 g.writeln('char* strstr(const char* haystack, const char* needle);')
4252 g.writeln('int snprintf(char* str, size_t size, const char* format, ...);')
4253 g.writeln('int fcntl(int fd, int cmd, ...);')
4254 g.writeln('int pipe(int* pipefds);')
4255 g.writeln('int close(int fd);')
4256 g.writeln('void* signal(int sig, void* handler);')
4257 g.writeln('int atexit(void (*f)(void));')
4258 g.writeln('#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__)')
4259 g.writeln('extern FILE* __stdinp;')
4260 g.writeln('extern FILE* __stdoutp;')
4261 g.writeln('extern FILE* __stderrp;')
4262 g.writeln('#define stdin __stdinp')
4263 g.writeln('#define stdout __stdoutp')
4264 g.writeln('#define stderr __stderrp')
4265 g.writeln('int* __error(void);')
4266 g.writeln('#define errno (*__error())')
4267 g.writeln('#elif defined(__OpenBSD__)')
4268 g.writeln('struct __sFstub { long _stub; };')
4269 g.writeln('extern struct __sFstub __stdin[];')
4270 g.writeln('extern struct __sFstub __stdout[];')
4271 g.writeln('extern struct __sFstub __stderr[];')
4272 g.writeln('#define stdin ((FILE*)__stdin)')
4273 g.writeln('#define stdout ((FILE*)__stdout)')
4274 g.writeln('#define stderr ((FILE*)__stderr)')
4275 g.writeln('extern int errno;')
4276 g.writeln('#elif defined(__NetBSD__)')
4277 g.writeln('#if defined(__LP64__) || defined(_LP64)')
4278 g.writeln('struct __netbsd_FILE_stub { unsigned char _opaque[152]; };')
4279 g.writeln('#else')
4280 g.writeln('struct __netbsd_FILE_stub { unsigned char _opaque[88]; };')
4281 g.writeln('#endif')
4282 g.writeln('extern struct __netbsd_FILE_stub __sF[];')
4283 g.writeln('#define stdin ((FILE*)&__sF[0])')
4284 g.writeln('#define stdout ((FILE*)&__sF[1])')
4285 g.writeln('#define stderr ((FILE*)&__sF[2])')
4286 g.writeln('extern int errno;')
4287 g.writeln('#elif defined(__ANDROID__)')
4288 g.writeln('extern FILE* stdin;')
4289 g.writeln('extern FILE* stdout;')
4290 g.writeln('extern FILE* stderr;')
4291 g.writeln('int* __errno(void);')
4292 g.writeln('#define errno (*__errno())')
4293 g.writeln('#elif defined(__linux__)')
4294 g.writeln('extern FILE* stdin;')
4295 g.writeln('extern FILE* stdout;')
4296 g.writeln('extern FILE* stderr;')
4297 g.writeln('int* __errno_location(void);')
4298 g.writeln('#define errno (*__errno_location())')
4299 g.writeln('#elif defined(_WIN32)')
4300 g.writeln('extern FILE* stdin;')
4301 g.writeln('extern FILE* stdout;')
4302 g.writeln('extern FILE* stderr;')
4303 g.writeln('int* _errno(void);')
4304 g.writeln('#define errno (*_errno())')
4305 g.writeln('#else')
4306 g.writeln('extern FILE* stdin;')
4307 g.writeln('extern FILE* stdout;')
4308 g.writeln('extern FILE* stderr;')
4309 g.writeln('extern int errno;')
4310 g.writeln('#endif')
4311 g.writeln('typedef int pid_t;')
4312 g.writeln('#if !defined(_OFF_T) && !defined(_OFF_T_DEFINED) && !defined(__off_t_defined) && !defined(_BSD_OFF_T_DEFINED_) && !defined(_OFF_T_DECLARED)')
4313 g.writeln('typedef long long off_t;')
4314 g.writeln('#endif')
4315 g.writeln('typedef void* pthread_t;')
4316 g.writeln('typedef union { unsigned char _opaque[64]; long long _align; } pthread_attr_t;')
4317 g.writeln('typedef union { unsigned char _opaque[128]; long long _align; } pthread_mutex_t;')
4318 g.writeln('typedef union { unsigned char _opaque[128]; long long _align; } pthread_cond_t;')
4319 g.writeln('typedef union { unsigned char _opaque[256]; long long _align; } pthread_rwlock_t;')
4320 g.writeln('typedef union { unsigned char _opaque[64]; long long _align; } pthread_rwlockattr_t;')
4321 g.writeln('typedef union { unsigned char _opaque[64]; long long _align; } pthread_condattr_t;')
4322 g.writeln('typedef union { unsigned char _opaque[128]; long long _align; } sem_t;')
4323 g.writeln('typedef union { unsigned char _opaque[128]; long long _align; } sigset_t;')
4324 g.headerless_stdarg_decls()
4325 g.writeln('#ifndef PTHREAD_MUTEX_INITIALIZER')
4326 g.writeln('#ifdef __APPLE__')
4327 g.writeln('#define PTHREAD_MUTEX_INITIALIZER { ._opaque = { 0xa7, 0xab, 0xaa, 0x32 } }')
4328 g.writeln('#else')
4329 g.writeln('#define PTHREAD_MUTEX_INITIALIZER { 0 }')
4330 g.writeln('#endif')
4331 g.writeln('#endif')
4332 g.writeln('int pthread_mutex_init(void* mutex, void* attr);')
4333 g.writeln('int pthread_mutex_lock(void* mutex);')
4334 g.writeln('int pthread_mutex_unlock(void* mutex);')
4335 g.writeln('int pthread_mutex_destroy(void* mutex);')
4336 g.writeln('typedef struct SRWLOCK { void* Ptr; } SRWLOCK;')
4337 g.writeln('typedef struct CONDITION_VARIABLE { void* Ptr; } CONDITION_VARIABLE;')
4338 g.writeln('typedef void* atomic_uintptr_t;')
4339 g.writeln('#if !defined(__cplusplus) && !defined(_WCHAR_T) && !defined(_WCHAR_T_DEFINED) && !defined(__WCHAR_T) && !defined(__wchar_t_defined) && !defined(_BSD_WCHAR_T_DEFINED_) && !defined(_WCHAR_T_DECLARED)')
4340 g.writeln('#ifdef __WCHAR_TYPE__')
4341 g.writeln('typedef __WCHAR_TYPE__ wchar_t;')
4342 g.writeln('#elif defined(_WIN32)')
4343 g.writeln('typedef unsigned short wchar_t;')
4344 g.writeln('#else')
4345 g.writeln('typedef unsigned int wchar_t;')
4346 g.writeln('#endif')
4347 g.writeln('#endif')
4348 g.writeln('#ifndef FD_SET')
4349 g.writeln('#ifndef FD_SETSIZE')
4350 g.writeln('#define FD_SETSIZE 1024')
4351 g.writeln('#endif')
4352 g.headerless_fd_set_struct()
4353 g.writeln('#endif')
4354 g.headerless_windows_console_structs()
4355 g.headerless_winsize_struct()
4356 g.headerless_addrinfo_struct()
4357 g.headerless_sockaddr_structs()
4358 g.headerless_epoll_structs()
4359 g.headerless_kevent_struct()
4360 g.headerless_dirent_struct()
4361 g.headerless_statvfs_struct()
4362 g.headerless_timeval_struct()
4363 g.headerless_rusage_struct()
4364 g.headerless_timespec_struct()
4365 g.headerless_utsname_struct()
4366 g.headerless_stat_struct()
4367 g.headerless_tm_struct()
4368 g.headerless_termios_struct()
4369 g.headerless_platform_constants()
4370}
4371
4372const c_headerless_libc_declared_fns = [
4373 'getenv',
4374 'setenv',
4375 'abort',
4376 'memset',
4377 'memcpy',
4378 'memmove',
4379 'memcmp',
4380 'strlen',
4381 'strcmp',
4382 'strncmp',
4383 'strncpy',
4384 'floor',
4385 'ceil',
4386 'floorf',
4387 'ceilf',
4388 'sqrt',
4389 'pow',
4390 'ldexp',
4391 'fmod',
4392 'cos',
4393 'acos',
4394 'fabs',
4395 'open',
4396 'read',
4397 'fork',
4398 'dup2',
4399 'execlp',
4400 'execvp',
4401 '_exit',
4402 'access',
4403 'realpath',
4404 'strrchr',
4405 'strstr',
4406 'snprintf',
4407 'fcntl',
4408 'pipe',
4409 'close',
4410 'signal',
4411 'atexit',
4412 '__error',
4413 '__errno',
4414 '__errno_location',
4415 '_errno',
4416 'pthread_mutex_init',
4417 'pthread_mutex_lock',
4418 'pthread_mutex_unlock',
4419 'pthread_mutex_destroy',
4420]
4421
4422fn (mut g FlatGen) headerless_windows_sdk_types() {
4423 g.writeln('#ifndef WINAPI')
4424 g.writeln('#if defined(_WIN32) && (defined(__i386__) || defined(_M_IX86))')
4425 g.writeln('#define WINAPI __stdcall')
4426 g.writeln('#else')
4427 g.writeln('#define WINAPI')
4428 g.writeln('#endif')
4429 g.writeln('#endif')
4430 g.writeln('#ifdef _WIN32')
4431 g.writeln('#if !defined(_WINDEF_) && !defined(_MINWINDEF_)')
4432 g.writeln('typedef unsigned long DWORD;')
4433 g.writeln('typedef int BOOL;')
4434 g.writeln('typedef void* HANDLE;')
4435 g.writeln('#endif')
4436 g.writeln('#if !defined(_SECURITY_ATTRIBUTES_DEFINED) && !defined(_SECURITY_ATTRIBUTES)')
4437 g.writeln('#define _SECURITY_ATTRIBUTES_DEFINED')
4438 g.writeln('typedef struct SECURITY_ATTRIBUTES { DWORD nLength; void* lpSecurityDescriptor; BOOL bInheritHandle; } SECURITY_ATTRIBUTES;')
4439 g.writeln('#endif')
4440 g.writeln('#if !defined(_OVERLAPPED_) && !defined(_OVERLAPPED_DECLARED)')
4441 g.writeln('#define _OVERLAPPED_DECLARED')
4442 g.writeln('typedef struct OVERLAPPED { uintptr_t Internal; uintptr_t InternalHigh; union { struct { DWORD Offset; DWORD OffsetHigh; }; void* Pointer; }; HANDLE hEvent; } OVERLAPPED;')
4443 g.writeln('#endif')
4444 g.writeln('#endif')
4445}
4446
4447fn (mut g FlatGen) headerless_stdarg_decls() {
4448 g.writeln('#ifndef va_start')
4449 g.writeln('#if defined(_MSC_VER) && !defined(__clang__)')
4450 g.writeln('typedef char* va_list;')
4451 g.writeln('#define __V_VA_ALIGN(type) ((sizeof(type) + sizeof(void*) - 1) & ~(sizeof(void*) - 1))')
4452 g.writeln('#define va_start(ap, last) ((void)((ap) = (va_list)&(last) + __V_VA_ALIGN(last)))')
4453 g.writeln('#define va_arg(ap, type) (*(type*)(((ap) += __V_VA_ALIGN(type)) - __V_VA_ALIGN(type)))')
4454 g.writeln('#define va_end(ap) ((void)((ap) = (va_list)0))')
4455 g.writeln('#define va_copy(dst, src) ((void)((dst) = (src)))')
4456 g.writeln('#else')
4457 g.writeln('typedef __builtin_va_list va_list;')
4458 g.writeln('#define va_start(ap, last) __builtin_va_start(ap, last)')
4459 g.writeln('#define va_arg(ap, type) __builtin_va_arg(ap, type)')
4460 g.writeln('#define va_end(ap) __builtin_va_end(ap)')
4461 g.writeln('#define va_copy(dst, src) __builtin_va_copy(dst, src)')
4462 g.writeln('#endif')
4463 g.writeln('#endif')
4464}
4465
4466fn (mut g FlatGen) headerless_fd_set_struct() {
4467 g.writeln('#ifdef _WIN32')
4468 g.writeln('typedef uintptr_t SOCKET;')
4469 g.writeln('struct fd_set { unsigned int fd_count; SOCKET fd_array[FD_SETSIZE]; };')
4470 g.writeln('typedef struct fd_set fd_set;')
4471 g.writeln('static inline void v_fd_zero(fd_set* set) { set->fd_count = 0; }')
4472 g.writeln('static inline void v_fd_set(SOCKET fd, fd_set* set) { for (unsigned int i = 0; i < set->fd_count; i++) { if (set->fd_array[i] == fd) { return; } } if (set->fd_count < FD_SETSIZE) { set->fd_array[set->fd_count++] = fd; } }')
4473 g.writeln('static inline int v_fd_isset(SOCKET fd, fd_set* set) { for (unsigned int i = 0; i < set->fd_count; i++) { if (set->fd_array[i] == fd) { return 1; } } return 0; }')
4474 g.writeln('#define FD_ZERO(set) v_fd_zero(set)')
4475 g.writeln('#define FD_SET(fd, set) v_fd_set((SOCKET)(fd), set)')
4476 g.writeln('#define FD_ISSET(fd, set) v_fd_isset((SOCKET)(fd), set)')
4477 g.writeln('#elif defined(__APPLE__)')
4478 g.writeln('#define __V_FD_BITS 32')
4479 g.writeln('struct fd_set { unsigned int fds_bits[FD_SETSIZE / __V_FD_BITS]; };')
4480 g.writeln('typedef struct fd_set fd_set;')
4481 g.writeln('#define FD_ZERO(set) memset((set), 0, sizeof(*(set)))')
4482 g.writeln('#define FD_SET(fd, set) ((set)->fds_bits[(fd) / __V_FD_BITS] |= (1U << ((fd) % __V_FD_BITS)))')
4483 g.writeln('#define FD_ISSET(fd, set) (((set)->fds_bits[(fd) / __V_FD_BITS] & (1U << ((fd) % __V_FD_BITS))) != 0)')
4484 g.writeln('#else')
4485 g.writeln('#define __V_FD_BITS (8 * (int)sizeof(unsigned long))')
4486 g.writeln('struct fd_set { unsigned long fds_bits[FD_SETSIZE / __V_FD_BITS]; };')
4487 g.writeln('typedef struct fd_set fd_set;')
4488 g.writeln('#define FD_ZERO(set) memset((set), 0, sizeof(*(set)))')
4489 g.writeln('#define FD_SET(fd, set) ((set)->fds_bits[(fd) / __V_FD_BITS] |= (1UL << ((fd) % __V_FD_BITS)))')
4490 g.writeln('#define FD_ISSET(fd, set) (((set)->fds_bits[(fd) / __V_FD_BITS] & (1UL << ((fd) % __V_FD_BITS))) != 0)')
4491 g.writeln('#endif')
4492}
4493
4494fn (mut g FlatGen) headerless_windows_console_structs() {
4495 g.writeln('#if defined(_WIN32)')
4496 g.writeln('typedef struct COORD { i16 X; i16 Y; } COORD;')
4497 g.writeln('typedef struct SMALL_RECT { u16 Left; u16 Top; u16 Right; u16 Bottom; } SMALL_RECT;')
4498 g.writeln('typedef union uChar { u16 UnicodeChar; u8 AsciiChar; } uChar;')
4499 g.writeln('typedef struct KEY_EVENT_RECORD { int bKeyDown; u16 wRepeatCount; u16 wVirtualKeyCode; u16 wVirtualScanCode; uChar uChar; u32 dwControlKeyState; } KEY_EVENT_RECORD;')
4500 g.writeln('typedef struct MOUSE_EVENT_RECORD { COORD dwMousePosition; u32 dwButtonState; u32 dwControlKeyState; u32 dwEventFlags; } MOUSE_EVENT_RECORD;')
4501 g.writeln('typedef struct WINDOW_BUFFER_SIZE_RECORD { COORD dwSize; } WINDOW_BUFFER_SIZE_RECORD;')
4502 g.writeln('typedef struct MENU_EVENT_RECORD { u32 dwCommandId; } MENU_EVENT_RECORD;')
4503 g.writeln('typedef struct FOCUS_EVENT_RECORD { int bSetFocus; } FOCUS_EVENT_RECORD;')
4504 g.writeln('typedef union Event { KEY_EVENT_RECORD KeyEvent; MOUSE_EVENT_RECORD MouseEvent; WINDOW_BUFFER_SIZE_RECORD WindowBufferSizeEvent; MENU_EVENT_RECORD MenuEvent; FOCUS_EVENT_RECORD FocusEvent; } Event;')
4505 g.writeln('typedef struct INPUT_RECORD { u16 EventType; Event Event; } INPUT_RECORD;')
4506 g.writeln('typedef struct CONSOLE_SCREEN_BUFFER_INFO { COORD dwSize; COORD dwCursorPosition; u16 wAttributes; SMALL_RECT srWindow; COORD dwMaximumWindowSize; } CONSOLE_SCREEN_BUFFER_INFO;')
4507 g.writeln('typedef struct CHAR_INFO { uChar Char; u16 Attributes; } CHAR_INFO;')
4508 g.writeln('#endif')
4509}
4510
4511fn (mut g FlatGen) headerless_winsize_struct() {
4512 g.writeln('struct winsize { unsigned short ws_row; unsigned short ws_col; unsigned short ws_xpixel; unsigned short ws_ypixel; };')
4513}
4514
4515fn (mut g FlatGen) headerless_addrinfo_struct() {
4516 g.writeln('#if defined(_WIN32)')
4517 g.writeln('struct addrinfo { int ai_flags; int ai_family; int ai_socktype; int ai_protocol; size_t ai_addrlen; char* ai_canonname; void* ai_addr; struct addrinfo* ai_next; };')
4518 g.writeln('#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__)')
4519 g.writeln('struct addrinfo { int ai_flags; int ai_family; int ai_socktype; int ai_protocol; unsigned int ai_addrlen; char* ai_canonname; void* ai_addr; struct addrinfo* ai_next; };')
4520 g.writeln('#else')
4521 g.writeln('struct addrinfo { int ai_flags; int ai_family; int ai_socktype; int ai_protocol; unsigned int ai_addrlen; void* ai_addr; char* ai_canonname; struct addrinfo* ai_next; };')
4522 g.writeln('#endif')
4523 g.writeln('typedef struct addrinfo addrinfo;')
4524}
4525
4526fn (mut g FlatGen) headerless_sockaddr_structs() {
4527 g.writeln('#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__)')
4528 g.writeln('struct sockaddr { u8 sa_len; u8 sa_family; char sa_data[14]; };')
4529 g.writeln('struct sockaddr_in { u8 sin_len; u8 sin_family; u16 sin_port; u32 sin_addr; char sin_zero[8]; };')
4530 g.writeln('struct sockaddr_in6 { u8 sin6_len; u8 sin6_family; u16 sin6_port; u32 sin6_flowinfo; u8 sin6_addr[16]; u32 sin6_scope_id; };')
4531 g.writeln('struct sockaddr_un { u8 sun_len; u8 sun_family; char sun_path[104]; };')
4532 g.writeln('#else')
4533 g.writeln('struct sockaddr { u16 sa_family; char sa_data[14]; };')
4534 g.writeln('struct sockaddr_in { u16 sin_family; u16 sin_port; u32 sin_addr; char sin_zero[8]; };')
4535 g.writeln('struct sockaddr_in6 { u16 sin6_family; u16 sin6_port; u32 sin6_flowinfo; u8 sin6_addr[16]; u32 sin6_scope_id; };')
4536 g.writeln('struct sockaddr_un { u16 sun_family; char sun_path[108]; };')
4537 g.writeln('#endif')
4538}
4539
4540fn (mut g FlatGen) headerless_epoll_structs() {
4541 g.writeln('#if defined(__linux__) || defined(__ANDROID__)')
4542 g.writeln('typedef union epoll_data { void* ptr; int fd; u32 u32; u64 u64; } epoll_data_t;')
4543 g.writeln('struct epoll_event { u32 events; epoll_data_t data; } __attribute__((packed));')
4544 g.writeln('#endif')
4545}
4546
4547fn (mut g FlatGen) headerless_kevent_struct() {
4548 g.writeln('#if defined(__NetBSD__)')
4549 g.writeln('struct kevent { uintptr_t ident; u32 filter; u32 flags; u32 fflags; i64 data; void* udata; u64 ext[4]; };')
4550 g.writeln('#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)')
4551 g.writeln('struct kevent { uintptr_t ident; i16 filter; u16 flags; u32 fflags; intptr_t data; void* udata; };')
4552 g.writeln('#endif')
4553}
4554
4555fn (mut g FlatGen) headerless_dirent_struct() {
4556 g.writeln('#if defined(__APPLE__)')
4557 g.writeln('struct dirent { u64 d_ino; u64 d_seekoff; u16 d_reclen; u16 d_namlen; u8 d_type; char d_name[1024]; };')
4558 g.writeln('#elif defined(__FreeBSD__)')
4559 g.writeln('struct dirent { u64 d_ino; i64 d_seekoff; u16 d_reclen; u8 d_type; u8 __pad0; u16 d_namlen; u16 __pad1; char d_name[256]; };')
4560 g.writeln('#elif defined(__OpenBSD__)')
4561 g.writeln('struct dirent { u64 d_ino; i64 d_seekoff; u16 d_reclen; u8 d_type; u8 d_namlen; u8 __d_padding[4]; char d_name[256]; };')
4562 g.writeln('#elif defined(__NetBSD__)')
4563 g.writeln('struct dirent { u64 d_ino; u16 d_reclen; u16 d_namlen; u8 d_type; char d_name[512]; };')
4564 g.writeln('#elif defined(__DragonFly__)')
4565 g.writeln('struct dirent { u64 d_ino; u16 d_namlen; u8 d_type; u8 __unused1; u32 __unused2; char d_name[256]; };')
4566 g.writeln('#elif defined(__linux__) && (defined(__i386__) || defined(__arm__))')
4567 g.writeln('struct dirent { unsigned long d_ino; long d_off; unsigned short d_reclen; unsigned char d_type; char d_name[256]; };')
4568 g.writeln('#else')
4569 g.writeln('struct dirent { u64 d_ino; i64 d_off; unsigned short d_reclen; unsigned char d_type; char d_name[256]; };')
4570 g.writeln('#endif')
4571}
4572
4573fn (mut g FlatGen) headerless_statvfs_struct() {
4574 g.writeln('#ifdef __NetBSD__')
4575 g.writeln('struct statvfs { unsigned long f_flag; unsigned long f_bsize; unsigned long f_frsize; unsigned long f_iosize; u64 f_blocks; u64 f_bfree; u64 f_bavail; u64 f_bresvd; u64 f_files; u64 f_ffree; u64 f_favail; u64 f_fresvd; u64 f_syncreads; u64 f_syncwrites; u64 f_asyncreads; u64 f_asyncwrites; struct { i32 __fsid_val[2]; } f_fsidx; unsigned long f_fsid; unsigned long f_namemax; u32 f_owner; u64 f_spare[4]; char f_fstypename[32]; char f_mntonname[1024]; char f_mntfromname[1024]; char f_mntfromlabel[1024]; };')
4576 g.writeln('#else')
4577 g.writeln('struct statvfs { unsigned long f_bsize; unsigned long f_frsize; unsigned long f_blocks; unsigned long f_bfree; unsigned long f_bavail; unsigned long f_files; unsigned long f_ffree; unsigned long f_favail; unsigned long f_fsid; unsigned long f_flag; unsigned long f_namemax; int __f_spare[6]; };')
4578 g.writeln('#endif')
4579}
4580
4581fn (mut g FlatGen) headerless_timeval_struct() {
4582 g.writeln('#ifdef _WIN32')
4583 g.writeln('struct timeval { long tv_sec; long tv_usec; };')
4584 g.writeln('#else')
4585 g.writeln('struct timeval { long tv_sec; long tv_usec; };')
4586 g.writeln('#endif')
4587 g.writeln('typedef struct timeval timeval;')
4588}
4589
4590fn (mut g FlatGen) headerless_rusage_struct() {
4591 g.writeln('struct rusage { struct timeval ru_utime; struct timeval ru_stime; long ru_maxrss; long ru_ixrss; long ru_idrss; long ru_isrss; long ru_minflt; long ru_majflt; long ru_nswap; long ru_inblock; long ru_oublock; long ru_msgsnd; long ru_msgrcv; long ru_nsignals; long ru_nvcsw; long ru_nivcsw; };')
4592}
4593
4594fn (mut g FlatGen) headerless_timespec_struct() {
4595 g.writeln('#if !defined(_STRUCT_TIMESPEC) && !defined(_TIMESPEC_DEFINED) && !defined(_TIMESPEC_DECLARED) && !defined(__timespec_defined)')
4596 g.writeln('#ifdef _WIN32')
4597 g.writeln('struct timespec { i64 tv_sec; long tv_nsec; };')
4598 g.writeln('#else')
4599 g.writeln('struct timespec { long tv_sec; long tv_nsec; };')
4600 g.writeln('#endif')
4601 g.writeln('#endif')
4602 g.writeln('typedef struct timespec timespec;')
4603}
4604
4605fn (mut g FlatGen) headerless_tm_struct() {
4606 g.writeln('#ifdef _WIN32')
4607 g.writeln('struct tm { int tm_sec; int tm_min; int tm_hour; int tm_mday; int tm_mon; int tm_year; int tm_wday; int tm_yday; int tm_isdst; };')
4608 g.writeln('#else')
4609 g.writeln('struct tm { int tm_sec; int tm_min; int tm_hour; int tm_mday; int tm_mon; int tm_year; int tm_wday; int tm_yday; int tm_isdst; long tm_gmtoff; const char* tm_zone; };')
4610 g.writeln('#endif')
4611 g.writeln('typedef struct tm tm;')
4612}
4613
4614fn (mut g FlatGen) headerless_termios_struct() {
4615 g.writeln('#if defined(__APPLE__)')
4616 g.writeln('struct termios { size_t c_iflag; size_t c_oflag; size_t c_cflag; size_t c_lflag; u8 c_cc[20]; size_t c_ispeed; size_t c_ospeed; };')
4617 g.writeln('#elif defined(__linux__) || defined(__ANDROID__)')
4618 g.writeln('struct termios { int c_iflag; int c_oflag; int c_cflag; int c_lflag; u8 c_line; u8 c_cc[32]; int c_ispeed; int c_ospeed; };')
4619 g.writeln('#elif defined(__sun)')
4620 g.writeln('struct termios { int c_iflag; int c_oflag; int c_cflag; int c_lflag; u8 c_cc[20]; };')
4621 g.writeln('#elif defined(__QNX__) || defined(__QNXNTO__)')
4622 g.writeln('struct termios { int c_iflag; int c_oflag; int c_cflag; int c_lflag; u8 c_cc[20]; u32 reserved[3]; int c_ispeed; int c_ospeed; };')
4623 g.writeln('#else')
4624 g.writeln('struct termios { int c_iflag; int c_oflag; int c_cflag; int c_lflag; u8 c_cc[20]; int c_ispeed; int c_ospeed; };')
4625 g.writeln('#endif')
4626 g.writeln('typedef struct termios termios;')
4627}
4628
4629fn (mut g FlatGen) headerless_utsname_struct() {
4630 g.writeln('#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)')
4631 g.writeln('struct utsname { char sysname[256]; char nodename[256]; char release[256]; char version[256]; char machine[256]; };')
4632 g.writeln('#else')
4633 g.writeln('struct utsname { char sysname[65]; char nodename[65]; char release[65]; char version[65]; char machine[65]; char domainname[65]; };')
4634 g.writeln('#endif')
4635}
4636
4637fn (mut g FlatGen) headerless_stat_struct() {
4638 g.writeln('#ifdef __APPLE__')
4639 g.writeln('struct stat { int st_dev; unsigned short st_mode; unsigned short st_nlink; u64 st_ino; u32 st_uid; u32 st_gid; int st_rdev; i64 st_atime; i64 st_atimensec; i64 st_mtime; i64 st_mtimensec; i64 st_ctime; i64 st_ctimensec; i64 st_birthtime; i64 st_birthtimensec; i64 st_size; i64 st_blocks; int st_blksize; u32 st_flags; u32 st_gen; int st_lspare; i64 st_qspare[2]; };')
4640 g.writeln('#elif defined(__linux__)')
4641 g.headerless_linux_stat_struct()
4642 g.writeln('#elif defined(_WIN32)')
4643 g.writeln('struct stat { u64 st_dev; u64 st_ino; u32 st_mode; u64 st_nlink; u32 st_uid; u32 st_gid; u64 st_rdev; u64 st_size; int st_atime; int st_mtime; int st_ctime; };')
4644 g.writeln('#elif defined(__FreeBSD__)')
4645 g.headerless_freebsd_stat_struct()
4646 g.writeln('#elif defined(__OpenBSD__)')
4647 g.headerless_openbsd_stat_struct()
4648 g.writeln('#elif defined(__NetBSD__)')
4649 g.headerless_netbsd_stat_struct()
4650 g.writeln('#elif defined(__DragonFly__)')
4651 g.headerless_dragonfly_stat_struct()
4652 g.writeln('#elif defined(__sun)')
4653 g.headerless_solaris_stat_struct()
4654 g.writeln('#elif defined(__QNX__) || defined(__QNXNTO__)')
4655 g.headerless_qnx_stat_struct()
4656 g.writeln('#else')
4657 g.writeln('#error unsupported headerless Unix struct stat layout for this platform')
4658 g.writeln('#endif')
4659}
4660
4661fn (mut g FlatGen) headerless_freebsd_stat_struct() {
4662 g.writeln('#if defined(__i386__)')
4663 g.writeln('struct stat { u64 st_dev; u64 st_ino; u64 st_nlink; u16 st_mode; i16 st_bsdflags; u32 st_uid; u32 st_gid; i32 st_padding1; u64 st_rdev; i32 st_atim_ext; i64 st_atime; long st_atimensec; i32 st_mtim_ext; i64 st_mtime; long st_mtimensec; i32 st_ctim_ext; i64 st_ctime; long st_ctimensec; i32 st_btim_ext; i64 st_birthtime; long st_birthtimensec; i64 st_size; i64 st_blocks; i32 st_blksize; u32 st_flags; u64 st_gen; u64 st_filerev; u64 st_spare[9]; };')
4664 g.writeln('#else')
4665 g.writeln('struct stat { u64 st_dev; u64 st_ino; u64 st_nlink; u16 st_mode; i16 st_bsdflags; u32 st_uid; u32 st_gid; i32 st_padding1; u64 st_rdev; i64 st_atime; long st_atimensec; i64 st_mtime; long st_mtimensec; i64 st_ctime; long st_ctimensec; i64 st_birthtime; long st_birthtimensec; i64 st_size; i64 st_blocks; i32 st_blksize; u32 st_flags; u64 st_gen; u64 st_filerev; u64 st_spare[9]; };')
4666 g.writeln('#endif')
4667}
4668
4669fn (mut g FlatGen) headerless_openbsd_stat_struct() {
4670 g.writeln('struct stat { u32 st_mode; i32 st_dev; u64 st_ino; u32 st_nlink; u32 st_uid; u32 st_gid; i32 st_rdev; i64 st_atime; long st_atimensec; i64 st_mtime; long st_mtimensec; i64 st_ctime; long st_ctimensec; i64 __st_birthtime; long __st_birthtimensec; i64 st_size; i64 st_blocks; i32 st_blksize; u32 st_flags; u32 st_gen; };')
4671}
4672
4673fn (mut g FlatGen) headerless_netbsd_stat_struct() {
4674 g.writeln('struct stat { u64 st_dev; u32 st_mode; u64 st_ino; u32 st_nlink; u32 st_uid; u32 st_gid; u64 st_rdev; i64 st_atime; long st_atimensec; i64 st_mtime; long st_mtimensec; i64 st_ctime; long st_ctimensec; i64 st_birthtime; long st_birthtimensec; i64 st_size; i64 st_blocks; i32 st_blksize; u32 st_flags; u32 st_gen; u32 st_spare[2]; };')
4675}
4676
4677fn (mut g FlatGen) headerless_dragonfly_stat_struct() {
4678 g.writeln('struct stat { u64 st_ino; u32 st_nlink; u32 st_dev; u16 st_mode; u16 st_padding1; u32 st_uid; u32 st_gid; u32 st_rdev; i64 st_atime; long st_atimensec; i64 st_mtime; long st_mtimensec; i64 st_ctime; long st_ctimensec; i64 st_size; i64 st_blocks; u32 __old_st_blksize; u32 st_flags; u32 st_gen; i32 st_lspare; i64 st_blksize; i64 st_qspare2; };')
4679}
4680
4681fn (mut g FlatGen) headerless_solaris_stat_struct() {
4682 g.writeln('#if defined(_LP64)')
4683 g.writeln('struct stat { u64 st_dev; u64 st_ino; u32 st_mode; u32 st_nlink; u32 st_uid; u32 st_gid; u64 st_rdev; i64 st_size; long st_atime; long st_atimensec; long st_mtime; long st_mtimensec; long st_ctime; long st_ctimensec; long st_blksize; i64 st_blocks; char st_fstype[16]; };')
4684 g.writeln('#else')
4685 g.writeln('struct stat { unsigned long st_dev; long st_pad1[3]; unsigned long st_ino; u32 st_mode; u32 st_nlink; u32 st_uid; u32 st_gid; unsigned long st_rdev; long st_pad2[2]; long st_size; long st_pad3; long st_atime; long st_atimensec; long st_mtime; long st_mtimensec; long st_ctime; long st_ctimensec; long st_blksize; long st_blocks; char st_fstype[16]; long st_pad4[8]; };')
4686 g.writeln('#endif')
4687}
4688
4689fn (mut g FlatGen) headerless_qnx_stat_struct() {
4690 g.writeln('#if _FILE_OFFSET_BITS - 0 == 64')
4691 g.writeln('struct stat { u64 st_ino; i64 st_size; u64 st_dev; u64 st_rdev; u32 st_uid; u32 st_gid; long st_mtime; long st_atime; long st_ctime; u32 st_mode; u32 st_nlink; long st_blocksize; i32 st_nblocks; long st_blksize; i64 st_blocks; };')
4692 g.writeln('#elif defined(__BIGENDIAN__)')
4693 g.writeln('struct stat { unsigned long st_ino_hi; unsigned long st_ino; long st_size_hi; long st_size; unsigned long st_dev; unsigned long st_rdev; u32 st_uid; u32 st_gid; long st_mtime; long st_atime; long st_ctime; u32 st_mode; u32 st_nlink; long st_blocksize; i32 st_nblocks; long st_blksize; long st_blocks_hi; long st_blocks; };')
4694 g.writeln('#else')
4695 g.writeln('struct stat { unsigned long st_ino; unsigned long st_ino_hi; long st_size; long st_size_hi; unsigned long st_dev; unsigned long st_rdev; u32 st_uid; u32 st_gid; long st_mtime; long st_atime; long st_ctime; u32 st_mode; u32 st_nlink; long st_blocksize; i32 st_nblocks; long st_blksize; long st_blocks; long st_blocks_hi; };')
4696 g.writeln('#endif')
4697}
4698
4699fn (mut g FlatGen) headerless_linux_stat_struct() {
4700 g.writeln('#if defined(__x86_64__) && !defined(__ILP32__)')
4701 g.writeln('struct stat { u64 st_dev; u64 st_ino; u64 st_nlink; u32 st_mode; u32 st_uid; u32 st_gid; int __pad0; u64 st_rdev; i64 st_size; i64 st_blksize; i64 st_blocks; i64 st_atime; i64 st_atimensec; i64 st_mtime; i64 st_mtimensec; i64 st_ctime; i64 st_ctimensec; i64 __glibc_reserved[3]; };')
4702 g.writeln('#elif defined(__aarch64__) || (defined(__riscv) && __riscv_xlen == 64) || defined(__loongarch_lp64)')
4703 g.writeln('struct stat { u64 st_dev; u64 st_ino; u32 st_mode; u32 st_nlink; u32 st_uid; u32 st_gid; u64 st_rdev; unsigned long __pad1; i64 st_size; int st_blksize; int __pad2; i64 st_blocks; i64 st_atime; i64 st_atimensec; i64 st_mtime; i64 st_mtimensec; i64 st_ctime; i64 st_ctimensec; unsigned int __glibc_reserved[2]; };')
4704 g.writeln('#elif defined(__i386__) || defined(__arm__)')
4705 g.writeln('struct stat { u64 st_dev; unsigned short __pad1; unsigned long st_ino; u32 st_mode; unsigned long st_nlink; u32 st_uid; u32 st_gid; u64 st_rdev; unsigned short __pad2; long st_size; long st_blksize; long st_blocks; long st_atime; unsigned long st_atimensec; long st_mtime; unsigned long st_mtimensec; long st_ctime; unsigned long st_ctimensec; unsigned long __glibc_reserved4; unsigned long __glibc_reserved5; };')
4706 g.writeln('#else')
4707 g.writeln('#error unsupported Linux struct stat layout for this architecture')
4708 g.writeln('#endif')
4709}
4710
4711fn (mut g FlatGen) headerless_platform_constants() {
4712 g.writeln('#define STDIN_FILENO 0')
4713 g.writeln('#define STDOUT_FILENO 1')
4714 g.writeln('#define STDERR_FILENO 2')
4715 g.writeln('#define F_OK 0')
4716 g.writeln('#define WEXITSTATUS(status) (((status) >> 8) & 0xff)')
4717 g.writeln('#define WTERMSIG(status) ((status) & 0x7f)')
4718 g.writeln('#define WIFEXITED(status) (WTERMSIG(status) == 0)')
4719 g.writeln('#define WIFSIGNALED(status) ((((status) & 0x7f) + 1) >= 2)')
4720 g.writeln('#define WNOHANG 1')
4721 g.writeln('#define LOCK_SH 1')
4722 g.writeln('#define LOCK_EX 2')
4723 g.writeln('#define LOCK_NB 4')
4724 g.writeln('#define LOCK_UN 8')
4725 g.writeln('#define ENOENT 2')
4726 g.writeln('#define RUSAGE_SELF 0')
4727 g.writeln('#ifdef __APPLE__')
4728 g.headerless_darwin_constants()
4729 g.writeln('#elif defined(_WIN32)')
4730 g.headerless_windows_constants()
4731 g.writeln('#elif defined(__FreeBSD__)')
4732 g.headerless_bsd_constants('0x00100000', '12', '13', '4', '47', '28', '0x00020000', '0x0800',
4733 true)
4734 g.writeln('#elif defined(__OpenBSD__)')
4735 g.headerless_bsd_constants('0x10000', '8', '9', '3', '28', '24', '0x0400', '', false)
4736 g.writeln('#elif defined(__NetBSD__)')
4737 g.headerless_bsd_constants('0x00400000', '8', '9', '3', '28', '24', '0x0400', '0x0800', false)
4738 g.writeln('#elif defined(__DragonFly__)')
4739 g.headerless_bsd_constants('0x00020000', '8', '9', '4', '47', '28', '0x0400', '0x0800', false)
4740 g.writeln('#elif defined(__sun)')
4741 g.headerless_solaris_constants()
4742 g.writeln('#elif defined(__QNX__) || defined(__QNXNTO__)')
4743 g.headerless_qnx_constants()
4744 g.writeln('#elif defined(__linux__) || defined(__ANDROID__)')
4745 g.headerless_linux_constants()
4746 g.writeln('#else')
4747 g.writeln('#error unsupported headerless C platform constants')
4748 g.writeln('#endif')
4749 g.headerless_signal_constants()
4750 g.headerless_ptrace_constants()
4751 g.headerless_sysctl_constants()
4752 g.writeln('#ifndef MSG_NOSIGNAL')
4753 g.writeln('#define MSG_NOSIGNAL 0')
4754 g.writeln('#endif')
4755 g.writeln('#ifndef SO_NOSIGPIPE')
4756 g.writeln('#define SO_NOSIGPIPE 0')
4757 g.writeln('#endif')
4758}
4759
4760fn (mut g FlatGen) headerless_signal_constants() {
4761 g.writeln('#define SIGKILL 9')
4762 g.writeln('#define SIGTERM 15')
4763 g.writeln('#define SIGPIPE 13')
4764 g.writeln('#define SIG_IGN ((void*)1)')
4765 g.writeln('#if defined(__linux__) || defined(__ANDROID__)')
4766 g.writeln('#define SIGSTOP 19')
4767 g.writeln('#define SIGCONT 18')
4768 g.writeln('#define SIG_BLOCK 0')
4769 g.writeln('#else')
4770 g.writeln('#define SIGSTOP 17')
4771 g.writeln('#define SIGCONT 19')
4772 g.writeln('#define SIG_BLOCK 1')
4773 g.writeln('#endif')
4774}
4775
4776fn (mut g FlatGen) headerless_ptrace_constants() {
4777 g.writeln('#if defined(__linux__) || defined(__ANDROID__)')
4778 g.writeln('#define PTRACE_ATTACH 16')
4779 g.writeln('#define PTRACE_DETACH 17')
4780 g.writeln('#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__)')
4781 g.writeln('#define PT_TRACE_ME 0')
4782 g.writeln('#define PT_ATTACH 10')
4783 g.writeln('#define PT_DETACH 11')
4784 g.writeln('#endif')
4785}
4786
4787fn (mut g FlatGen) headerless_sysctl_constants() {
4788 g.writeln('#if defined(__FreeBSD__)')
4789 g.writeln('#define CTL_KERN 1')
4790 g.writeln('#define CTL_VM 2')
4791 g.writeln('#define KERN_PROC 14')
4792 g.writeln('#define KERN_PROC_PID 1')
4793 g.writeln('#define KERN_PROC_ARGS 7')
4794 g.writeln('#define KERN_PROC_PATHNAME 12')
4795 g.writeln('#define KERN_PROC_INC_THREAD 0x10')
4796 g.writeln('#elif defined(__OpenBSD__)')
4797 g.writeln('#define CTL_KERN 1')
4798 g.writeln('#define CTL_VM 2')
4799 g.writeln('#define KERN_PROC 66')
4800 g.writeln('#define KERN_PROC_PID 1')
4801 g.writeln('#define KERN_PROC_ARGS 55')
4802 g.writeln('#define KERN_PROC_ARGV 1')
4803 g.writeln('#define VM_UVMEXP 4')
4804 g.writeln('#endif')
4805}
4806
4807fn (mut g FlatGen) headerless_mmap_constants(map_anonymous string) {
4808 g.writeln('#define PROT_READ 0x1')
4809 g.writeln('#define PROT_WRITE 0x2')
4810 g.writeln('#define PROT_EXEC 0x4')
4811 g.writeln('#define MAP_PRIVATE 0x0002')
4812 g.writeln('#define MAP_ANONYMOUS ${map_anonymous}')
4813 g.writeln('#define MAP_ANON MAP_ANONYMOUS')
4814 g.writeln('#define MAP_FAILED ((void*)-1)')
4815}
4816
4817fn (mut g FlatGen) headerless_linux_syscall_constants() {
4818 g.writeln('#ifndef SYS_getrandom')
4819 g.writeln('#if defined(__x86_64__)')
4820 g.writeln('#define SYS_getrandom 318')
4821 g.writeln('#elif defined(__i386__)')
4822 g.writeln('#define SYS_getrandom 355')
4823 g.writeln('#elif defined(__arm__)')
4824 g.writeln('#define SYS_getrandom 384')
4825 g.writeln('#elif defined(__aarch64__) || (defined(__riscv) && __riscv_xlen == 64) || defined(__loongarch_lp64)')
4826 g.writeln('#define SYS_getrandom 278')
4827 g.writeln('#else')
4828 g.writeln('#define SYS_getrandom 278')
4829 g.writeln('#endif')
4830 g.writeln('#endif')
4831}
4832
4833fn (mut g FlatGen) headerless_linux_sysconf_constants() {
4834 g.writeln('#if defined(__ANDROID__)')
4835 g.writeln('#define _SC_PAGESIZE 0x0027')
4836 g.writeln('#define _SC_NPROCESSORS_ONLN 0x0061')
4837 g.writeln('#define _SC_PHYS_PAGES 0x0062')
4838 g.writeln('#define _SC_AVPHYS_PAGES 0x0063')
4839 g.writeln('#else')
4840 g.writeln('#define _SC_PAGESIZE 30')
4841 g.writeln('#define _SC_NPROCESSORS_ONLN 84')
4842 g.writeln('#define _SC_PHYS_PAGES 85')
4843 g.writeln('#define _SC_AVPHYS_PAGES 86')
4844 g.writeln('#endif')
4845}
4846
4847fn (mut g FlatGen) headerless_kqueue_common_constants() {
4848 g.writeln('#define EVFILT_READ (-1)')
4849 g.writeln('#define EVFILT_WRITE (-2)')
4850 g.writeln('#define EV_ADD 0x0001')
4851 g.writeln('#define EV_DELETE 0x0002')
4852 g.writeln('#define EV_ENABLE 0x0004')
4853 g.writeln('#define EV_DISABLE 0x0008')
4854 g.writeln('#define EV_ONESHOT 0x0010')
4855 g.writeln('#define EV_CLEAR 0x0020')
4856 g.writeln('#define EV_RECEIPT 0x0040')
4857 g.writeln('#define EV_DISPATCH 0x0080')
4858 g.writeln('#define EV_EOF 0x8000')
4859 g.writeln('#define EV_ERROR 0x4000')
4860 g.writeln('#define EV_SET(kevp, a, b, c, d, e, f) do { struct kevent* __kevp = (struct kevent*)(kevp); __kevp->ident = (uintptr_t)(a); __kevp->filter = (b); __kevp->flags = (c); __kevp->fflags = (d); __kevp->data = (intptr_t)(e); __kevp->udata = (void*)(f); } while (0)')
4861}
4862
4863fn (mut g FlatGen) headerless_darwin_kqueue_constants() {
4864 g.headerless_kqueue_common_constants()
4865 g.writeln('#define EVFILT_AIO (-3)')
4866 g.writeln('#define EVFILT_VNODE (-4)')
4867 g.writeln('#define EVFILT_PROC (-5)')
4868 g.writeln('#define EVFILT_SIGNAL (-6)')
4869 g.writeln('#define EVFILT_TIMER (-7)')
4870 g.writeln('#define EVFILT_MACHPORT (-8)')
4871 g.writeln('#define EVFILT_FS (-9)')
4872 g.writeln('#define EVFILT_USER (-10)')
4873 g.writeln('#define EVFILT_VM (-12)')
4874 g.writeln('#define EVFILT_EXCEPT (-15)')
4875 g.writeln('#define EVFILT_SYSCOUNT 18')
4876 g.writeln('#define EV_UDATA_SPECIFIC 0x0100')
4877 g.writeln('#define EV_DISPATCH2 (EV_DISPATCH | EV_UDATA_SPECIFIC)')
4878 g.writeln('#define EV_VANISHED 0x0200')
4879 g.writeln('#define EV_SYSFLAGS 0xF000')
4880 g.writeln('#define EV_FLAG0 0x1000')
4881 g.writeln('#define EV_FLAG1 0x2000')
4882}
4883
4884fn (mut g FlatGen) headerless_darwin_constants() {
4885 g.writeln('#define O_RDONLY 0x0000')
4886 g.writeln('#define O_WRONLY 0x0001')
4887 g.writeln('#define O_RDWR 0x0002')
4888 g.writeln('#define O_NONBLOCK 0x0004')
4889 g.writeln('#define O_APPEND 0x0008')
4890 g.writeln('#define O_SYNC 0x0080')
4891 g.writeln('#define O_CREAT 0x0200')
4892 g.writeln('#define O_TRUNC 0x0400')
4893 g.writeln('#define O_EXCL 0x0800')
4894 g.writeln('#define O_NOCTTY 0x20000')
4895 g.writeln('#define O_CLOEXEC 0x01000000')
4896 g.writeln('#define F_GETFD 1')
4897 g.writeln('#define F_SETFD 2')
4898 g.writeln('#define F_GETFL 3')
4899 g.writeln('#define F_SETFL 4')
4900 g.writeln('#define F_SETLK 8')
4901 g.writeln('#define F_SETLKW 9')
4902 g.writeln('#define FD_CLOEXEC 1')
4903 g.writeln('#define F_RDLCK 1')
4904 g.writeln('#define F_UNLCK 2')
4905 g.writeln('#define F_WRLCK 3')
4906 g.writeln('#define EACCES 13')
4907 g.writeln('#define EFAULT 14')
4908 g.writeln('#define EINTR 4')
4909 g.writeln('#define EINVAL 22')
4910 g.writeln('#define EAGAIN 35')
4911 g.writeln('#define EWOULDBLOCK 35')
4912 g.writeln('#define EINPROGRESS 36')
4913 g.writeln('#define EBUSY 16')
4914 g.writeln('#define EDEADLK 11')
4915 g.writeln('#define ETIMEDOUT 60')
4916 g.writeln('#define EPROTONOSUPPORT 43')
4917 g.writeln('#define EAFNOSUPPORT 47')
4918 g.writeln('#define EADDRNOTAVAIL 49')
4919 g.writeln('#define EAI_SYSTEM 11')
4920 g.writeln('#define CLOCK_REALTIME 0')
4921 g.writeln('#define CLOCK_MONOTONIC 6')
4922 g.writeln('#define _SC_PAGESIZE 29')
4923 g.headerless_mmap_constants('0x1000')
4924 g.headerless_darwin_kqueue_constants()
4925 g.writeln('#define FIONREAD 0x4004667f')
4926 g.writeln('#define TIOCGWINSZ 0x40087468')
4927 g.writeln('#define TCSANOW 0')
4928 g.writeln('#define TCSADRAIN 1')
4929 g.writeln('#define TCSAFLUSH 2')
4930 g.writeln('#define IGNBRK 1')
4931 g.writeln('#define BRKINT 2')
4932 g.writeln('#define PARMRK 8')
4933 g.writeln('#define INPCK 16')
4934 g.writeln('#define ISTRIP 32')
4935 g.writeln('#define ICRNL 256')
4936 g.writeln('#define IXON 512')
4937 g.writeln('#define OPOST 1')
4938 g.writeln('#define CS8 768')
4939 g.writeln('#define ISIG 128')
4940 g.writeln('#define ICANON 256')
4941 g.writeln('#define ECHO 8')
4942 g.writeln('#define IEXTEN 1024')
4943 g.writeln('#define TOSTOP 4194304')
4944 g.writeln('#define VMIN 16')
4945 g.writeln('#define VTIME 17')
4946 g.writeln('#define PTHREAD_PROCESS_PRIVATE 2')
4947 g.writeln('#define PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP 0')
4948 g.writeln('#define S_IFMT 0170000')
4949 g.writeln('#define S_IFIFO 0010000')
4950 g.writeln('#define S_IFCHR 0020000')
4951 g.writeln('#define S_IFDIR 0040000')
4952 g.writeln('#define S_IFBLK 0060000')
4953 g.writeln('#define S_IFREG 0100000')
4954 g.writeln('#define S_IFLNK 0120000')
4955 g.writeln('#define S_IFSOCK 0140000')
4956 g.writeln('#define S_IRUSR 0000400')
4957 g.writeln('#define S_IWUSR 0000200')
4958 g.writeln('#define S_IXUSR 0000100')
4959 g.writeln('#define S_IRGRP 0000040')
4960 g.writeln('#define S_IWGRP 0000020')
4961 g.writeln('#define S_IXGRP 0000010')
4962 g.writeln('#define S_IROTH 0000004')
4963 g.writeln('#define S_IWOTH 0000002')
4964 g.writeln('#define S_IXOTH 0000001')
4965 g.headerless_darwin_net_constants()
4966 g.writeln('#define SIG_ERR ((void (*)(int))-1)')
4967 g.writeln('struct flock { off_t l_start; off_t l_len; pid_t l_pid; short l_type; short l_whence; };')
4968}
4969
4970fn (mut g FlatGen) headerless_bsd_constants(o_cloexec string, f_setlk string, f_setlkw string, clock_monotonic string, sc_pagesize string, af_inet6 string, msg_nosignal string, so_nosigpipe string, flock_sysid bool) {
4971 g.writeln('#define O_RDONLY 0x0000')
4972 g.writeln('#define O_WRONLY 0x0001')
4973 g.writeln('#define O_RDWR 0x0002')
4974 g.writeln('#define O_NONBLOCK 0x0004')
4975 g.writeln('#define O_APPEND 0x0008')
4976 g.writeln('#define O_SYNC 0x0080')
4977 g.writeln('#define O_CREAT 0x0200')
4978 g.writeln('#define O_TRUNC 0x0400')
4979 g.writeln('#define O_EXCL 0x0800')
4980 g.writeln('#define O_NOCTTY 0x8000')
4981 g.writeln('#define O_CLOEXEC ${o_cloexec}')
4982 g.writeln('#define F_GETFD 1')
4983 g.writeln('#define F_SETFD 2')
4984 g.writeln('#define F_GETFL 3')
4985 g.writeln('#define F_SETFL 4')
4986 g.writeln('#define F_SETLK ${f_setlk}')
4987 g.writeln('#define F_SETLKW ${f_setlkw}')
4988 g.writeln('#define FD_CLOEXEC 1')
4989 g.writeln('#define F_RDLCK 1')
4990 g.writeln('#define F_UNLCK 2')
4991 g.writeln('#define F_WRLCK 3')
4992 g.writeln('#define EACCES 13')
4993 g.writeln('#define EFAULT 14')
4994 g.writeln('#define EINTR 4')
4995 g.writeln('#define EINVAL 22')
4996 g.writeln('#define EAGAIN 35')
4997 g.writeln('#define EWOULDBLOCK 35')
4998 g.writeln('#define EINPROGRESS 36')
4999 g.writeln('#define EBUSY 16')
5000 g.writeln('#define EDEADLK 11')
5001 g.writeln('#define ETIMEDOUT 60')
5002 g.writeln('#define EPROTONOSUPPORT 43')
5003 g.writeln('#define EAFNOSUPPORT 47')
5004 g.writeln('#define EADDRNOTAVAIL 49')
5005 g.writeln('#define EAI_SYSTEM 11')
5006 g.writeln('#define CLOCK_REALTIME 0')
5007 g.writeln('#define CLOCK_MONOTONIC ${clock_monotonic}')
5008 g.writeln('#define _SC_PAGESIZE ${sc_pagesize}')
5009 g.headerless_mmap_constants('0x1000')
5010 g.headerless_kqueue_common_constants()
5011 g.writeln('#define FIONREAD 0x4004667f')
5012 g.writeln('#define TIOCGWINSZ 0x40087468')
5013 g.writeln('#define TCSANOW 0')
5014 g.writeln('#define TCSADRAIN 1')
5015 g.writeln('#define TCSAFLUSH 2')
5016 g.writeln('#define IGNBRK 1')
5017 g.writeln('#define BRKINT 2')
5018 g.writeln('#define PARMRK 8')
5019 g.writeln('#define INPCK 16')
5020 g.writeln('#define ISTRIP 32')
5021 g.writeln('#define ICRNL 256')
5022 g.writeln('#define IXON 512')
5023 g.writeln('#define OPOST 1')
5024 g.writeln('#define CS8 768')
5025 g.writeln('#define ISIG 128')
5026 g.writeln('#define ICANON 256')
5027 g.writeln('#define ECHO 8')
5028 g.writeln('#define IEXTEN 1024')
5029 g.writeln('#define TOSTOP 4194304')
5030 g.writeln('#define VMIN 16')
5031 g.writeln('#define VTIME 17')
5032 g.writeln('#define PTHREAD_PROCESS_PRIVATE 0')
5033 g.writeln('#define PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP 0')
5034 g.writeln('#define S_IFMT 0170000')
5035 g.writeln('#define S_IFIFO 0010000')
5036 g.writeln('#define S_IFCHR 0020000')
5037 g.writeln('#define S_IFDIR 0040000')
5038 g.writeln('#define S_IFBLK 0060000')
5039 g.writeln('#define S_IFREG 0100000')
5040 g.writeln('#define S_IFLNK 0120000')
5041 g.writeln('#define S_IFSOCK 0140000')
5042 g.writeln('#define S_IRUSR 0000400')
5043 g.writeln('#define S_IWUSR 0000200')
5044 g.writeln('#define S_IXUSR 0000100')
5045 g.writeln('#define S_IRGRP 0000040')
5046 g.writeln('#define S_IWGRP 0000020')
5047 g.writeln('#define S_IXGRP 0000010')
5048 g.writeln('#define S_IROTH 0000004')
5049 g.writeln('#define S_IWOTH 0000002')
5050 g.writeln('#define S_IXOTH 0000001')
5051 g.headerless_bsd_net_constants(af_inet6, msg_nosignal, so_nosigpipe)
5052 g.writeln('#define SIG_ERR ((void (*)(int))-1)')
5053 if flock_sysid {
5054 g.writeln('struct flock { off_t l_start; off_t l_len; pid_t l_pid; short l_type; short l_whence; int l_sysid; };')
5055 } else {
5056 g.writeln('struct flock { off_t l_start; off_t l_len; pid_t l_pid; short l_type; short l_whence; };')
5057 }
5058}
5059
5060fn (mut g FlatGen) headerless_solaris_constants() {
5061 g.writeln('#define O_RDONLY 0')
5062 g.writeln('#define O_WRONLY 1')
5063 g.writeln('#define O_RDWR 2')
5064 g.writeln('#define O_APPEND 0x08')
5065 g.writeln('#define O_SYNC 0x10')
5066 g.writeln('#define O_NONBLOCK 0x80')
5067 g.writeln('#define O_CREAT 0x100')
5068 g.writeln('#define O_TRUNC 0x200')
5069 g.writeln('#define O_EXCL 0x400')
5070 g.writeln('#define O_NOCTTY 0x800')
5071 g.writeln('#define O_CLOEXEC 0x800000')
5072 g.writeln('#define F_GETFD 1')
5073 g.writeln('#define F_SETFD 2')
5074 g.writeln('#define F_GETFL 3')
5075 g.writeln('#define F_SETFL 4')
5076 g.writeln('#define F_SETLK 6')
5077 g.writeln('#define F_SETLKW 7')
5078 g.writeln('#define FD_CLOEXEC 1')
5079 g.writeln('#define F_RDLCK 1')
5080 g.writeln('#define F_WRLCK 2')
5081 g.writeln('#define F_UNLCK 3')
5082 g.writeln('#define EINTR 4')
5083 g.writeln('#define EINVAL 22')
5084 g.writeln('#define EAGAIN 11')
5085 g.writeln('#define EWOULDBLOCK EAGAIN')
5086 g.writeln('#define EINPROGRESS 150')
5087 g.writeln('#define EBUSY 16')
5088 g.writeln('#define EDEADLK 45')
5089 g.writeln('#define ETIMEDOUT 145')
5090 g.writeln('#define EPROTONOSUPPORT 120')
5091 g.writeln('#define EAFNOSUPPORT 124')
5092 g.writeln('#define EADDRNOTAVAIL 126')
5093 g.writeln('#define EAI_SYSTEM 11')
5094 g.writeln('#define CLOCK_REALTIME 0')
5095 g.writeln('#define CLOCK_MONOTONIC 4')
5096 g.writeln('#define _SC_PAGESIZE 11')
5097 g.headerless_mmap_constants('0x100')
5098 g.writeln('#define FIONREAD 0x4004667f')
5099 g.writeln("#define TIOCGWINSZ (('T' << 8) | 104)")
5100 g.writeln("#define TCSANOW (('T' << 8) | 14)")
5101 g.writeln("#define TCSADRAIN (('T' << 8) | 15)")
5102 g.writeln("#define TCSAFLUSH (('T' << 8) | 16)")
5103 g.writeln('#define IGNBRK 0000001')
5104 g.writeln('#define BRKINT 0000002')
5105 g.writeln('#define PARMRK 0000010')
5106 g.writeln('#define INPCK 0000020')
5107 g.writeln('#define ISTRIP 0000040')
5108 g.writeln('#define ICRNL 0000400')
5109 g.writeln('#define IXON 0002000')
5110 g.writeln('#define OPOST 0000001')
5111 g.writeln('#define CS8 0000060')
5112 g.writeln('#define ISIG 0000001')
5113 g.writeln('#define ICANON 0000002')
5114 g.writeln('#define ECHO 0000010')
5115 g.writeln('#define IEXTEN 0100000')
5116 g.writeln('#define TOSTOP 0000400')
5117 g.writeln('#define VMIN 4')
5118 g.writeln('#define VTIME 5')
5119 g.writeln('#define PTHREAD_PROCESS_PRIVATE 0')
5120 g.writeln('#define PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP 0')
5121 g.writeln('#define S_IFMT 0170000')
5122 g.writeln('#define S_IFIFO 0010000')
5123 g.writeln('#define S_IFCHR 0020000')
5124 g.writeln('#define S_IFDIR 0040000')
5125 g.writeln('#define S_IFBLK 0060000')
5126 g.writeln('#define S_IFREG 0100000')
5127 g.writeln('#define S_IFLNK 0120000')
5128 g.writeln('#define S_IFSOCK 0140000')
5129 g.writeln('#define S_IRUSR 0000400')
5130 g.writeln('#define S_IWUSR 0000200')
5131 g.writeln('#define S_IXUSR 0000100')
5132 g.writeln('#define S_IRGRP 0000040')
5133 g.writeln('#define S_IWGRP 0000020')
5134 g.writeln('#define S_IXGRP 0000010')
5135 g.writeln('#define S_IROTH 0000004')
5136 g.writeln('#define S_IWOTH 0000002')
5137 g.writeln('#define S_IXOTH 0000001')
5138 g.headerless_solaris_net_constants()
5139 g.writeln('#define SIG_ERR ((void (*)(int))-1)')
5140 g.writeln('struct flock { short l_type; short l_whence; off_t l_start; off_t l_len; int l_sysid; pid_t l_pid; long l_pad[4]; };')
5141}
5142
5143fn (mut g FlatGen) headerless_qnx_constants() {
5144 g.writeln('#define O_RDONLY 000000')
5145 g.writeln('#define O_WRONLY 000001')
5146 g.writeln('#define O_RDWR 000002')
5147 g.writeln('#define O_APPEND 000010')
5148 g.writeln('#define O_SYNC 000040')
5149 g.writeln('#define O_NONBLOCK 000200')
5150 g.writeln('#define O_CREAT 000400')
5151 g.writeln('#define O_TRUNC 001000')
5152 g.writeln('#define O_EXCL 002000')
5153 g.writeln('#define O_NOCTTY 004000')
5154 g.writeln('#define O_CLOEXEC 020000')
5155 g.writeln('#define F_GETFD 1')
5156 g.writeln('#define F_SETFD 2')
5157 g.writeln('#define F_GETFL 3')
5158 g.writeln('#define F_SETFL 4')
5159 g.writeln('#define F_SETLK 6')
5160 g.writeln('#define F_SETLKW 7')
5161 g.writeln('#define FD_CLOEXEC 1')
5162 g.writeln('#define F_RDLCK 1')
5163 g.writeln('#define F_WRLCK 2')
5164 g.writeln('#define F_UNLCK 3')
5165 g.writeln('#define EINTR 4')
5166 g.writeln('#define EINVAL 22')
5167 g.writeln('#define EAGAIN 11')
5168 g.writeln('#define EWOULDBLOCK EAGAIN')
5169 g.writeln('#define EINPROGRESS 236')
5170 g.writeln('#define EBUSY 16')
5171 g.writeln('#define EDEADLK 45')
5172 g.writeln('#define ETIMEDOUT 260')
5173 g.writeln('#define EPROTONOSUPPORT 243')
5174 g.writeln('#define EAFNOSUPPORT 247')
5175 g.writeln('#define EADDRNOTAVAIL 249')
5176 g.writeln('#define EAI_SYSTEM 11')
5177 g.writeln('#define CLOCK_REALTIME 0')
5178 g.writeln('#define CLOCK_MONOTONIC 2')
5179 g.writeln('#define _SC_PAGESIZE 11')
5180 g.headerless_mmap_constants('0x00080000')
5181 g.writeln('#define FIONREAD 0x4004667f')
5182 g.writeln('#define TIOCGWINSZ 0x40087468')
5183 g.writeln('#define TCSANOW 0x0001')
5184 g.writeln('#define TCSADRAIN 0x0002')
5185 g.writeln('#define TCSAFLUSH 0x0004')
5186 g.writeln('#define IGNBRK 0x00000001')
5187 g.writeln('#define BRKINT 0x00000002')
5188 g.writeln('#define PARMRK 0x00000008')
5189 g.writeln('#define INPCK 0x00000010')
5190 g.writeln('#define ISTRIP 0x00000020')
5191 g.writeln('#define ICRNL 0x00000100')
5192 g.writeln('#define IXON 0x00000400')
5193 g.writeln('#define OPOST 0x00000001')
5194 g.writeln('#define CS8 0x30')
5195 g.writeln('#define ISIG 0x00000001')
5196 g.writeln('#define ICANON 0x00000002')
5197 g.writeln('#define ECHO 0x00000008')
5198 g.writeln('#define IEXTEN 0x00008000')
5199 g.writeln('#define TOSTOP 0x00000100')
5200 g.writeln('#define VMIN 16')
5201 g.writeln('#define VTIME 17')
5202 g.writeln('#define PTHREAD_PROCESS_PRIVATE 0')
5203 g.writeln('#define PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP 0')
5204 g.writeln('#define S_IFMT 0170000')
5205 g.writeln('#define S_IFIFO 0010000')
5206 g.writeln('#define S_IFCHR 0020000')
5207 g.writeln('#define S_IFDIR 0040000')
5208 g.writeln('#define S_IFBLK 0060000')
5209 g.writeln('#define S_IFREG 0100000')
5210 g.writeln('#define S_IFLNK 0120000')
5211 g.writeln('#define S_IFSOCK 0140000')
5212 g.writeln('#define S_IRUSR 0000400')
5213 g.writeln('#define S_IWUSR 0000200')
5214 g.writeln('#define S_IXUSR 0000100')
5215 g.writeln('#define S_IRGRP 0000040')
5216 g.writeln('#define S_IWGRP 0000020')
5217 g.writeln('#define S_IXGRP 0000010')
5218 g.writeln('#define S_IROTH 0000004')
5219 g.writeln('#define S_IWOTH 0000002')
5220 g.writeln('#define S_IXOTH 0000001')
5221 g.headerless_qnx_net_constants()
5222 g.writeln('#define SIG_ERR ((void (*)(int))-1)')
5223 g.writeln('struct flock { short l_type; short l_whence; int l_zero1; off_t l_start; off_t l_len; pid_t l_pid; unsigned int l_sysid; };')
5224}
5225
5226fn (mut g FlatGen) headerless_windows_constants() {
5227 g.writeln('#define O_RDONLY 0x0000')
5228 g.writeln('#define O_WRONLY 0x0001')
5229 g.writeln('#define O_RDWR 0x0002')
5230 g.writeln('#define O_APPEND 0x0008')
5231 g.writeln('#define O_CREAT 0x0100')
5232 g.writeln('#define O_TRUNC 0x0200')
5233 g.writeln('#define O_EXCL 0x0400')
5234 g.writeln('#define O_BINARY 0x8000')
5235 g.writeln('#define _O_BINARY 0x8000')
5236 g.writeln('#define F_GETFD 1')
5237 g.writeln('#define F_SETFD 2')
5238 g.writeln('#define F_GETFL 3')
5239 g.writeln('#define F_SETFL 4')
5240 g.writeln('#define FD_CLOEXEC 1')
5241 g.writeln('#define EINTR 4')
5242 g.writeln('#define EINVAL 22')
5243 g.writeln('#define EAGAIN 11')
5244 g.writeln('#define EWOULDBLOCK 11')
5245 g.writeln('#define EINPROGRESS 10036')
5246 g.writeln('#define EBUSY 16')
5247 g.writeln('#define EDEADLK 36')
5248 g.writeln('#define ETIMEDOUT 10060')
5249 g.writeln('#define EPROTONOSUPPORT 10043')
5250 g.writeln('#define EAFNOSUPPORT 10047')
5251 g.writeln('#define EADDRNOTAVAIL 10049')
5252 g.writeln('#define EAI_SYSTEM 11')
5253 g.writeln('#define CLOCK_REALTIME 0')
5254 g.writeln('#define CLOCK_MONOTONIC 1')
5255 g.writeln('#define _SC_PAGESIZE 30')
5256 g.writeln('#define FIONREAD 0x4004667f')
5257 g.writeln('#define FIONBIO 0x8004667eU')
5258 g.writeln('#define TCSANOW 0')
5259 g.writeln('#define TCSADRAIN 1')
5260 g.writeln('#define TCSAFLUSH 2')
5261 g.writeln('#define PTHREAD_PROCESS_PRIVATE 0')
5262 g.writeln('#define PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP 0')
5263 g.writeln('#define S_IFMT 0170000')
5264 g.writeln('#define S_IFIFO 0010000')
5265 g.writeln('#define S_IFCHR 0020000')
5266 g.writeln('#define S_IFDIR 0040000')
5267 g.writeln('#define S_IFBLK 0060000')
5268 g.writeln('#define S_IFREG 0100000')
5269 g.writeln('#define S_IFLNK 0120000')
5270 g.writeln('#define S_IFSOCK 0140000')
5271 g.writeln('#define S_IREAD 0000400')
5272 g.writeln('#define S_IWRITE 0000200')
5273 g.writeln('#define S_IEXEC 0000100')
5274 g.writeln('#define S_IRUSR 0000400')
5275 g.writeln('#define S_IWUSR 0000200')
5276 g.writeln('#define S_IXUSR 0000100')
5277 g.headerless_windows_net_constants()
5278 g.writeln('#define SIG_ERR ((void (*)(int))-1)')
5279 g.writeln('#define GENERIC_READ 0x80000000U')
5280 g.writeln('#define GENERIC_WRITE 0x40000000U')
5281 g.writeln('#define FILE_SHARE_READ 0x00000001U')
5282 g.writeln('#define FILE_SHARE_WRITE 0x00000002U')
5283 g.writeln('#define FILE_SHARE_DELETE 0x00000004U')
5284 g.writeln('#define OPEN_EXISTING 3')
5285 g.writeln('#define OPEN_ALWAYS 4')
5286 g.writeln('#define FILE_ATTRIBUTE_NORMAL 0x00000080U')
5287 g.writeln('#define FILE_ATTRIBUTE_DIRECTORY 0x00000010U')
5288 g.writeln('#define INVALID_FILE_ATTRIBUTES 0xffffffffU')
5289 g.writeln('#define LOCKFILE_FAIL_IMMEDIATELY 0x00000001U')
5290 g.writeln('#define LOCKFILE_EXCLUSIVE_LOCK 0x00000002U')
5291 g.writeln('#define MAXDWORD 0xffffffffU')
5292 g.writeln('#define MEM_COMMIT 0x00001000U')
5293 g.writeln('#define MEM_RESERVE 0x00002000U')
5294 g.writeln('#define PAGE_READWRITE 0x04U')
5295 g.writeln('#define PAGE_EXECUTE_READ 0x20U')
5296 g.writeln('#define TLS_OUT_OF_INDEXES 0xffffffffU')
5297 g.writeln('#define TRUE 1')
5298 g.writeln('#define FALSE 0')
5299 g.writeln('#define INFINITE 0xffffffffU')
5300 g.writeln('#define INVALID_HANDLE_VALUE ((void*)-1)')
5301 g.writeln('#define STD_INPUT_HANDLE 0xfffffff6U')
5302 g.writeln('#define STD_OUTPUT_HANDLE 0xfffffff5U')
5303 g.writeln('#define STD_ERROR_HANDLE 0xfffffff4U')
5304 g.writeln('#define ENABLE_PROCESSED_INPUT 0x0001')
5305 g.writeln('#define ENABLE_LINE_INPUT 0x0002')
5306 g.writeln('#define ENABLE_ECHO_INPUT 0x0004')
5307 g.writeln('#define ENABLE_WINDOW_INPUT 0x0008')
5308 g.writeln('#define ENABLE_MOUSE_INPUT 0x0010')
5309 g.writeln('#define ENABLE_EXTENDED_FLAGS 0x0080')
5310 g.writeln('#define STARTF_USESTDHANDLES 0x00000100U')
5311 g.writeln('#define CREATE_NEW_PROCESS_GROUP 0x00000200U')
5312 g.writeln('#define CREATE_UNICODE_ENVIRONMENT 0x00000400U')
5313 g.writeln('#define NORMAL_PRIORITY_CLASS 0x00000020U')
5314 g.writeln('#define CREATE_NO_WINDOW 0x08000000U')
5315 g.writeln('#define HANDLE_FLAG_INHERIT 0x00000001U')
5316 g.writeln('#define CTRL_BREAK_EVENT 1')
5317 g.writeln('#define STILL_ACTIVE 259')
5318 g.writeln('#define KEY_EVENT 0x0001')
5319 g.writeln('#define MOUSE_EVENT 0x0002')
5320 g.writeln('#define WINDOW_BUFFER_SIZE_EVENT 0x0004')
5321 g.writeln('#define MENU_EVENT 0x0008')
5322 g.writeln('#define FOCUS_EVENT 0x0010')
5323 g.writeln('#define MOUSE_MOVED 0x0001')
5324 g.writeln('#define DOUBLE_CLICK 0x0002')
5325 g.writeln('#define MOUSE_WHEELED 0x0004')
5326 g.writeln('#define VK_BACK 0x08')
5327 g.writeln('#define VK_RETURN 0x0d')
5328 g.writeln('#define VK_PRIOR 0x21')
5329 g.writeln('#define VK_NEXT 0x22')
5330 g.writeln('#define VK_END 0x23')
5331 g.writeln('#define VK_HOME 0x24')
5332 g.writeln('#define VK_LEFT 0x25')
5333 g.writeln('#define VK_UP 0x26')
5334 g.writeln('#define VK_RIGHT 0x27')
5335 g.writeln('#define VK_DOWN 0x28')
5336 g.writeln('#define VK_INSERT 0x2d')
5337 g.writeln('#define VK_DELETE 0x2e')
5338 g.writeln('#define ERROR_ACCESS_DENIED 5')
5339 g.writeln('#define ERROR_CLASS_ALREADY_EXISTS 1410')
5340 g.writeln('#define HWND_MESSAGE ((void*)-3)')
5341 g.writeln('#define MB_ERR_INVALID_CHARS 0x00000008U')
5342 g.writeln('#define GMEM_MOVEABLE 0x0002U')
5343 g.writeln('#define CF_UNICODETEXT 13')
5344}
5345
5346fn (mut g FlatGen) headerless_linux_constants() {
5347 g.writeln('#define O_RDONLY 0')
5348 g.writeln('#define O_WRONLY 1')
5349 g.writeln('#define O_RDWR 2')
5350 g.writeln('#define O_CREAT 0100')
5351 g.writeln('#define O_EXCL 0200')
5352 g.writeln('#define O_NOCTTY 0400')
5353 g.writeln('#define O_TRUNC 01000')
5354 g.writeln('#define O_APPEND 02000')
5355 g.writeln('#define O_NONBLOCK 04000')
5356 g.writeln('#define O_SYNC 04010000')
5357 g.writeln('#define O_CLOEXEC 02000000')
5358 g.writeln('#define F_GETFD 1')
5359 g.writeln('#define F_SETFD 2')
5360 g.writeln('#define F_GETFL 3')
5361 g.writeln('#define F_SETFL 4')
5362 g.writeln('#define F_SETLK 6')
5363 g.writeln('#define F_SETLKW 7')
5364 g.writeln('#define FD_CLOEXEC 1')
5365 g.writeln('#define F_RDLCK 0')
5366 g.writeln('#define F_WRLCK 1')
5367 g.writeln('#define F_UNLCK 2')
5368 g.writeln('#define EINTR 4')
5369 g.writeln('#define EIO 5')
5370 g.writeln('#define EBADF 9')
5371 g.writeln('#define EINVAL 22')
5372 g.writeln('#define EAGAIN 11')
5373 g.writeln('#define EWOULDBLOCK 11')
5374 g.writeln('#define ENOMEM 12')
5375 g.writeln('#define EFAULT 14')
5376 g.writeln('#define EINPROGRESS 115')
5377 g.writeln('#define ESPIPE 29')
5378 g.writeln('#define EBUSY 16')
5379 g.writeln('#define EDEADLK 35')
5380 g.writeln('#define ETIMEDOUT 110')
5381 g.writeln('#define EOVERFLOW 75')
5382 g.writeln('#define EPROTONOSUPPORT 93')
5383 g.writeln('#define EAFNOSUPPORT 97')
5384 g.writeln('#define EADDRNOTAVAIL 99')
5385 g.writeln('#define EAI_SYSTEM -11')
5386 g.writeln('#define CLOCK_REALTIME 0')
5387 g.writeln('#define CLOCK_MONOTONIC 1')
5388 g.headerless_linux_sysconf_constants()
5389 g.headerless_mmap_constants('0x20')
5390 g.headerless_linux_syscall_constants()
5391 g.writeln('#define FIONREAD 0x541b')
5392 g.writeln('#define TIOCGWINSZ 0x5413')
5393 g.writeln('#define EPOLLIN 0x001')
5394 g.writeln('#define EPOLLPRI 0x002')
5395 g.writeln('#define EPOLLOUT 0x004')
5396 g.writeln('#define EPOLLERR 0x008')
5397 g.writeln('#define EPOLLHUP 0x010')
5398 g.writeln('#define EPOLLRDHUP 0x2000')
5399 g.writeln('#define EPOLLEXCLUSIVE (1U << 28)')
5400 g.writeln('#define EPOLLWAKEUP (1U << 29)')
5401 g.writeln('#define EPOLLONESHOT (1U << 30)')
5402 g.writeln('#define EPOLLET (1U << 31)')
5403 g.writeln('#define EPOLL_CTL_ADD 1')
5404 g.writeln('#define EPOLL_CTL_DEL 2')
5405 g.writeln('#define EPOLL_CTL_MOD 3')
5406 g.writeln('#define TCSANOW 0')
5407 g.writeln('#define TCSADRAIN 1')
5408 g.writeln('#define TCSAFLUSH 2')
5409 g.writeln('#define IGNBRK 0000001')
5410 g.writeln('#define BRKINT 0000002')
5411 g.writeln('#define PARMRK 0000010')
5412 g.writeln('#define INPCK 0000020')
5413 g.writeln('#define ISTRIP 0000040')
5414 g.writeln('#define ICRNL 0000400')
5415 g.writeln('#define IXON 0002000')
5416 g.writeln('#define OPOST 0000001')
5417 g.writeln('#define CS8 0000060')
5418 g.writeln('#define ISIG 0000001')
5419 g.writeln('#define ICANON 0000002')
5420 g.writeln('#define ECHO 0000010')
5421 g.writeln('#define IEXTEN 0100000')
5422 g.writeln('#define TOSTOP 0000400')
5423 g.writeln('#define VMIN 6')
5424 g.writeln('#define VTIME 5')
5425 g.writeln('#define PTHREAD_PROCESS_PRIVATE 0')
5426 g.writeln('#define PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP 2')
5427 g.writeln('#define S_IFMT 00170000')
5428 g.writeln('#define S_IFIFO 0010000')
5429 g.writeln('#define S_IFCHR 0020000')
5430 g.writeln('#define S_IFDIR 0040000')
5431 g.writeln('#define S_IFBLK 0060000')
5432 g.writeln('#define S_IFREG 0100000')
5433 g.writeln('#define S_IFLNK 0120000')
5434 g.writeln('#define S_IFSOCK 0140000')
5435 g.writeln('#define S_IRUSR 0000400')
5436 g.writeln('#define S_IWUSR 0000200')
5437 g.writeln('#define S_IXUSR 0000100')
5438 g.writeln('#define S_IRGRP 0000040')
5439 g.writeln('#define S_IWGRP 0000020')
5440 g.writeln('#define S_IXGRP 0000010')
5441 g.writeln('#define S_IROTH 0000004')
5442 g.writeln('#define S_IWOTH 0000002')
5443 g.writeln('#define S_IXOTH 0000001')
5444 g.headerless_linux_net_constants()
5445 g.writeln('#define SIG_ERR ((void (*)(int))-1)')
5446 g.writeln('struct flock { short l_type; short l_whence; off_t l_start; off_t l_len; pid_t l_pid; };')
5447}
5448
5449fn (mut g FlatGen) headerless_darwin_net_constants() {
5450 g.writeln('#define AF_UNSPEC 0')
5451 g.writeln('#define AF_UNIX 1')
5452 g.writeln('#define AF_INET 2')
5453 g.writeln('#define AF_INET6 30')
5454 g.writeln('#define SOCK_STREAM 1')
5455 g.writeln('#define SOCK_DGRAM 2')
5456 g.writeln('#define SOCK_RAW 3')
5457 g.writeln('#define SOCK_SEQPACKET 5')
5458 g.writeln('#define IPPROTO_IP 0')
5459 g.writeln('#define IPPROTO_ICMP 1')
5460 g.writeln('#define IPPROTO_TCP 6')
5461 g.writeln('#define IPPROTO_UDP 17')
5462 g.writeln('#define IPPROTO_IPV6 41')
5463 g.writeln('#define IPPROTO_ICMPV6 58')
5464 g.writeln('#define IPPROTO_RAW 255')
5465 g.writeln('#define SOL_SOCKET 0xffff')
5466 g.writeln('#define SO_DEBUG 0x0001')
5467 g.writeln('#define SO_REUSEADDR 0x0004')
5468 g.writeln('#define SO_KEEPALIVE 0x0008')
5469 g.writeln('#define SO_DONTROUTE 0x0010')
5470 g.writeln('#define SO_BROADCAST 0x0020')
5471 g.writeln('#define SO_LINGER 0x0080')
5472 g.writeln('#define SO_OOBINLINE 0x0100')
5473 g.writeln('#define SO_SNDBUF 0x1001')
5474 g.writeln('#define SO_RCVBUF 0x1002')
5475 g.writeln('#define SO_SNDLOWAT 0x1003')
5476 g.writeln('#define SO_RCVLOWAT 0x1004')
5477 g.writeln('#define SO_SNDTIMEO 0x1005')
5478 g.writeln('#define SO_RCVTIMEO 0x1006')
5479 g.writeln('#define SO_ERROR 0x1007')
5480 g.writeln('#define SO_TYPE 0x1008')
5481 g.writeln('#define SO_NOSIGPIPE 0x1022')
5482 g.writeln('#define TCP_NODELAY 1')
5483 g.writeln('#define IP_HDRINCL 2')
5484 g.writeln('#define IP_MULTICAST_IF 9')
5485 g.writeln('#define IP_MULTICAST_TTL 10')
5486 g.writeln('#define IP_MULTICAST_LOOP 11')
5487 g.writeln('#define IP_ADD_MEMBERSHIP 12')
5488 g.writeln('#define IP_DROP_MEMBERSHIP 13')
5489 g.writeln('#define IPV6_MULTICAST_IF 9')
5490 g.writeln('#define IPV6_MULTICAST_HOPS 10')
5491 g.writeln('#define IPV6_MULTICAST_LOOP 11')
5492 g.writeln('#define IPV6_ADD_MEMBERSHIP 12')
5493 g.writeln('#define IPV6_JOIN_GROUP 12')
5494 g.writeln('#define IPV6_DROP_MEMBERSHIP 13')
5495 g.writeln('#define IPV6_LEAVE_GROUP 13')
5496 g.writeln('#define IPV6_V6ONLY 27')
5497 g.writeln('#define AI_PASSIVE 0x00000001')
5498 g.writeln('#define MSG_DONTWAIT 0x80')
5499}
5500
5501fn (mut g FlatGen) headerless_bsd_net_constants(af_inet6 string, msg_nosignal string, so_nosigpipe string) {
5502 g.writeln('#define AF_UNSPEC 0')
5503 g.writeln('#define AF_UNIX 1')
5504 g.writeln('#define AF_INET 2')
5505 g.writeln('#define AF_INET6 ${af_inet6}')
5506 g.writeln('#define SOCK_STREAM 1')
5507 g.writeln('#define SOCK_DGRAM 2')
5508 g.writeln('#define SOCK_RAW 3')
5509 g.writeln('#define SOCK_SEQPACKET 5')
5510 g.writeln('#if defined(__FreeBSD__)')
5511 g.writeln('#define SOCK_NONBLOCK 0x20000000')
5512 g.writeln('#endif')
5513 g.writeln('#define IPPROTO_IP 0')
5514 g.writeln('#define IPPROTO_ICMP 1')
5515 g.writeln('#define IPPROTO_TCP 6')
5516 g.writeln('#define IPPROTO_UDP 17')
5517 g.writeln('#define IPPROTO_IPV6 41')
5518 g.writeln('#define IPPROTO_ICMPV6 58')
5519 g.writeln('#define IPPROTO_RAW 255')
5520 g.writeln('#define SOL_SOCKET 0xffff')
5521 g.writeln('#define SO_DEBUG 0x0001')
5522 g.writeln('#define SO_REUSEADDR 0x0004')
5523 g.writeln('#define SO_KEEPALIVE 0x0008')
5524 g.writeln('#define SO_DONTROUTE 0x0010')
5525 g.writeln('#define SO_BROADCAST 0x0020')
5526 g.writeln('#define SO_LINGER 0x0080')
5527 g.writeln('#define SO_OOBINLINE 0x0100')
5528 g.writeln('#define SO_REUSEPORT 0x0200')
5529 if so_nosigpipe.len > 0 {
5530 g.writeln('#define SO_NOSIGPIPE ${so_nosigpipe}')
5531 }
5532 g.writeln('#define SO_SNDBUF 0x1001')
5533 g.writeln('#define SO_RCVBUF 0x1002')
5534 g.writeln('#define SO_SNDLOWAT 0x1003')
5535 g.writeln('#define SO_RCVLOWAT 0x1004')
5536 g.writeln('#define SO_SNDTIMEO 0x1005')
5537 g.writeln('#define SO_RCVTIMEO 0x1006')
5538 g.writeln('#define SO_ERROR 0x1007')
5539 g.writeln('#define SO_TYPE 0x1008')
5540 g.writeln('#define TCP_NODELAY 1')
5541 g.writeln('#define IP_HDRINCL 2')
5542 g.writeln('#define IP_MULTICAST_IF 9')
5543 g.writeln('#define IP_MULTICAST_TTL 10')
5544 g.writeln('#define IP_MULTICAST_LOOP 11')
5545 g.writeln('#define IP_ADD_MEMBERSHIP 12')
5546 g.writeln('#define IP_DROP_MEMBERSHIP 13')
5547 g.writeln('#define IPV6_MULTICAST_IF 9')
5548 g.writeln('#define IPV6_MULTICAST_HOPS 10')
5549 g.writeln('#define IPV6_MULTICAST_LOOP 11')
5550 g.writeln('#define IPV6_ADD_MEMBERSHIP 12')
5551 g.writeln('#define IPV6_JOIN_GROUP 12')
5552 g.writeln('#define IPV6_DROP_MEMBERSHIP 13')
5553 g.writeln('#define IPV6_LEAVE_GROUP 13')
5554 g.writeln('#define IPV6_V6ONLY 27')
5555 g.writeln('#define AI_PASSIVE 0x00000001')
5556 g.writeln('#define MSG_DONTWAIT 0x80')
5557 g.writeln('#define MSG_NOSIGNAL ${msg_nosignal}')
5558}
5559
5560fn (mut g FlatGen) headerless_solaris_net_constants() {
5561 g.writeln('#define AF_UNSPEC 0')
5562 g.writeln('#define AF_UNIX 1')
5563 g.writeln('#define AF_INET 2')
5564 g.writeln('#define AF_INET6 26')
5565 g.writeln('#define SOCK_STREAM 2')
5566 g.writeln('#define SOCK_DGRAM 1')
5567 g.writeln('#define SOCK_RAW 4')
5568 g.writeln('#define SOCK_SEQPACKET 6')
5569 g.writeln('#define IPPROTO_IP 0')
5570 g.writeln('#define IPPROTO_ICMP 1')
5571 g.writeln('#define IPPROTO_TCP 6')
5572 g.writeln('#define IPPROTO_UDP 17')
5573 g.writeln('#define IPPROTO_IPV6 41')
5574 g.writeln('#define IPPROTO_ICMPV6 58')
5575 g.writeln('#define IPPROTO_RAW 255')
5576 g.writeln('#define SOL_SOCKET 0xffff')
5577 g.writeln('#define SO_DEBUG 0x0001')
5578 g.writeln('#define SO_REUSEADDR 0x0004')
5579 g.writeln('#define SO_KEEPALIVE 0x0008')
5580 g.writeln('#define SO_DONTROUTE 0x0010')
5581 g.writeln('#define SO_BROADCAST 0x0020')
5582 g.writeln('#define SO_LINGER 0x0080')
5583 g.writeln('#define SO_OOBINLINE 0x0100')
5584 g.writeln('#define SO_SNDBUF 0x1001')
5585 g.writeln('#define SO_RCVBUF 0x1002')
5586 g.writeln('#define SO_SNDLOWAT 0x1003')
5587 g.writeln('#define SO_RCVLOWAT 0x1004')
5588 g.writeln('#define SO_SNDTIMEO 0x1005')
5589 g.writeln('#define SO_RCVTIMEO 0x1006')
5590 g.writeln('#define SO_ERROR 0x1007')
5591 g.writeln('#define SO_TYPE 0x1008')
5592 g.writeln('#define TCP_NODELAY 1')
5593 g.writeln('#define IP_HDRINCL 2')
5594 g.writeln('#define IP_MULTICAST_IF 0x10')
5595 g.writeln('#define IP_MULTICAST_TTL 0x11')
5596 g.writeln('#define IP_MULTICAST_LOOP 0x12')
5597 g.writeln('#define IP_ADD_MEMBERSHIP 0x13')
5598 g.writeln('#define IP_DROP_MEMBERSHIP 0x14')
5599 g.writeln('#define IPV6_MULTICAST_IF 0x6')
5600 g.writeln('#define IPV6_MULTICAST_HOPS 0x7')
5601 g.writeln('#define IPV6_MULTICAST_LOOP 0x8')
5602 g.writeln('#define IPV6_ADD_MEMBERSHIP 0x9')
5603 g.writeln('#define IPV6_JOIN_GROUP 0x9')
5604 g.writeln('#define IPV6_DROP_MEMBERSHIP 0xa')
5605 g.writeln('#define IPV6_LEAVE_GROUP 0xa')
5606 g.writeln('#define IPV6_V6ONLY 0x27')
5607 g.writeln('#define AI_PASSIVE 0x0008')
5608 g.writeln('#define MSG_DONTWAIT 0x80')
5609 g.writeln('#define MSG_NOSIGNAL 0x200')
5610}
5611
5612fn (mut g FlatGen) headerless_qnx_net_constants() {
5613 g.writeln('#define AF_UNSPEC 0')
5614 g.writeln('#define AF_UNIX 1')
5615 g.writeln('#define AF_INET 2')
5616 g.writeln('#define AF_INET6 24')
5617 g.writeln('#define SOCK_STREAM 1')
5618 g.writeln('#define SOCK_DGRAM 2')
5619 g.writeln('#define SOCK_RAW 3')
5620 g.writeln('#define SOCK_SEQPACKET 5')
5621 g.writeln('#define IPPROTO_IP 0')
5622 g.writeln('#define IPPROTO_ICMP 1')
5623 g.writeln('#define IPPROTO_TCP 6')
5624 g.writeln('#define IPPROTO_UDP 17')
5625 g.writeln('#define IPPROTO_IPV6 41')
5626 g.writeln('#define IPPROTO_ICMPV6 58')
5627 g.writeln('#define IPPROTO_RAW 255')
5628 g.writeln('#define SOL_SOCKET 0xffff')
5629 g.writeln('#define SO_DEBUG 0x0001')
5630 g.writeln('#define SO_REUSEADDR 0x0004')
5631 g.writeln('#define SO_KEEPALIVE 0x0008')
5632 g.writeln('#define SO_DONTROUTE 0x0010')
5633 g.writeln('#define SO_BROADCAST 0x0020')
5634 g.writeln('#define SO_LINGER 0x0080')
5635 g.writeln('#define SO_OOBINLINE 0x0100')
5636 g.writeln('#define SO_SNDBUF 0x1001')
5637 g.writeln('#define SO_RCVBUF 0x1002')
5638 g.writeln('#define SO_SNDLOWAT 0x1003')
5639 g.writeln('#define SO_RCVLOWAT 0x1004')
5640 g.writeln('#define SO_SNDTIMEO 0x1005')
5641 g.writeln('#define SO_RCVTIMEO 0x1006')
5642 g.writeln('#define SO_ERROR 0x1007')
5643 g.writeln('#define SO_TYPE 0x1008')
5644 g.writeln('#define TCP_NODELAY 1')
5645 g.writeln('#define IP_HDRINCL 2')
5646 g.writeln('#define IP_MULTICAST_IF 9')
5647 g.writeln('#define IP_MULTICAST_TTL 10')
5648 g.writeln('#define IP_MULTICAST_LOOP 11')
5649 g.writeln('#define IP_ADD_MEMBERSHIP 12')
5650 g.writeln('#define IP_DROP_MEMBERSHIP 13')
5651 g.writeln('#define IPV6_MULTICAST_IF 9')
5652 g.writeln('#define IPV6_MULTICAST_HOPS 10')
5653 g.writeln('#define IPV6_MULTICAST_LOOP 11')
5654 g.writeln('#define IPV6_ADD_MEMBERSHIP 12')
5655 g.writeln('#define IPV6_JOIN_GROUP 12')
5656 g.writeln('#define IPV6_DROP_MEMBERSHIP 13')
5657 g.writeln('#define IPV6_LEAVE_GROUP 13')
5658 g.writeln('#define IPV6_V6ONLY 27')
5659 g.writeln('#define AI_PASSIVE 0x00000001')
5660 g.writeln('#define MSG_DONTWAIT 0x80')
5661 g.writeln('#define MSG_NOSIGNAL 0x0800')
5662}
5663
5664fn (mut g FlatGen) headerless_linux_net_constants() {
5665 g.writeln('#define AF_UNSPEC 0')
5666 g.writeln('#define AF_UNIX 1')
5667 g.writeln('#define AF_INET 2')
5668 g.writeln('#define AF_INET6 10')
5669 g.writeln('#define SOCK_STREAM 1')
5670 g.writeln('#define SOCK_DGRAM 2')
5671 g.writeln('#define SOCK_RAW 3')
5672 g.writeln('#define SOCK_SEQPACKET 5')
5673 g.writeln('#define SOCK_NONBLOCK 04000')
5674 g.writeln('#define IPPROTO_IP 0')
5675 g.writeln('#define IPPROTO_ICMP 1')
5676 g.writeln('#define IPPROTO_TCP 6')
5677 g.writeln('#define IPPROTO_UDP 17')
5678 g.writeln('#define IPPROTO_IPV6 41')
5679 g.writeln('#define IPPROTO_ICMPV6 58')
5680 g.writeln('#define IPPROTO_RAW 255')
5681 g.writeln('#define SOL_SOCKET 1')
5682 g.writeln('#define SO_DEBUG 1')
5683 g.writeln('#define SO_REUSEADDR 2')
5684 g.writeln('#define SO_TYPE 3')
5685 g.writeln('#define SO_ERROR 4')
5686 g.writeln('#define SO_DONTROUTE 5')
5687 g.writeln('#define SO_BROADCAST 6')
5688 g.writeln('#define SO_SNDBUF 7')
5689 g.writeln('#define SO_RCVBUF 8')
5690 g.writeln('#define SO_KEEPALIVE 9')
5691 g.writeln('#define SO_OOBINLINE 10')
5692 g.writeln('#define SO_LINGER 13')
5693 g.writeln('#define SO_REUSEPORT 15')
5694 g.writeln('#define SO_RCVLOWAT 18')
5695 g.writeln('#define SO_SNDLOWAT 19')
5696 g.writeln('#define SO_RCVTIMEO 20')
5697 g.writeln('#define SO_SNDTIMEO 21')
5698 g.writeln('#define TCP_NODELAY 1')
5699 g.writeln('#define TCP_DEFER_ACCEPT 9')
5700 g.writeln('#define TCP_QUICKACK 12')
5701 g.writeln('#define TCP_FASTOPEN 23')
5702 g.writeln('#define IP_HDRINCL 3')
5703 g.writeln('#define IP_MULTICAST_IF 32')
5704 g.writeln('#define IP_MULTICAST_TTL 33')
5705 g.writeln('#define IP_MULTICAST_LOOP 34')
5706 g.writeln('#define IP_ADD_MEMBERSHIP 35')
5707 g.writeln('#define IP_DROP_MEMBERSHIP 36')
5708 g.writeln('#define IPV6_MULTICAST_IF 17')
5709 g.writeln('#define IPV6_MULTICAST_HOPS 18')
5710 g.writeln('#define IPV6_MULTICAST_LOOP 19')
5711 g.writeln('#define IPV6_ADD_MEMBERSHIP 20')
5712 g.writeln('#define IPV6_JOIN_GROUP 20')
5713 g.writeln('#define IPV6_DROP_MEMBERSHIP 21')
5714 g.writeln('#define IPV6_LEAVE_GROUP 21')
5715 g.writeln('#define IPV6_V6ONLY 26')
5716 g.writeln('#define AI_PASSIVE 0x0001')
5717 g.writeln('#define SOMAXCONN 4096')
5718 g.writeln('#define MSG_DONTWAIT 0x40')
5719 g.writeln('#define MSG_NOSIGNAL 0x4000')
5720}
5721
5722fn (mut g FlatGen) headerless_windows_net_constants() {
5723 g.writeln('#define AF_UNSPEC 0')
5724 g.writeln('#define AF_UNIX 1')
5725 g.writeln('#define AF_INET 2')
5726 g.writeln('#define AF_INET6 23')
5727 g.writeln('#define SOCK_STREAM 1')
5728 g.writeln('#define SOCK_DGRAM 2')
5729 g.writeln('#define SOCK_RAW 3')
5730 g.writeln('#define SOCK_SEQPACKET 5')
5731 g.writeln('#define SOCKET_ERROR (-1)')
5732 g.writeln('#define WSAEWOULDBLOCK 10035')
5733 g.writeln('#define IPPROTO_IP 0')
5734 g.writeln('#define IPPROTO_ICMP 1')
5735 g.writeln('#define IPPROTO_TCP 6')
5736 g.writeln('#define IPPROTO_UDP 17')
5737 g.writeln('#define IPPROTO_IPV6 41')
5738 g.writeln('#define IPPROTO_ICMPV6 58')
5739 g.writeln('#define IPPROTO_RAW 255')
5740 g.writeln('#define SOL_SOCKET 0xffff')
5741 g.writeln('#define SO_DEBUG 0x0001')
5742 g.writeln('#define SO_REUSEADDR 0x0004')
5743 g.writeln('#define SO_KEEPALIVE 0x0008')
5744 g.writeln('#define SO_DONTROUTE 0x0010')
5745 g.writeln('#define SO_BROADCAST 0x0020')
5746 g.writeln('#define SO_LINGER 0x0080')
5747 g.writeln('#define SO_OOBINLINE 0x0100')
5748 g.writeln('#define SO_SNDBUF 0x1001')
5749 g.writeln('#define SO_RCVBUF 0x1002')
5750 g.writeln('#define SO_SNDLOWAT 0x1003')
5751 g.writeln('#define SO_RCVLOWAT 0x1004')
5752 g.writeln('#define SO_SNDTIMEO 0x1005')
5753 g.writeln('#define SO_RCVTIMEO 0x1006')
5754 g.writeln('#define SO_ERROR 0x1007')
5755 g.writeln('#define SO_TYPE 0x1008')
5756 g.writeln('#define TCP_NODELAY 1')
5757 g.writeln('#define IP_HDRINCL 2')
5758 g.writeln('#define IP_MULTICAST_IF 9')
5759 g.writeln('#define IP_MULTICAST_TTL 10')
5760 g.writeln('#define IP_MULTICAST_LOOP 11')
5761 g.writeln('#define IP_ADD_MEMBERSHIP 12')
5762 g.writeln('#define IP_DROP_MEMBERSHIP 13')
5763 g.writeln('#define IPV6_MULTICAST_IF 9')
5764 g.writeln('#define IPV6_MULTICAST_HOPS 10')
5765 g.writeln('#define IPV6_MULTICAST_LOOP 11')
5766 g.writeln('#define IPV6_ADD_MEMBERSHIP 12')
5767 g.writeln('#define IPV6_JOIN_GROUP 12')
5768 g.writeln('#define IPV6_DROP_MEMBERSHIP 13')
5769 g.writeln('#define IPV6_LEAVE_GROUP 13')
5770 g.writeln('#define IPV6_V6ONLY 27')
5771 g.writeln('#define AI_PASSIVE 0x00000001')
5772 g.writeln('#define MSG_DONTWAIT 0')
5773 g.writeln('#define MSG_NOSIGNAL 0')
5774}
5775
5776fn (mut g FlatGen) write_arch_macros() {
5777 g.writeln('#ifndef __V_architecture')
5778 g.writeln('#define __V_architecture 0')
5779 g.writeln('#endif')
5780 g.writeln('#if defined(__x86_64__) || defined(_M_AMD64)')
5781 g.writeln('#define __V_amd64 1')
5782 g.writeln('#undef __V_architecture')
5783 g.writeln('#define __V_architecture 1')
5784 g.writeln('#endif')
5785 g.writeln('#if defined(__aarch64__) || defined(__arm64__) || defined(_M_ARM64)')
5786 g.writeln('#define __V_arm64 1')
5787 g.writeln('#undef __V_architecture')
5788 g.writeln('#define __V_architecture 2')
5789 g.writeln('#endif')
5790 g.writeln('#if defined(__arm__) || defined(_M_ARM)')
5791 g.writeln('#define __V_arm32 1')
5792 g.writeln('#undef __V_architecture')
5793 g.writeln('#define __V_architecture 3')
5794 g.writeln('#endif')
5795 g.writeln('#if defined(__riscv) && __riscv_xlen == 64')
5796 g.writeln('#define __V_rv64 1')
5797 g.writeln('#undef __V_architecture')
5798 g.writeln('#define __V_architecture 4')
5799 g.writeln('#endif')
5800 g.writeln('#if defined(__riscv) && __riscv_xlen == 32')
5801 g.writeln('#define __V_rv32 1')
5802 g.writeln('#undef __V_architecture')
5803 g.writeln('#define __V_architecture 5')
5804 g.writeln('#endif')
5805 g.writeln('#if defined(__i386__) || defined(_M_IX86)')
5806 g.writeln('#define __V_x86 1')
5807 g.writeln('#undef __V_architecture')
5808 g.writeln('#define __V_architecture 6')
5809 g.writeln('#endif')
5810}
5811
5812fn (mut g FlatGen) libc_compat_decls() {
5813 if g.libc_compat_fns['gettid'] {
5814 g.writeln('#ifdef __linux__')
5815 g.writeln('#ifndef SYS_gettid')
5816 g.writeln('#if defined(__x86_64__)')
5817 g.writeln('#define SYS_gettid 186')
5818 g.writeln('#elif defined(__aarch64__)')
5819 g.writeln('#define SYS_gettid 178')
5820 g.writeln('#elif defined(__i386__)')
5821 g.writeln('#define SYS_gettid 224')
5822 g.writeln('#elif defined(__arm__)')
5823 g.writeln('#define SYS_gettid 224')
5824 g.writeln('#elif defined(__riscv) && __riscv_xlen == 64')
5825 g.writeln('#define SYS_gettid 178')
5826 g.writeln('#elif defined(__loongarch_lp64)')
5827 g.writeln('#define SYS_gettid 178')
5828 g.writeln('#else')
5829 g.writeln('#error unsupported Linux gettid syscall number for this architecture')
5830 g.writeln('#endif')
5831 g.writeln('#endif')
5832 g.writeln('static inline u32 v3_gettid(void) {')
5833 g.writeln('\treturn (u32)syscall(SYS_gettid);')
5834 g.writeln('}')
5835 g.writeln('#endif')
5836 g.writeln('')
5837 }
5838}
5839
5840fn (mut g FlatGen) prealloc_atomic_compat_decls() {
5841 g.writeln('static inline int v_prealloc_atomic_add_i32(int *ptr, int delta) { return __atomic_add_fetch(ptr, delta, 5); }')
5842 g.writeln('static inline int v_prealloc_atomic_load_i32(int *ptr) { return __atomic_add_fetch(ptr, 0, 5); }')
5843 g.writeln('#ifdef __TINYC__')
5844 g.writeln('static inline int v_prealloc_atomic_store_i32(int *ptr, int val) { return (int)__atomic_exchange_4((u32*)ptr, (u32)val, 5); }')
5845 g.writeln('static inline int v_prealloc_atomic_cas_i32(int *ptr, int expected, int desired) { u32 e = (u32)expected; return __atomic_compare_exchange_4((u32*)ptr, &e, (u32)desired, 5, 5); }')
5846 g.writeln('#else')
5847 g.writeln('static inline int v_prealloc_atomic_store_i32(int *ptr, int val) { return __atomic_exchange_n(ptr, val, 5); }')
5848 g.writeln('static inline int v_prealloc_atomic_cas_i32(int *ptr, int expected, int desired) { return __atomic_compare_exchange_n(ptr, &expected, desired, 0, 5, 5); }')
5849 g.writeln('#endif')
5850}
5851
5852fn (mut g FlatGen) atomic_builtin_compat_decls() {
5853 // Atomic helpers. We use compiler __atomic_* builtins (memory order 5 == __ATOMIC_SEQ_CST).
5854 // clang/gcc inline the generic _n / RMW builtins. tcc only implements the inline
5855 // __atomic_{add,sub,fetch}_* RMW builtins; for load/store/exchange/cas it has no generic
5856 // _n form, so we route those to the sized __atomic_*_N libcalls (resolved from libc).
5857 g.writeln('static inline byte atomic_fetch_add_byte(void* ptr, byte delta) { return __atomic_fetch_add((byte*)ptr, delta, 5); }')
5858 g.writeln('static inline u16 atomic_fetch_add_u16(void* ptr, u16 delta) { return __atomic_fetch_add((u16*)ptr, delta, 5); }')
5859 g.writeln('static inline u32 atomic_fetch_add_u32(void* ptr, u32 delta) { return __atomic_fetch_add((u32*)ptr, delta, 5); }')
5860 g.writeln('static inline u64 atomic_fetch_add_u64(void* ptr, u64 delta) { return __atomic_fetch_add((u64*)ptr, delta, 5); }')
5861 g.writeln('static inline void* atomic_fetch_add_ptr(void* ptr, void* delta) { return (void*)(uintptr_t)__atomic_fetch_add((uintptr_t*)ptr, (uintptr_t)delta, 5); }')
5862 g.writeln('static inline byte atomic_fetch_sub_byte(void* ptr, byte delta) { return __atomic_fetch_sub((byte*)ptr, delta, 5); }')
5863 g.writeln('static inline u16 atomic_fetch_sub_u16(void* ptr, u16 delta) { return __atomic_fetch_sub((u16*)ptr, delta, 5); }')
5864 g.writeln('static inline u32 atomic_fetch_sub_u32(void* ptr, u32 delta) { return __atomic_fetch_sub((u32*)ptr, delta, 5); }')
5865 g.writeln('static inline u64 atomic_fetch_sub_u64(void* ptr, u64 delta) { return __atomic_fetch_sub((u64*)ptr, delta, 5); }')
5866 g.writeln('static inline void* atomic_fetch_sub_ptr(void* ptr, void* delta) { return (void*)(uintptr_t)__atomic_fetch_sub((uintptr_t*)ptr, (uintptr_t)delta, 5); }')
5867 g.writeln('static inline byte atomic_load_byte(void* ptr) { return __atomic_fetch_add((byte*)ptr, 0, 5); }')
5868 g.writeln('static inline u16 atomic_load_u16(void* ptr) { return __atomic_fetch_add((u16*)ptr, 0, 5); }')
5869 g.writeln('static inline u32 atomic_load_u32(void* ptr) { return __atomic_fetch_add((u32*)ptr, 0, 5); }')
5870 g.writeln('static inline u64 atomic_load_u64(void* ptr) { return __atomic_fetch_add((u64*)ptr, 0, 5); }')
5871 g.writeln('#ifdef __TINYC__')
5872 g.writeln('#if UINTPTR_MAX == 0xFFFFFFFF')
5873 g.writeln('static inline void* atomic_load_ptr(void* ptr) { return (void*)(size_t)__atomic_load_4((u32*)ptr, 5); }')
5874 g.writeln('#else')
5875 g.writeln('static inline void* atomic_load_ptr(void* ptr) { return (void*)(size_t)__atomic_load_8((u64*)ptr, 5); }')
5876 g.writeln('#endif')
5877 g.writeln('static inline byte atomic_exchange_byte(void* ptr, byte val) { return __atomic_exchange_1((byte*)ptr, val, 5); }')
5878 g.writeln('static inline u16 atomic_exchange_u16(void* ptr, u16 val) { return __atomic_exchange_2((u16*)ptr, val, 5); }')
5879 g.writeln('static inline u32 atomic_exchange_u32(void* ptr, u32 val) { return __atomic_exchange_4((u32*)ptr, val, 5); }')
5880 g.writeln('static inline u64 atomic_exchange_u64(void* ptr, u64 val) { return __atomic_exchange_8((u64*)ptr, val, 5); }')
5881 g.writeln('static inline void atomic_store_byte(void* ptr, byte val) { __atomic_store_1((byte*)ptr, val, 5); }')
5882 g.writeln('static inline void atomic_store_u16(void* ptr, u16 val) { __atomic_store_2((u16*)ptr, val, 5); }')
5883 g.writeln('static inline void atomic_store_u32(void* ptr, u32 val) { __atomic_store_4((u32*)ptr, val, 5); }')
5884 g.writeln('static inline void atomic_store_u64(void* ptr, u64 val) { __atomic_store_8((u64*)ptr, val, 5); }')
5885 g.writeln('#if UINTPTR_MAX == 0xFFFFFFFF')
5886 g.writeln('static inline void* atomic_exchange_ptr(void* ptr, void* val) { return (void*)(size_t)__atomic_exchange_4((u32*)ptr, (u32)(size_t)val, 5); }')
5887 g.writeln('static inline void atomic_store_ptr(void* ptr, void* val) { __atomic_store_4((u32*)ptr, (u32)(size_t)val, 5); }')
5888 g.writeln('#else')
5889 g.writeln('static inline void* atomic_exchange_ptr(void* ptr, void* val) { return (void*)(size_t)__atomic_exchange_8((u64*)ptr, (u64)(size_t)val, 5); }')
5890 g.writeln('static inline void atomic_store_ptr(void* ptr, void* val) { __atomic_store_8((u64*)ptr, (u64)(size_t)val, 5); }')
5891 g.writeln('#endif')
5892 g.writeln('static inline bool atomic_compare_exchange_strong_byte(void* ptr, byte* expected, byte desired) { return __atomic_compare_exchange_1((byte*)ptr, expected, desired, 5, 5); }')
5893 g.writeln('static inline bool atomic_compare_exchange_strong_u16(void* ptr, u16* expected, u16 desired) { return __atomic_compare_exchange_2((u16*)ptr, expected, desired, 5, 5); }')
5894 g.writeln('static inline bool atomic_compare_exchange_strong_u32(void* ptr, u32* expected, u32 desired) { return __atomic_compare_exchange_4((u32*)ptr, expected, desired, 5, 5); }')
5895 g.writeln('static inline bool atomic_compare_exchange_strong_u64(void* ptr, u64* expected, u64 desired) { return __atomic_compare_exchange_8((u64*)ptr, expected, desired, 5, 5); }')
5896 g.writeln('#if UINTPTR_MAX == 0xFFFFFFFF')
5897 g.writeln('static inline bool atomic_compare_exchange_strong_ptr(void* ptr, void* expected, ptrdiff_t desired) { return __atomic_compare_exchange_4((u32*)ptr, (u32*)expected, (u32)desired, 5, 5); }')
5898 g.writeln('#else')
5899 g.writeln('static inline bool atomic_compare_exchange_strong_ptr(void* ptr, void* expected, ptrdiff_t desired) { return __atomic_compare_exchange_8((u64*)ptr, (u64*)expected, (u64)desired, 5, 5); }')
5900 g.writeln('#endif')
5901 g.writeln('static inline bool atomic_compare_exchange_weak_byte(void* ptr, byte* expected, byte desired) { return __atomic_compare_exchange_1((byte*)ptr, expected, desired, 5, 5); }')
5902 g.writeln('static inline bool atomic_compare_exchange_weak_u16(void* ptr, u16* expected, u16 desired) { return __atomic_compare_exchange_2((u16*)ptr, expected, desired, 5, 5); }')
5903 g.writeln('static inline bool atomic_compare_exchange_weak_u32(void* ptr, u32* expected, u32 desired) { return __atomic_compare_exchange_4((u32*)ptr, expected, desired, 5, 5); }')
5904 g.writeln('static inline bool atomic_compare_exchange_weak_u64(void* ptr, u64* expected, u64 desired) { return __atomic_compare_exchange_8((u64*)ptr, expected, desired, 5, 5); }')
5905 g.writeln('#else')
5906 g.writeln('static inline void* atomic_load_ptr(void* ptr) { return __atomic_load_n((void**)ptr, 5); }')
5907 g.writeln('static inline byte atomic_exchange_byte(void* ptr, byte val) { return __atomic_exchange_n((byte*)ptr, val, 5); }')
5908 g.writeln('static inline u16 atomic_exchange_u16(void* ptr, u16 val) { return __atomic_exchange_n((u16*)ptr, val, 5); }')
5909 g.writeln('static inline u32 atomic_exchange_u32(void* ptr, u32 val) { return __atomic_exchange_n((u32*)ptr, val, 5); }')
5910 g.writeln('static inline u64 atomic_exchange_u64(void* ptr, u64 val) { return __atomic_exchange_n((u64*)ptr, val, 5); }')
5911 g.writeln('static inline void* atomic_exchange_ptr(void* ptr, void* val) { return __atomic_exchange_n((void**)ptr, val, 5); }')
5912 g.writeln('static inline void atomic_store_byte(void* ptr, byte val) { __atomic_store_n((byte*)ptr, val, 5); }')
5913 g.writeln('static inline void atomic_store_u16(void* ptr, u16 val) { __atomic_store_n((u16*)ptr, val, 5); }')
5914 g.writeln('static inline void atomic_store_u32(void* ptr, u32 val) { __atomic_store_n((u32*)ptr, val, 5); }')
5915 g.writeln('static inline void atomic_store_u64(void* ptr, u64 val) { __atomic_store_n((u64*)ptr, val, 5); }')
5916 g.writeln('static inline void atomic_store_ptr(void* ptr, void* val) { __atomic_store_n((void**)ptr, val, 5); }')
5917 g.writeln('static inline bool atomic_compare_exchange_strong_byte(void* ptr, byte* expected, byte desired) { return __atomic_compare_exchange_n((byte*)ptr, expected, desired, 0, 5, 5); }')
5918 g.writeln('static inline bool atomic_compare_exchange_strong_u16(void* ptr, u16* expected, u16 desired) { return __atomic_compare_exchange_n((u16*)ptr, expected, desired, 0, 5, 5); }')
5919 g.writeln('static inline bool atomic_compare_exchange_strong_u32(void* ptr, u32* expected, u32 desired) { return __atomic_compare_exchange_n((u32*)ptr, expected, desired, 0, 5, 5); }')
5920 g.writeln('static inline bool atomic_compare_exchange_strong_u64(void* ptr, u64* expected, u64 desired) { return __atomic_compare_exchange_n((u64*)ptr, expected, desired, 0, 5, 5); }')
5921 g.writeln('static inline bool atomic_compare_exchange_strong_ptr(void* ptr, void* expected, ptrdiff_t desired) { return __atomic_compare_exchange_n((void**)ptr, (void**)expected, (void*)desired, 0, 5, 5); }')
5922 g.writeln('static inline bool atomic_compare_exchange_weak_byte(void* ptr, byte* expected, byte desired) { return __atomic_compare_exchange_n((byte*)ptr, expected, desired, 1, 5, 5); }')
5923 g.writeln('static inline bool atomic_compare_exchange_weak_u16(void* ptr, u16* expected, u16 desired) { return __atomic_compare_exchange_n((u16*)ptr, expected, desired, 1, 5, 5); }')
5924 g.writeln('static inline bool atomic_compare_exchange_weak_u32(void* ptr, u32* expected, u32 desired) { return __atomic_compare_exchange_n((u32*)ptr, expected, desired, 1, 5, 5); }')
5925 g.writeln('static inline bool atomic_compare_exchange_weak_u64(void* ptr, u64* expected, u64 desired) { return __atomic_compare_exchange_n((u64*)ptr, expected, desired, 1, 5, 5); }')
5926 g.writeln('#endif')
5927 g.writeln('static inline bool atomic_compare_exchange_weak_ptr(void* ptr, void* expected, ptrdiff_t desired) { return atomic_compare_exchange_strong_ptr(ptr, expected, desired); }')
5928 g.writeln('static inline void cpu_relax(void) { __asm__ __volatile__("" ::: "memory"); }')
5929}
5930
5931fn (mut g FlatGen) builtin_abi_decls() {
5932 if !g.has_builtins {
5933 return
5934 }
5935 g.libc_compat_decls()
5936 g.writeln('#ifndef __linux__')
5937 g.writeln('#define pthread_rwlockattr_setkind_np(attr, kind) 0')
5938 g.writeln('#endif')
5939 g.filelock_compat_decls()
5940 g.writeln('#define array_new(elem_size, len, cap) __new_array((len), (cap), (elem_size))')
5941 g.writeln('#define array_push array__push')
5942 g.writeln('void array__push_many(array* a, void* val, int size);')
5943 g.writeln('#define array_push_many_ptr(a, val, size) array__push_many((a), (void*)(val), (size))')
5944 g.writeln('#define array_get array__get')
5945 g.writeln('#define array_set(a, i, ...) array__set(&(a), (i), __VA_ARGS__)')
5946 g.writeln('array array__clone(array* a);')
5947 g.writeln('#define array_slice array__slice')
5948 g.writeln('#define array_delete array__delete')
5949 g.writeln('#define array_ensure_cap array__ensure_cap')
5950 g.writeln('#define map__get_or_set map__get_and_set')
5951 g.writeln('#ifndef V_COMMIT_HASH')
5952 g.writeln('#define V_COMMIT_HASH ""')
5953 g.writeln('#endif')
5954 g.writeln('#ifndef memory_order_relaxed')
5955 g.writeln('#define memory_order_relaxed 0')
5956 g.writeln('#define memory_order_acquire 2')
5957 g.writeln('#define memory_order_release 3')
5958 g.writeln('#define memory_order_acq_rel 4')
5959 g.writeln('#define memory_order_seq_cst 5')
5960 g.writeln('#endif')
5961 g.writeln('#define atomic_thread_fence(order) __atomic_thread_fence(order)')
5962 // Weak fallbacks for the heap-tracking hooks. A program that provides real
5963 // implementations (e.g. a `vheap_alloc`/`vheap_free` from a linked C file, as
5964 // some projects do) overrides these without a redefinition/static-vs-non-static
5965 // clash against that file's own non-static prototype.
5966 g.writeln('__attribute__((weak)) void vheap_alloc(void* p, u64 n) { (void)p; (void)n; }')
5967 g.writeln('__attribute__((weak)) void vheap_free(void* p) { (void)p; }')
5968 g.prealloc_atomic_compat_decls()
5969 g.atomic_builtin_compat_decls()
5970 g.writeln('static inline double math__abs(double a) { return a < 0 ? -a : a; }')
5971 g.writeln('static inline double math__min(double a, double b) { return a < b ? a : b; }')
5972 g.writeln('static const u64 _wyp[4] = {0x2d358dccaa6c78a5ull, 0x8bb84b93962eacc9ull, 0x4b33a62ed433d4a3ull, 0x4d5a2da51de1aa47ull};')
5973 g.writeln('static inline u64 _wymix(u64 a, u64 b) { u64 ha = a >> 32, hb = b >> 32, la = (u32)a, lb = (u32)b, hi, lo; u64 rh = ha * hb, rm0 = ha * lb, rm1 = hb * la, rl = la * lb, t = rl + (rm0 << 32), c = t < rl; lo = t + (rm1 << 32); c += lo < t; hi = rh + (rm0 >> 32) + (rm1 >> 32) + c; return lo ^ hi; }')
5974 g.writeln('static inline u64 wyhash64(u64 a, u64 b) { a ^= _wyp[0]; b ^= _wyp[1]; a *= 0xa0761d6478bd642full; b *= 0xe7037ed1a0b428dbull; return (a ^ (a >> 32)) ^ (b ^ (b >> 32)); }')
5975 g.writeln('static inline u64 wyhash(const void* key, size_t len, u64 seed, const u64* secret) { const unsigned char* p = (const unsigned char*)key; u64 h = seed ^ secret[0] ^ (u64)len; for (size_t i = 0; i < len; i++) h = wyhash64(h ^ (u64)p[i], secret[(i + 1) & 3]); return h; }')
5976 g.writeln('#define v_signal_with_handler_cast(sig, handler) signal((sig), ((void (*)(int))(handler)))')
5977 g.writeln('string string__clone(string a);')
5978 g.writeln('void string__free(string* s);')
5979 g.writeln('string string__plus(string s, string a);')
5980 g.writeln('string int__str(int n);')
5981 g.writeln('string i64__str(i64 n);')
5982 g.writeln('string u64__str(u64 nn);')
5983 g.writeln('string f64__str(double x);')
5984 g.writeln('string rune__str(i32 c);')
5985 g.writeln('u8* malloc_noscan(ptrdiff_t n);')
5986 g.writeln('static inline string v3_c_lit(const char* s, int len) { return (string){.str = (u8*)s, .len = len, .is_lit = 1}; }')
5987 g.writeln('static inline string v3_char_string(int c) { return rune__str((i32)c); }')
5988 g.writeln('static inline string v3_f64_fixed(double x, int precision) { char tmp[128]; int n = snprintf(tmp, sizeof(tmp), "%.*f", precision, x); if (n < 0) return v3_c_lit("", 0); if (n < (int)sizeof(tmp)) { u8* out = malloc_noscan(n + 1); memcpy(out, tmp, n + 1); return (string){.str = out, .len = n, .is_lit = 0}; } u8* out = malloc_noscan(n + 1); snprintf((char*)out, (size_t)n + 1, "%.*f", precision, x); return (string){.str = out, .len = n, .is_lit = 0}; }')
5989 g.writeln('static inline string v3_int_zpad(int n, int width) { string s = int__str(n); if (n < 0) return s; while (s.len < width) s = string__plus(v3_c_lit("0", 1), s); return s; }')
5990 g.writeln('static inline string v3_i64_zpad(i64 n, int width) { string s = i64__str(n); if (n < 0) return s; while (s.len < width) s = string__plus(v3_c_lit("0", 1), s); return s; }')
5991 g.writeln('static inline string v3_u64_zpad(u64 n, int width) { string s = u64__str(n); while (s.len < width) s = string__plus(v3_c_lit("0", 1), s); return s; }')
5992 g.writeln('static inline i64 v3_map_signed(void* p, int bytes) { if (bytes == 1) return *(signed char*)p; if (bytes == 2) return *(short*)p; if (bytes == 8) return *(long long*)p; return *(int*)p; }')
5993 g.writeln('static inline u64 v3_map_unsigned(void* p, int bytes) { if (bytes == 1) return *(unsigned char*)p; if (bytes == 2) return *(unsigned short*)p; if (bytes == 8) return *(unsigned long long*)p; return *(unsigned int*)p; }')
5994 g.writeln('static inline string v3_f32_array_str(float* vals, int n) { string out = v3_c_lit("[", 1); for (int i = 0; i < n; ++i) { if (i > 0) out = string__plus(out, v3_c_lit(", ", 2)); out = string__plus(out, f64__str((double)vals[i])); } return string__plus(out, v3_c_lit("]", 1)); }')
5995 g.writeln('static inline string v3_f64_array_str(double* vals, int n) { string out = v3_c_lit("[", 1); for (int i = 0; i < n; ++i) { if (i > 0) out = string__plus(out, v3_c_lit(", ", 2)); out = string__plus(out, f64__str(vals[i])); } return string__plus(out, v3_c_lit("]", 1)); }')
5996 g.writeln('static inline string v3_map_str_piece(void* p, int kind, int bytes, int fixed_len) {')
5997 g.writeln('\tif (kind == 1) { return string__plus(string__plus(v3_c_lit("\'", 1), *(string*)p), v3_c_lit("\'", 1)); }')
5998 g.writeln('\tif (kind == 2) { return v3_i64_zpad(v3_map_signed(p, bytes), 0); }')
5999 g.writeln('\tif (kind == 3) { return u64__str(v3_map_unsigned(p, bytes)); }')
6000 g.writeln('\tif (kind == 4) { i32 r = bytes == 1 ? (i32)(*(u8*)p) : *(i32*)p; return string__plus(string__plus(v3_c_lit("`", 1), rune__str(r)), v3_c_lit("`", 1)); }')
6001 g.writeln('\tif (kind == 5) { if (bytes == (int)sizeof(float)) return f64__str((double)*(float*)p); return f64__str(*(double*)p); }')
6002 g.writeln('\tif (kind == 6) { if (fixed_len == 0 && bytes == (int)sizeof(Array)) { Array a = *(Array*)p; if (a.element_size == (int)sizeof(float)) return v3_f32_array_str((float*)a.data, a.len); if (a.element_size == (int)sizeof(double)) return v3_f64_array_str((double*)a.data, a.len); } if (fixed_len > 0 && bytes == fixed_len * (int)sizeof(float)) return v3_f32_array_str((float*)p, fixed_len); int n = fixed_len > 0 ? fixed_len : bytes / (int)sizeof(double); return v3_f64_array_str((double*)p, n); }')
6003 g.writeln('\tif (kind == 8) { return f64__str((double)*(float*)p); }')
6004 g.writeln('\tif (kind == 9) { int n = fixed_len > 0 ? fixed_len : bytes / (int)sizeof(float); return v3_f32_array_str((float*)p, n); }')
6005 g.writeln('\tif (kind == 7) { return *(bool*)p ? v3_c_lit("true", 4) : v3_c_lit("false", 5); }')
6006 g.writeln('\treturn v3_c_lit("<map value>", 11);')
6007 g.writeln('}')
6008 g.writeln('static inline string v3_map_str(map m, int key_kind, int val_kind, int val_fixed_len) {')
6009 g.writeln('\tstring out = v3_c_lit("{", 1); bool first = true;')
6010 g.writeln('\tfor (int i = 0; i < m.key_values.len; ++i) {')
6011 g.writeln('\t\tif (m.key_values.deletes != 0 && m.key_values.all_deleted != 0 && m.key_values.all_deleted[i] != 0) continue;')
6012 g.writeln('\t\tif (!first) out = string__plus(out, v3_c_lit(", ", 2));')
6013 g.writeln('\t\tvoid* key = (void*)(m.key_values.keys + i * m.key_values.key_bytes);')
6014 g.writeln('\t\tvoid* val = (void*)(m.key_values.values + i * m.key_values.value_bytes);')
6015 g.writeln('\t\tout = string__plus(out, v3_map_str_piece(key, key_kind, m.key_values.key_bytes, 0));')
6016 g.writeln('\t\tout = string__plus(out, v3_c_lit(": ", 2));')
6017 g.writeln('\t\tout = string__plus(out, v3_map_str_piece(val, val_kind, m.value_bytes, val_fixed_len));')
6018 g.writeln('\t\tfirst = false;')
6019 g.writeln('\t}')
6020 g.writeln('\treturn string__plus(out, v3_c_lit("}", 1));')
6021 g.writeln('}')
6022 g.writeln('static inline int array_index_int(Array a, int val) { for (int i = 0; i < a.len; i++) if (((int*)a.data)[i] == val) return i; return -1; }')
6023 g.writeln('static inline int array_last_index_int(Array a, int val) { for (int i = a.len - 1; i >= 0; i--) if (((int*)a.data)[i] == val) return i; return -1; }')
6024 g.writeln('static inline bool array_contains_int(Array a, int val) { return array_index_int(a, val) >= 0; }')
6025 g.writeln('static inline int array_index_u8(Array a, u8 val) { for (int i = 0; i < a.len; i++) if (((u8*)a.data)[i] == val) return i; return -1; }')
6026 g.writeln('static inline int array_last_index_u8(Array a, u8 val) { for (int i = a.len - 1; i >= 0; i--) if (((u8*)a.data)[i] == val) return i; return -1; }')
6027 g.writeln('static inline bool array_contains_u8(Array a, u8 val) { return array_index_u8(a, val) >= 0; }')
6028 g.writeln('static inline int array_index_string(Array a, string val) { string* data = (string*)a.data; for (int i = 0; i < a.len; i++) if (data[i].len == val.len && memcmp(data[i].str, val.str, val.len) == 0) return i; return -1; }')
6029 g.writeln('static inline int array_last_index_string(Array a, string val) { string* data = (string*)a.data; for (int i = a.len - 1; i >= 0; i--) if (data[i].len == val.len && memcmp(data[i].str, val.str, val.len) == 0) return i; return -1; }')
6030 g.writeln('static inline bool array_contains_string(Array a, string val) { return array_index_string(a, val) >= 0; }')
6031 g.writeln('static inline int array_last_index_raw(Array a, const void* val) { for (int i = a.len - 1; i >= 0; i--) if (memcmp((u8*)a.data + (size_t)i * (size_t)a.element_size, val, (size_t)a.element_size) == 0) return i; return -1; }')
6032 g.writeln('static inline bool array_eq_raw(Array a, Array b, int elem_size) { return a.len == b.len && (a.len == 0 || memcmp(a.data, b.data, (size_t)a.len * elem_size) == 0); }')
6033 g.writeln('static inline bool array_eq_string(Array a, Array b) { if (a.len != b.len) return false; string* ad = (string*)a.data; string* bd = (string*)b.data; for (int i = 0; i < a.len; i++) if (ad[i].len != bd[i].len || memcmp(ad[i].str, bd[i].str, ad[i].len) != 0) return false; return true; }')
6034 g.writeln('static inline bool array_eq_array(Array a, Array b, int depth) { if (a.len != b.len || a.element_size != b.element_size) return false; if (depth <= 1 || a.element_size != sizeof(Array)) { if (a.element_size == sizeof(string)) return array_eq_string(a, b); return array_eq_raw(a, b, a.element_size); } Array* ad = (Array*)a.data; Array* bd = (Array*)b.data; for (int i = 0; i < a.len; i++) { if (!array_eq_array(ad[i], bd[i], depth - 1)) return false; } return true; }')
6035 g.writeln('static inline bool v3_map_map_eq(map a, map b);')
6036 g.writeln('static inline bool v3_map_value_eq(void* a, void* b, int value_bytes) { if (value_bytes == sizeof(string)) { string sa = *(string*)a; string sb = *(string*)b; return sa.len == sb.len && (sa.len == 0 || memcmp(sa.str, sb.str, sa.len) == 0); } if (value_bytes == sizeof(map)) { return v3_map_map_eq(*(map*)a, *(map*)b); } if (value_bytes == sizeof(string) + sizeof(map)) { string sa = *(string*)a; string sb = *(string*)b; if (!(sa.len == sb.len && (sa.len == 0 || memcmp(sa.str, sb.str, sa.len) == 0))) return false; map ma = *(map*)((u8*)a + sizeof(string)); map mb = *(map*)((u8*)b + sizeof(string)); return v3_map_map_eq(ma, mb); } if (value_bytes == sizeof(Array)) { Array aa = *(Array*)a; Array bb = *(Array*)b; if (aa.element_size != bb.element_size) return false; if (aa.element_size == sizeof(string)) return array_eq_string(aa, bb); if (aa.element_size == sizeof(Array)) return array_eq_array(aa, bb, 8); return array_eq_raw(aa, bb, aa.element_size); } return memcmp(a, b, value_bytes) == 0; }')
6037 g.writeln('static inline bool v3_map_map_eq(map a, map b) { if (a.len != b.len) return false; for (int i = 0; i < a.key_values.len; ++i) { if (a.key_values.deletes != 0 && a.key_values.all_deleted != 0 && a.key_values.all_deleted[i] != 0) continue; void* ak = (void*)(a.key_values.keys + i * a.key_values.key_bytes); void* av = (void*)(a.key_values.values + i * a.key_values.value_bytes); bool found = false; for (int j = 0; j < b.key_values.len; ++j) { if (b.key_values.deletes != 0 && b.key_values.all_deleted != 0 && b.key_values.all_deleted[j] != 0) continue; void* bk = (void*)(b.key_values.keys + j * b.key_values.key_bytes); if (a.key_eq_fn(ak, bk)) { void* bv = (void*)(b.key_values.values + j * b.key_values.value_bytes); if (!v3_map_value_eq(av, bv, a.value_bytes)) return false; found = true; break; } } if (!found) return false; } return true; }')
6038 g.writeln('static inline bool fixed_array_contains_string(const string* a, int len, string val) { for (int i = 0; i < len; i++) if (a[i].len == val.len && memcmp(a[i].str, val.str, val.len) == 0) return true; return false; }')
6039 g.writeln('static inline bool fixed_array_contains_u8(const u8* a, int len, u8 val) { for (int i = 0; i < len; i++) if (a[i] == val) return true; return false; }')
6040 g.writeln('static inline bool fixed_array_contains_int(const int* a, int len, int val) { for (int i = 0; i < len; i++) if (a[i] == val) return true; return false; }')
6041 g.writeln('static inline string Array_str(Array a) { if (a.element_size == 1) { u8* buf = (u8*)malloc((size_t)a.len + 1); if (a.len > 0) memcpy(buf, a.data, (size_t)a.len); buf[a.len] = 0; return (string){buf, a.len, 0}; } return (string){(u8*)"[]", 2, 1}; }')
6042 g.writeln('#ifndef max_int')
6043 g.writeln('#define max_int max_i32')
6044 g.writeln('#endif')
6045 g.writeln('#ifndef min_int')
6046 g.writeln('#define min_int min_i32')
6047 g.writeln('#endif')
6048 g.writeln('')
6049}
6050
6051fn (mut g FlatGen) filelock_compat_decls() {
6052 if !g.libc_compat_fns['filelock'] {
6053 return
6054 }
6055 g.writeln('#ifndef V_OS_FILELOCK_HELPERS_H')
6056 g.writeln('#ifdef _WIN32')
6057 g.writeln('BOOL LockFileEx(HANDLE handle, DWORD flags, DWORD reserved, DWORD low, DWORD high, OVERLAPPED* overlap);')
6058 g.writeln('BOOL UnlockFileEx(HANDLE handle, DWORD reserved, DWORD low, DWORD high, OVERLAPPED* overlap);')
6059 g.writeln('static inline int v_filelock_lock(HANDLE handle, int exclusive, int immediate, u64 start, u64 len) { OVERLAPPED overlap; memset(&overlap, 0, sizeof(overlap)); overlap.Offset = (DWORD)(start & 0xffffffffULL); overlap.OffsetHigh = (DWORD)(start >> 32); DWORD flags = immediate ? LOCKFILE_FAIL_IMMEDIATELY : 0; if (exclusive) { flags |= LOCKFILE_EXCLUSIVE_LOCK; } DWORD low = len == 0 ? MAXDWORD : (DWORD)(len & 0xffffffffULL); DWORD high = len == 0 ? MAXDWORD : (DWORD)(len >> 32); return LockFileEx(handle, flags, 0, low, high, &overlap) ? 0 : -1; }')
6060 g.writeln('static inline int v_filelock_unlock(HANDLE handle, u64 start, u64 len) { OVERLAPPED overlap; memset(&overlap, 0, sizeof(overlap)); overlap.Offset = (DWORD)(start & 0xffffffffULL); overlap.OffsetHigh = (DWORD)(start >> 32); DWORD low = len == 0 ? MAXDWORD : (DWORD)(len & 0xffffffffULL); DWORD high = len == 0 ? MAXDWORD : (DWORD)(len >> 32); return UnlockFileEx(handle, 0, low, high, &overlap) ? 0 : -1; }')
6061 g.writeln('#else')
6062 g.writeln('static inline int v_filelock_lock(int fd, int exclusive, int immediate, u64 start, u64 len) { struct flock fl; memset(&fl, 0, sizeof(fl)); fl.l_type = exclusive ? F_WRLCK : F_RDLCK; fl.l_whence = SEEK_SET; fl.l_start = (off_t)start; fl.l_len = len == 0 ? 0 : (off_t)len; return fcntl(fd, immediate ? F_SETLK : F_SETLKW, &fl); }')
6063 g.writeln('static inline int v_filelock_unlock(int fd, u64 start, u64 len) { struct flock fl; memset(&fl, 0, sizeof(fl)); fl.l_type = F_UNLCK; fl.l_whence = SEEK_SET; fl.l_start = (off_t)start; fl.l_len = len == 0 ? 0 : (off_t)len; return fcntl(fd, F_SETLK, &fl); }')
6064 g.writeln('#endif')
6065 g.writeln('#endif')
6066}
6067
6068fn (mut g FlatGen) collect_fixed_array_typedefs_needed() map[string]FixedArrayTypedefInfo {
6069 mut needed := map[string]FixedArrayTypedefInfo{}
6070 old_module := g.tc.cur_module
6071 for name, ret_type in g.tc.fn_ret_types {
6072 g.tc.cur_module = module_from_qualified_name(name)
6073 g.collect_fixed_array_typedef(ret_type, mut needed)
6074 }
6075 for name, param_types in g.tc.fn_param_types {
6076 g.tc.cur_module = module_from_qualified_name(name)
6077 for param_type in param_types {
6078 g.collect_fixed_array_typedef(param_type, mut needed)
6079 }
6080 }
6081 for name, fields in g.tc.structs {
6082 g.tc.cur_module = g.fixed_array_typedef_type_module(name, old_module)
6083 for field in fields {
6084 g.collect_fixed_array_typedef(field.typ, mut needed)
6085 }
6086 }
6087 for name, fields in g.tc.interface_fields {
6088 g.tc.cur_module = module_from_qualified_name(name)
6089 for field in fields {
6090 g.collect_fixed_array_typedef(field.typ, mut needed)
6091 }
6092 }
6093 for name, typ in g.global_types {
6094 g.tc.cur_module = g.global_modules[name] or { old_module }
6095 g.collect_fixed_array_typedef(typ, mut needed)
6096 }
6097 for _, typ in g.tc.c_globals {
6098 g.tc.cur_module = old_module
6099 g.collect_fixed_array_typedef(typ, mut needed)
6100 }
6101 for name, typ in g.tc.const_types {
6102 g.tc.cur_module = g.const_modules[name] or { old_module }
6103 g.collect_fixed_array_typedef(typ, mut needed)
6104 }
6105 g.tc.cur_module = old_module
6106 for node in g.a.nodes {
6107 g.collect_fixed_array_typedef_text(node.typ, mut needed)
6108 match node.kind {
6109 .array_init, .array_literal, .cast_expr, .sizeof_expr, .typeof_expr {
6110 g.collect_fixed_array_typedef_text(node.value, mut needed)
6111 }
6112 else {}
6113 }
6114 }
6115 g.tc.cur_module = old_module
6116 return needed
6117}
6118
6119fn (mut g FlatGen) fixed_array_typedefs() {
6120 needed := g.collect_fixed_array_typedefs_needed()
6121 old_len := g.emitted_fixed_array_typedefs.len
6122 for name, info in needed {
6123 g.emit_fixed_array_typedef(name, info, needed, mut g.emitted_fixed_array_typedefs)
6124 }
6125 // Return wrappers for non-early element types (struct/`string`/nested fixed array):
6126 // their bare typedef (above) and element definitions are available now, so a C
6127 // function returning `[N]Foo`/`[N]string` can return the wrapper struct instead of the
6128 // raw array type C rejects. Sorted for deterministic output.
6129 mut wrapper_names := []string{}
6130 for name, _ in needed {
6131 wrapper_names << name
6132 }
6133 wrapper_names.sort()
6134 mut emitted_wrapper := false
6135 for name in wrapper_names {
6136 if name !in g.fixed_array_ret_wrappers {
6137 continue
6138 }
6139 info := needed[name] or { continue }
6140 if fixed_array_typedef_is_early(info.arr) {
6141 continue
6142 }
6143 // Completes the struct forward-declared in fixed_array_early_typedefs().
6144 g.emit_fixed_array_ret_wrapper(name, info, true)
6145 emitted_wrapper = true
6146 }
6147 if g.emitted_fixed_array_typedefs.len > old_len || emitted_wrapper {
6148 g.writeln('')
6149 }
6150}
6151
6152// fixed_array_typedef_is_early reports whether a fixed array's bare typedef can be
6153// emitted before struct definitions: its element chain must bottom out in a
6154// primitive/pointer/enum (not a struct or `string`, whose definitions come later).
6155fn fixed_array_typedef_is_early(arr types.ArrayFixed) bool {
6156 elem := arr.elem_type
6157 if elem is types.ArrayFixed {
6158 return fixed_array_typedef_is_early(elem)
6159 }
6160 return fixed_array_elem_is_early_complete(elem)
6161}
6162
6163// populate_fixed_array_ret_wrappers records which fixed-array types get a return
6164// wrapper struct. It must run before function bodies are generated, so that fn
6165// signatures, return statements and call sites all agree on whether a given
6166// fixed-array return is wrapped. EVERY fixed-array type is wrapped, because C
6167// functions and fn pointers cannot return a raw array type regardless of the element:
6168// primitive/pointer/enum element wrappers are emitted early (before structs), while
6169// struct/`string`/nested element wrappers are emitted by fixed_array_typedefs(), after
6170// the element type is defined.
6171fn (mut g FlatGen) populate_fixed_array_ret_wrappers() {
6172 needed := g.collect_fixed_array_typedefs_needed()
6173 for name, _ in needed {
6174 g.fixed_array_ret_wrappers[name] = true
6175 }
6176}
6177
6178// emit_fixed_array_ret_wrapper writes the one-field `struct { T ret_arr[N]; }` wrapper
6179// for a fixed-array return type. The element type's C definition must already be emitted.
6180// `tagged` completes a previously forward-declared named struct (`struct X { ... };`),
6181// used for non-early element types whose wrapper is referenced by an fn-pointer typedef
6182// emitted earlier; otherwise a fresh anonymous typedef is written.
6183fn (mut g FlatGen) emit_fixed_array_ret_wrapper(name string, info FixedArrayTypedefInfo, tagged bool) {
6184 arr := info.arr
6185 old_module := g.tc.cur_module
6186 g.tc.cur_module = info.module
6187 elem_ct := g.tc.c_type(arr.elem_type)
6188 len_expr := g.fixed_array_len_value(arr)
6189 g.tc.cur_module = old_module
6190 wname := fixed_array_ret_wrapper_name(name)
6191 if tagged {
6192 g.writeln('struct ${wname} { ${elem_ct} ret_arr[${len_expr}]; };')
6193 } else {
6194 g.writeln('typedef struct { ${elem_ct} ret_arr[${len_expr}]; } ${wname};')
6195 }
6196}
6197
6198// emit_fixed_array_ret_wrapper_forward forward-declares a named return-wrapper struct so an
6199// fn-pointer typedef can name it as a (by-value) return type before the wrapper's element
6200// type is defined; the struct body is completed later by emit_fixed_array_ret_wrapper.
6201fn (mut g FlatGen) emit_fixed_array_ret_wrapper_forward(name string) {
6202 wname := fixed_array_ret_wrapper_name(name)
6203 g.writeln('typedef struct ${wname} ${wname};')
6204}
6205
6206// fixed_array_early_typedefs emits, before the fn-ptr typedef block, the bare
6207// typedefs for fixed arrays whose element chain is a primitive/pointer/enum, plus
6208// a one-field struct wrapper `struct { T ret_arr[N]; }` for each fixed-array
6209// return type. fn-ptr typedefs may name a fixed array in param position (bare
6210// typedef) or return position (wrapper); both must therefore be defined first. C
6211// functions cannot return raw array types, hence the wrapper (as V1 does). Bare
6212// typedefs of struct/`string`-element fixed arrays are deferred to
6213// fixed_array_typedefs(), after the struct definitions.
6214fn (mut g FlatGen) fixed_array_early_typedefs() {
6215 needed := g.collect_fixed_array_typedefs_needed()
6216 mut names := []string{}
6217 for name, _ in needed {
6218 names << name
6219 }
6220 names.sort()
6221 mut emitted_any := false
6222 for name in names {
6223 info := needed[name] or { continue }
6224 if !fixed_array_typedef_is_early(info.arr) {
6225 continue
6226 }
6227 g.emit_fixed_array_typedef(name, info, needed, mut g.emitted_fixed_array_typedefs)
6228 emitted_any = true
6229 }
6230 // Wrapper structs for fixed-array return types. Primitive/pointer/enum element wrappers
6231 // are fully defined here. Struct/`string`/nested element wrappers can't be defined yet
6232 // (their element type comes later), but an fn-pointer typedef in the next block may name
6233 // one as a return type, so forward-declare the named struct now and complete it in
6234 // fixed_array_typedefs(), after the element definitions.
6235 for name in names {
6236 if name !in g.fixed_array_ret_wrappers {
6237 continue
6238 }
6239 info := needed[name] or { continue }
6240 if fixed_array_typedef_is_early(info.arr) {
6241 g.emit_fixed_array_ret_wrapper(name, info, false)
6242 } else {
6243 g.emit_fixed_array_ret_wrapper_forward(name)
6244 }
6245 emitted_any = true
6246 }
6247 if emitted_any {
6248 g.writeln('')
6249 }
6250}
6251
6252// fixed_array_ret_wrapper_name is the struct name wrapping a fixed-array return.
6253fn fixed_array_ret_wrapper_name(bare_c_name string) string {
6254 return '_v_ret_${bare_c_name}'
6255}
6256
6257// fixed_array_elem_is_early_complete reports whether a fixed-array element type's
6258// C definition is available before the fn_ptr/return-wrapper typedef block (i.e.
6259// it is a primitive, pointer, or enum — not a struct or nested fixed array, whose
6260// bare typedefs/definitions are emitted later).
6261fn fixed_array_elem_is_early_complete(elem types.Type) bool {
6262 return elem is types.Primitive || elem is types.Pointer || elem is types.Enum
6263}
6264
6265// fn_return_type_name is the C type to write for a function/fn-ptr return type,
6266// substituting the fixed-array wrapper struct when one exists.
6267fn (mut g FlatGen) fn_return_type_name(t types.Type) string {
6268 if t is types.ArrayFixed {
6269 bare := g.tc.c_type(t)
6270 if bare in g.fixed_array_ret_wrappers {
6271 return fixed_array_ret_wrapper_name(bare)
6272 }
6273 }
6274 ct := g.optional_type_name(t)
6275 // A function/fn-ptr-valued return (`fn f() fn () int`) has the internal `fn_ptr:...`
6276 // encoding for its C type; map it to the shared `_fn_ptr_N` typedef, since a C function
6277 // cannot be declared returning that raw encoding (it would emit invalid C).
6278 if ct.starts_with('fn_ptr:') {
6279 return g.resolve_fn_ptr_type(ct)
6280 }
6281 return ct
6282}
6283
6284// fn_ptr_return_ct maps a fixed-array return c_type name (string form, used by the
6285// fn-ptr typedef machinery) to its wrapper struct name when one exists.
6286fn (g &FlatGen) fn_ptr_return_ct(ct string) string {
6287 if ct.starts_with('Array_fixed_') && ct in g.fixed_array_ret_wrappers {
6288 return fixed_array_ret_wrapper_name(ct)
6289 }
6290 return ct
6291}
6292
6293// emit_ready_fixed_array_typedefs emits, during the topological struct emission,
6294// any fixed-array bare typedef whose element type is now fully defined (i.e. its
6295// element struct has been emitted). Struct fields reference the typedef name
6296// (`Array_fixed_vec__Vec4_f32 x`), so the typedef must precede any struct that
6297// uses it — which a single later pass cannot guarantee.
6298fn (mut g FlatGen) emit_ready_fixed_array_typedefs(needed map[string]FixedArrayTypedefInfo, emitted_structs map[string]bool) {
6299 for name, info in needed {
6300 if g.emitted_fixed_array_typedefs[name] {
6301 continue
6302 }
6303 if g.fixed_array_elem_defined(info.arr, emitted_structs) {
6304 g.emit_fixed_array_typedef(name, info, needed, mut g.emitted_fixed_array_typedefs)
6305 }
6306 }
6307}
6308
6309// fixed_array_elem_defined reports whether a fixed array's element type is fully
6310// available: a primitive/pointer/enum (always), or a struct/`string` already
6311// emitted. Aliases are unwrapped to their underlying type first (`SimdFloat4` ->
6312// `vec.Vec4[f32]` struct), so an alias to a not-yet-emitted struct is not treated
6313// as ready.
6314fn (g &FlatGen) fixed_array_elem_defined(arr types.ArrayFixed, emitted_structs map[string]bool) bool {
6315 return g.fixed_array_type_defined(arr.elem_type, emitted_structs)
6316}
6317
6318fn (g &FlatGen) fixed_array_type_defined(typ0 types.Type, emitted_structs map[string]bool) bool {
6319 mut typ := typ0
6320 for typ is types.Alias {
6321 typ = typ.base_type
6322 }
6323 if typ is types.ArrayFixed {
6324 return g.fixed_array_type_defined(typ.elem_type, emitted_structs)
6325 }
6326 if typ is types.Struct {
6327 return g.tc.c_type(typ) in emitted_structs
6328 }
6329 if typ is types.String {
6330 return 'string' in emitted_structs
6331 }
6332 return true
6333}
6334
6335fn (mut g FlatGen) fixed_array_typedef_type_module(name string, fallback string) string {
6336 if info := g.struct_decl_infos[name] {
6337 return info.module
6338 }
6339 mod := module_from_qualified_name(name)
6340 if mod.len > 0 {
6341 return mod
6342 }
6343 return fallback
6344}
6345
6346fn module_from_qualified_name(name string) string {
6347 if name.contains('.') {
6348 return name.all_before_last('.')
6349 }
6350 if name.contains('__') {
6351 return name.all_before_last('__').replace('__', '.')
6352 }
6353 return ''
6354}
6355
6356fn fixed_array_typedef_module_priority(module_name string) int {
6357 if module_name.len == 0 || module_name == 'C' {
6358 return 0
6359 }
6360 if module_name == 'main' || module_name == 'builtin' {
6361 return 1
6362 }
6363 return 2
6364}
6365
6366fn (mut g FlatGen) collect_fixed_array_typedef(typ types.Type, mut needed map[string]FixedArrayTypedefInfo) {
6367 if typ is types.ArrayFixed {
6368 name := g.tc.c_type(typ)
6369 existing_priority := if name in needed {
6370 fixed_array_typedef_module_priority(needed[name].module)
6371 } else {
6372 -1
6373 }
6374 current_priority := fixed_array_typedef_module_priority(g.tc.cur_module)
6375 if name !in needed || current_priority > existing_priority {
6376 needed[name] = FixedArrayTypedefInfo{
6377 arr: typ
6378 module: g.tc.cur_module
6379 }
6380 }
6381 g.collect_fixed_array_typedef(typ.elem_type, mut needed)
6382 } else if typ is types.Pointer {
6383 g.collect_fixed_array_typedef(typ.base_type, mut needed)
6384 } else if typ is types.Alias {
6385 g.collect_fixed_array_typedef(typ.base_type, mut needed)
6386 } else if typ is types.OptionType {
6387 g.collect_fixed_array_typedef(typ.base_type, mut needed)
6388 } else if typ is types.ResultType {
6389 g.collect_fixed_array_typedef(typ.base_type, mut needed)
6390 } else if typ is types.Array {
6391 g.collect_fixed_array_typedef(typ.elem_type, mut needed)
6392 } else if typ is types.Map {
6393 g.collect_fixed_array_typedef(typ.key_type, mut needed)
6394 g.collect_fixed_array_typedef(typ.value_type, mut needed)
6395 } else if typ is types.FnType {
6396 for param in typ.params {
6397 g.collect_fixed_array_typedef(param, mut needed)
6398 }
6399 g.collect_fixed_array_typedef(typ.return_type, mut needed)
6400 } else if typ is types.MultiReturn {
6401 for item in typ.types {
6402 g.collect_fixed_array_typedef(item, mut needed)
6403 }
6404 }
6405}
6406
6407fn (mut g FlatGen) collect_fixed_array_typedef_text(type_text string, mut needed map[string]FixedArrayTypedefInfo) {
6408 clean := type_text.trim_space()
6409 if clean.len == 0 {
6410 return
6411 }
6412 typ := g.tc.parse_type(clean)
6413 if fixed_array_typedef_has_non_decimal_len(typ) {
6414 return
6415 }
6416 g.collect_fixed_array_typedef(typ, mut needed)
6417}
6418
6419fn fixed_array_typedef_has_non_decimal_len(typ types.Type) bool {
6420 if typ is types.ArrayFixed {
6421 if typ.len_expr.len > 0 {
6422 return true
6423 }
6424 return fixed_array_typedef_has_non_decimal_len(typ.elem_type)
6425 }
6426 if typ is types.Pointer {
6427 return fixed_array_typedef_has_non_decimal_len(typ.base_type)
6428 }
6429 if typ is types.Alias {
6430 return fixed_array_typedef_has_non_decimal_len(typ.base_type)
6431 }
6432 if typ is types.OptionType {
6433 return fixed_array_typedef_has_non_decimal_len(typ.base_type)
6434 }
6435 if typ is types.ResultType {
6436 return fixed_array_typedef_has_non_decimal_len(typ.base_type)
6437 }
6438 if typ is types.Array {
6439 return fixed_array_typedef_has_non_decimal_len(typ.elem_type)
6440 }
6441 if typ is types.Map {
6442 return fixed_array_typedef_has_non_decimal_len(typ.key_type)
6443 || fixed_array_typedef_has_non_decimal_len(typ.value_type)
6444 }
6445 if typ is types.FnType {
6446 for param in typ.params {
6447 if fixed_array_typedef_has_non_decimal_len(param) {
6448 return true
6449 }
6450 }
6451 return fixed_array_typedef_has_non_decimal_len(typ.return_type)
6452 }
6453 if typ is types.MultiReturn {
6454 for item in typ.types {
6455 if fixed_array_typedef_has_non_decimal_len(item) {
6456 return true
6457 }
6458 }
6459 }
6460 return false
6461}
6462
6463fn (mut g FlatGen) emit_fixed_array_typedef(name string, info FixedArrayTypedefInfo, needed map[string]FixedArrayTypedefInfo, mut emitted map[string]bool) {
6464 if emitted[name] {
6465 return
6466 }
6467 arr := info.arr
6468 old_module := g.tc.cur_module
6469 g.tc.cur_module = info.module
6470 if arr.elem_type is types.ArrayFixed {
6471 inner_name := g.tc.c_type(arr.elem_type)
6472 if inner := needed[inner_name] {
6473 g.emit_fixed_array_typedef(inner_name, inner, needed, mut emitted)
6474 }
6475 }
6476 elem_ct := g.tc.c_type(arr.elem_type)
6477 len_expr := g.fixed_array_len_value(arr)
6478 g.writeln('typedef ${elem_ct} ${name}[${len_expr}];')
6479 g.tc.cur_module = old_module
6480 emitted[name] = true
6481}
6482
6483fn (mut g FlatGen) global_decls() {
6484 old_module := g.tc.cur_module
6485 for name, typ in g.global_types {
6486 if mod := g.global_modules[name] {
6487 g.tc.cur_module = mod
6488 } else {
6489 g.tc.cur_module = old_module
6490 }
6491 if typ is types.ArrayFixed {
6492 c_elem, dims := g.fixed_array_decl_parts(typ)
6493 init := if g.has_zero_sized_leading_init_slot(typ) { '' } else { ' = {0}' }
6494 g.writeln('${c_elem} ${c_name(name)}${dims}${init};')
6495 continue
6496 }
6497 mut ct := g.tc.c_type(typ)
6498 if ct == 'void' {
6499 continue
6500 }
6501 if ct.starts_with('fn_ptr:') {
6502 ct = g.resolve_fn_ptr_type(ct)
6503 }
6504 if name.starts_with('C.') {
6505 continue
6506 }
6507 init := if g.can_use_global_brace_zero_init(typ, ct) { ' = {0}' } else { '' }
6508 g.writeln('${ct} ${c_name(name)}${init};')
6509 }
6510 g.tc.cur_module = old_module
6511 if g.global_types.len > 0 {
6512 g.writeln('')
6513 }
6514 g.emit_global_inits()
6515}
6516
6517// emit_global_inits queues assignments for `__global x = expr` declarations into
6518// _vinit. The C globals are emitted zero-initialized above; their initializer
6519// expressions (often function calls like `new_timers(...)`) cannot be C static
6520// initializers, so they must run at startup. Without this, such globals stay
6521// NULL/zero and the first access segfaults.
6522//
6523// Plain initializers are emitted as `name = expr;`. Fixed-array globals are
6524// copied from a generated compound literal with `memmove`, since C arrays are
6525// not assignable. `&Struct{}` is emitted as a self-contained heap allocation
6526// (`(T*)memdup(&(T){...}, sizeof(T))`), so it is safe. Other prefix/array
6527// initializers that would need a dropped temporary are skipped, leaving the
6528// global zero/NULL -- no regression versus never initializing globals at all.
6529fn (mut g FlatGen) emit_global_inits() {
6530 old_module := g.tc.cur_module
6531 for qname in g.global_init_order {
6532 val_id := g.global_inits[qname] or { continue }
6533 if int(val_id) < 0 {
6534 continue
6535 }
6536 // g_main_argc/g_main_argv are filled in by main's preamble (from argc/argv)
6537 // *before* _vinit runs, and are zero by default in C anyway. Re-emitting their
6538 // `= 0` initializer here would clobber the real argv, leaving os.args empty.
6539 cqname := c_name(qname)
6540 if cqname == 'g_main_argc' || cqname == 'g_main_argv' {
6541 continue
6542 }
6543 if mod := g.global_modules[qname] {
6544 g.tc.cur_module = mod
6545 } else {
6546 g.tc.cur_module = old_module
6547 }
6548 if typ := g.global_types[qname] {
6549 if typ is types.ArrayFixed {
6550 target := c_name(qname)
6551 g.queue_fixed_array_runtime_init(target, val_id, typ)
6552 continue
6553 }
6554 }
6555 if !g.is_safe_global_init(val_id) {
6556 continue
6557 }
6558 tmp_sb := g.sb
6559 tmp_line_start := g.line_start
6560 g.sb = strings.new_builder(64)
6561 g.line_start = true
6562 g.gen_expr(val_id)
6563 expr_str := g.sb.str()
6564 g.sb = tmp_sb
6565 g.line_start = tmp_line_start
6566 if expr_str.trim_space().len == 0 {
6567 continue
6568 }
6569 target := c_name(qname)
6570 g.queue_runtime_init('\t${target} = ${expr_str};')
6571 if typ := g.global_types[qname] {
6572 if typ is types.Map {
6573 g.queue_map_literal_sets(target, val_id, typ)
6574 }
6575 }
6576 }
6577 g.tc.cur_module = old_module
6578}
6579
6580// is_safe_global_init reports whether a global initializer can be emitted as a
6581// self-contained `name = expr;` assignment in _vinit, i.e. without auxiliary
6582// declarations/temporaries that the global context cannot host.
6583fn (g &FlatGen) is_safe_global_init(val_id flat.NodeId) bool {
6584 if int(val_id) < 0 {
6585 return false
6586 }
6587 node := g.a.nodes[int(val_id)]
6588 if node.kind == .prefix {
6589 // `&Struct{}` becomes an inline `(T*)memdup(&(T){...}, sizeof(T))`, which is
6590 // self-contained; allow it. Other prefixes (e.g. `&local`) would need a
6591 // dropped temporary, so skip them.
6592 if node.op == .amp && node.children_count > 0 {
6593 child := g.a.nodes[int(g.a.child(&node, 0))]
6594 return child.kind == .struct_init || child.kind == .assoc
6595 }
6596 return false
6597 }
6598 return match node.kind {
6599 .array_literal, .array_init {
6600 // Array literals need a backing temp the transformer drops for globals;
6601 // leave them zero/NULL instead of emitting a reference to an undeclared
6602 // symbol.
6603 false
6604 }
6605 else {
6606 true
6607 }
6608 }
6609}
6610
6611fn (g &FlatGen) const_get_deps(val_id flat.NodeId) []string {
6612 mut deps := []string{}
6613 g.const_collect_deps(val_id, mut deps)
6614 return deps
6615}
6616
6617fn (g &FlatGen) const_collect_deps(val_id flat.NodeId, mut deps []string) {
6618 if int(val_id) < 0 || int(val_id) >= g.a.nodes.len {
6619 return
6620 }
6621 node := g.a.nodes[int(val_id)]
6622 if node.kind == .ident || node.kind == .selector {
6623 const_name := g.const_ref_name_from_node(node)
6624 if const_name.len > 0 {
6625 deps << const_name
6626 }
6627 }
6628 for i in 0 .. node.children_count {
6629 g.const_collect_deps(g.a.child(&node, i), mut deps)
6630 }
6631}
6632
6633fn (g &FlatGen) const_refs_other_const(val_id flat.NodeId) bool {
6634 if int(val_id) < 0 || int(val_id) >= g.a.nodes.len {
6635 return false
6636 }
6637 node := g.a.nodes[int(val_id)]
6638 if node.kind == .ident || node.kind == .selector {
6639 return g.const_ref_name_from_node(node).len > 0
6640 }
6641 for i in 0 .. node.children_count {
6642 if g.const_refs_other_const(g.a.child(&node, i)) {
6643 return true
6644 }
6645 }
6646 return false
6647}
6648
6649fn (mut g FlatGen) emit_const(name string, val_id flat.NodeId) {
6650 old_module := g.tc.cur_module
6651 if name in g.const_modules {
6652 g.tc.cur_module = g.const_modules[name]
6653 }
6654 val_node := g.a.nodes[int(val_id)]
6655 if val_node.kind == .empty {
6656 g.tc.cur_module = old_module
6657 return
6658 }
6659 v_type := if val_node.kind == .offsetof_expr {
6660 types.Type(types.usize_)
6661 } else {
6662 g.tc.resolve_type(val_id)
6663 }
6664 ct := g.tc.c_type(v_type)
6665 qname := g.const_ident_c_name(name)
6666 expr_str := if v_type is types.Array && val_node.kind == .array_literal {
6667 g.expr_to_string_with_expected_type(val_id, v_type)
6668 } else if g.is_const_expr(val_id) {
6669 g.const_expr_to_string(val_id, []string{})
6670 } else {
6671 g.expr_to_string(val_id)
6672 }
6673 if expr_str.trim_space().len == 0 {
6674 g.tc.cur_module = old_module
6675 return
6676 }
6677 mut is_static_const := g.is_const_expr(val_id) && !g.const_expr_needs_runtime_storage(expr_str)
6678 if v_type is types.Array {
6679 is_static_const = false
6680 }
6681 if v_type is types.ArrayFixed && v_type.elem_type is types.ArrayFixed {
6682 is_static_const = false
6683 }
6684 if !is_static_const {
6685 if v_type is types.ArrayFixed {
6686 c_elem, dims := g.fixed_array_decl_parts(v_type)
6687 g.writeln('${c_elem} ${qname}${dims};')
6688 g.queue_const_fixed_array_runtime_init(qname, val_id, v_type)
6689 } else if ct != 'void' {
6690 g.writeln('${ct} ${qname};')
6691 // The initializer is not a compile-time constant (e.g. `os.args =
6692 // arguments()`), so it cannot be a C static initializer. Run it at startup
6693 // in _vinit; otherwise the const stays zero/empty and first use is wrong.
6694 g.queue_const_runtime_init('\t${qname} = ${expr_str};')
6695 if v_type is types.Map {
6696 g.queue_const_map_literal_sets(qname, val_id, v_type)
6697 }
6698 }
6699 g.tc.cur_module = old_module
6700 return
6701 }
6702 if v_type is types.String {
6703 g.writeln('string ${qname} = ${expr_str};')
6704 } else if v_type is types.ArrayFixed {
6705 c_elem, dims := g.fixed_array_decl_parts(v_type)
6706 g.writeln('const ${c_elem} ${qname}${dims} = ${expr_str};')
6707 } else if v_type is types.Primitive || v_type is types.Char || v_type is types.Rune
6708 || v_type is types.ISize || v_type is types.USize || v_type is types.Enum
6709 || ct in ['bool', 'char', 'i8', 'i16', 'i32', 'int', 'i64', 'u8', 'u16', 'u32', 'u64', 'f32', 'f64', 'float', 'double', 'isize', 'usize'] {
6710 if qname == 'max_len' && ct == 'int' {
6711 g.writeln('enum { ${qname} = ${expr_str} };')
6712 } else if g.name_collides_with_struct_field(qname) {
6713 // A `#define` whose name matches a struct field would wrongly expand every
6714 // `.field` access; emit a real `const` variable instead (C keeps member and
6715 // ordinary-identifier namespaces separate, so there is no collision).
6716 g.writeln('static const ${ct} ${qname} = ${expr_str};')
6717 } else {
6718 g.writeln('#define ${qname} (${expr_str})')
6719 }
6720 } else {
6721 g.writeln('const ${ct} ${qname} = ${expr_str};')
6722 }
6723 g.tc.cur_module = old_module
6724}
6725
6726// name_collides_with_struct_field reports whether a name is the C name of any struct
6727// field, building the set lazily on first use.
6728fn (mut g FlatGen) name_collides_with_struct_field(name string) bool {
6729 if g.field_name_set.len == 0 {
6730 for _, fields in g.tc.structs {
6731 for f in fields {
6732 g.field_name_set[c_field_name(f.name)] = true
6733 }
6734 }
6735 // Guard against an all-fieldless program re-scanning every call.
6736 g.field_name_set[''] = true
6737 }
6738 return name in g.field_name_set
6739}
6740
6741fn (g &FlatGen) const_expr_needs_runtime_storage(expr string) bool {
6742 return expr.contains('array_new(') || expr.contains('new_map(') || expr.contains('({')
6743 || expr.contains('__map_')
6744}
6745
6746fn (mut g FlatGen) queue_map_literal_sets(target string, val_id flat.NodeId, map_type types.Map) {
6747 if int(val_id) < 0 || int(val_id) >= g.a.nodes.len {
6748 return
6749 }
6750 node := g.a.nodes[int(val_id)]
6751 if node.kind != .map_init {
6752 return
6753 }
6754 c_key := g.tc.c_type(map_type.key_type)
6755 c_val := g.tc.c_type(map_type.value_type)
6756 for i := 0; i + 1 < node.children_count; i += 2 {
6757 key := g.expr_to_string_with_expected_type(g.a.child(&node, i), map_type.key_type)
6758 val := g.expr_to_string_with_expected_type(g.a.child(&node, i + 1), map_type.value_type)
6759 g.queue_runtime_init('\tmap__set(&${target}, &(${c_key}[]){${key}}, &(${c_val}[]){${val}});')
6760 }
6761}
6762
6763fn (mut g FlatGen) queue_const_map_literal_sets(target string, val_id flat.NodeId, map_type types.Map) {
6764 if int(val_id) < 0 || int(val_id) >= g.a.nodes.len {
6765 return
6766 }
6767 node := g.a.nodes[int(val_id)]
6768 if node.kind != .map_init {
6769 return
6770 }
6771 c_key := g.tc.c_type(map_type.key_type)
6772 c_val := g.tc.c_type(map_type.value_type)
6773 for i := 0; i + 1 < node.children_count; i += 2 {
6774 key := g.expr_to_string_with_expected_type(g.a.child(&node, i), map_type.key_type)
6775 val := g.expr_to_string_with_expected_type(g.a.child(&node, i + 1), map_type.value_type)
6776 g.queue_const_runtime_init('\tmap__set(&${target}, &(${c_key}[]){${key}}, &(${c_val}[]){${val}});')
6777 }
6778}
6779
6780fn (mut g FlatGen) queue_fixed_array_runtime_init(target string, val_id flat.NodeId, fixed types.ArrayFixed) bool {
6781 expr := g.fixed_array_compound_literal_expr(val_id, fixed)
6782 if expr.trim_space().len == 0 {
6783 return false
6784 }
6785 g.queue_runtime_init('\tmemmove(${target}, ${expr}, sizeof(${target}));')
6786 return true
6787}
6788
6789fn (mut g FlatGen) queue_const_fixed_array_runtime_init(target string, val_id flat.NodeId, fixed types.ArrayFixed) bool {
6790 expr := g.fixed_array_compound_literal_expr(val_id, fixed)
6791 if expr.trim_space().len == 0 {
6792 return false
6793 }
6794 g.queue_const_runtime_init('\tmemmove(${target}, ${expr}, sizeof(${target}));')
6795 return true
6796}
6797
6798fn (mut g FlatGen) fixed_array_compound_literal_expr(val_id flat.NodeId, fixed types.ArrayFixed) string {
6799 init := g.fixed_array_initializer_string(val_id, fixed)
6800 if init.trim_space().len == 0 {
6801 return ''
6802 }
6803 c_elem, dims := g.fixed_array_decl_parts(fixed)
6804 return '(${c_elem}${dims})${init}'
6805}
6806
6807fn (mut g FlatGen) fixed_array_initializer_string(val_id flat.NodeId, fixed types.ArrayFixed) string {
6808 if int(val_id) < 0 || int(val_id) >= g.a.nodes.len {
6809 return ''
6810 }
6811 node := g.a.nodes[int(val_id)]
6812 if node.kind == .postfix && node.children_count > 0 {
6813 return g.fixed_array_initializer_string(g.a.child(&node, 0), fixed)
6814 }
6815 if node.kind == .array_init && node.children_count == 0 {
6816 return '{0}'
6817 }
6818 if node.kind != .array_literal {
6819 return ''
6820 }
6821 mut parts := []string{}
6822 for i in 0 .. node.children_count {
6823 child_id := g.a.child(&node, i)
6824 if fixed.elem_type is types.ArrayFixed {
6825 parts << g.fixed_array_initializer_string(child_id, fixed.elem_type)
6826 } else {
6827 parts << g.fixed_array_elem_initializer_string(child_id, fixed.elem_type)
6828 }
6829 }
6830 return '{${parts.join(', ')}}'
6831}
6832
6833fn (mut g FlatGen) fixed_array_elem_initializer_string(val_id flat.NodeId, elem_type types.Type) string {
6834 if int(val_id) < 0 || int(val_id) >= g.a.nodes.len {
6835 return '0'
6836 }
6837 node := g.a.nodes[int(val_id)]
6838 if g.is_const_expr(val_id) && !(node.kind == .prefix && node.op == .amp) {
6839 const_val := g.const_expr_to_string(val_id, []string{})
6840 if const_val.trim_space().len > 0 {
6841 return const_val
6842 }
6843 }
6844 expr := g.expr_to_string_with_expected_type(val_id, elem_type)
6845 if expr.trim_space().len > 0 {
6846 return expr
6847 }
6848 return '0'
6849}
6850
6851fn (mut g FlatGen) precompute_consts() string {
6852 old_sb := g.sb
6853 old_line_start := g.line_start
6854 g.sb = strings.new_builder(1024)
6855 g.line_start = true
6856 mut emitted := map[string]bool{}
6857 mut deferred := []string{}
6858 mut names := g.const_init_order.clone()
6859 for name, _ in g.const_vals {
6860 if g.is_const_alias_name(name) || name in names {
6861 continue
6862 }
6863 names << name
6864 }
6865 names = g.ordered_const_init_names(names)
6866 for name in names {
6867 val_id := g.const_vals[name] or { continue }
6868 if g.is_const_alias_name(name) {
6869 continue
6870 }
6871 if int(val_id) < 0 || int(val_id) >= g.a.nodes.len {
6872 continue
6873 }
6874 old_module := g.tc.cur_module
6875 if name in g.const_modules {
6876 g.tc.cur_module = g.const_modules[name]
6877 }
6878 deps := g.const_get_deps(val_id)
6879 g.tc.cur_module = old_module
6880 mut all_met := true
6881 for dep in deps {
6882 if dep !in emitted {
6883 all_met = false
6884 break
6885 }
6886 }
6887 if !all_met {
6888 deferred << name
6889 } else {
6890 g.emit_const(name, val_id)
6891 emitted[name] = true
6892 }
6893 }
6894 for _ in 0 .. 20 {
6895 if deferred.len == 0 {
6896 break
6897 }
6898 mut remaining := []string{}
6899 for name in deferred {
6900 val_id := g.const_vals[name]
6901 deps := g.const_get_deps(val_id)
6902 mut all_met := true
6903 for dep in deps {
6904 if dep !in emitted {
6905 all_met = false
6906 break
6907 }
6908 }
6909 if all_met {
6910 g.emit_const(name, val_id)
6911 emitted[name] = true
6912 } else {
6913 remaining << name
6914 }
6915 }
6916 deferred = remaining.clone()
6917 }
6918 for name in deferred {
6919 g.emit_const(name, g.const_vals[name])
6920 }
6921 if g.const_vals.len > 0 {
6922 g.writeln('')
6923 }
6924 result := g.sb.str()
6925 // `.str()` copies out of the temporary const builder.
6926 unsafe { g.sb.free() }
6927 g.sb = old_sb
6928 g.line_start = old_line_start
6929 return result
6930}
6931
6932fn (g &FlatGen) ordered_const_init_names(names []string) []string {
6933 mut names_by_module := map[string][]string{}
6934 mut module_order := []string{}
6935 for name in names {
6936 mod := g.const_modules[name] or { '' }
6937 if mod !in names_by_module {
6938 names_by_module[mod] = []string{}
6939 module_order << mod
6940 }
6941 names_by_module[mod] << name
6942 }
6943 mut result := []string{}
6944 mut visiting := map[string]bool{}
6945 mut visited := map[string]bool{}
6946 for mod in module_order {
6947 g.visit_const_init_module(mod, names_by_module, mut visiting, mut visited, mut result)
6948 }
6949 return result
6950}
6951
6952fn (g &FlatGen) visit_const_init_module(mod string, names_by_module map[string][]string, mut visiting map[string]bool, mut visited map[string]bool, mut result []string) {
6953 if mod in visited || mod in visiting {
6954 return
6955 }
6956 visiting[mod] = true
6957 for dep in g.module_imports[mod] or { []string{} } {
6958 dep_module := startup_module_key(dep)
6959 if dep_module in names_by_module {
6960 g.visit_const_init_module(dep_module, names_by_module, mut visiting, mut visited, mut
6961 result)
6962 }
6963 }
6964 visiting.delete(mod)
6965 visited[mod] = true
6966 if module_names := names_by_module[mod] {
6967 result << module_names
6968 }
6969}
6970
6971fn startup_module_key(mod string) string {
6972 if mod.contains('.') {
6973 return mod.all_after_last('.')
6974 }
6975 return mod
6976}
6977
6978fn (g &FlatGen) is_const_expr(id flat.NodeId) bool {
6979 if int(id) < 0 || int(id) >= g.a.nodes.len {
6980 return false
6981 }
6982 node := g.a.nodes[int(id)]
6983 return match node.kind {
6984 .int_literal, .float_literal, .bool_literal, .char_literal, .string_literal, .enum_val,
6985 .sizeof_expr, .offsetof_expr {
6986 true
6987 }
6988 .prefix {
6989 if node.op == .amp {
6990 false
6991 } else {
6992 g.is_const_expr(g.a.child(&node, 0))
6993 }
6994 }
6995 .infix {
6996 g.is_const_expr(g.a.child(&node, 0)) && g.is_const_expr(g.a.child(&node, 1))
6997 }
6998 .paren {
6999 g.is_const_expr(g.a.child(&node, 0))
7000 }
7001 .cast_expr {
7002 g.is_const_expr(g.a.child(&node, 0))
7003 }
7004 .ident {
7005 g.const_ref_name(node.value).len > 0
7006 }
7007 .selector {
7008 const_name := g.const_ref_name_from_node(node)
7009 if const_name.len > 0 {
7010 true
7011 } else if node.children_count > 0 {
7012 base := g.a.child_node(&node, 0)
7013 base.kind == .ident && base.value == 'C'
7014 } else {
7015 false
7016 }
7017 }
7018 .array_literal {
7019 mut all_const := true
7020 for ci in 0 .. node.children_count {
7021 if !g.is_const_expr(g.a.child(&node, ci)) {
7022 all_const = false
7023 break
7024 }
7025 }
7026 all_const
7027 }
7028 .struct_init {
7029 mut all_const := true
7030 for ci in 0 .. node.children_count {
7031 child := g.a.child_node(&node, ci)
7032 if child.kind == .field_init {
7033 if ftyp := g.struct_field_type(node.value, child.value) {
7034 if ftyp is types.Array || ftyp is types.Map {
7035 all_const = false
7036 break
7037 }
7038 }
7039 }
7040 if child.children_count > 0 && !g.is_const_expr(g.a.child(child, 0)) {
7041 all_const = false
7042 break
7043 }
7044 }
7045 all_const
7046 }
7047 else {
7048 false
7049 }
7050 }
7051}
7052
7053fn (g &FlatGen) is_runtime_assignable(id flat.NodeId) bool {
7054 if int(id) < 0 || int(id) >= g.a.nodes.len {
7055 return false
7056 }
7057 node := g.a.nodes[int(id)]
7058 return match node.kind {
7059 .string_literal, .string_interp {
7060 true
7061 }
7062 .call {
7063 g.is_runtime_assignable_call(&node)
7064 }
7065 .ident {
7066 true
7067 }
7068 .or_expr {
7069 true
7070 }
7071 .infix {
7072 if node.children_count >= 2 {
7073 lhs_type := g.tc.resolve_type(g.a.child(&node, 0))
7074 rhs_type := g.tc.resolve_type(g.a.child(&node, 1))
7075 lhs_type is types.String || rhs_type is types.String
7076 } else {
7077 false
7078 }
7079 }
7080 .cast_expr, .prefix, .struct_init, .map_init {
7081 true
7082 }
7083 else {
7084 false
7085 }
7086 }
7087}
7088
7089fn (g &FlatGen) is_runtime_assignable_call(node &flat.Node) bool {
7090 if node.children_count == 0 {
7091 return false
7092 }
7093 callee_id := g.a.child(node, 0)
7094 if int(callee_id) < 0 {
7095 return false
7096 }
7097 callee := g.a.nodes[int(callee_id)]
7098 return callee.kind == .ident || callee.kind == .selector
7099}
7100
7101fn (g &FlatGen) op_str(op flat.Op) string {
7102 return match op {
7103 .plus { '+' }
7104 .minus { '-' }
7105 .mul { '*' }
7106 .div { '/' }
7107 .mod { '%' }
7108 .eq { '==' }
7109 .ne { '!=' }
7110 .lt { '<' }
7111 .gt { '>' }
7112 .le { '<=' }
7113 .ge { '>=' }
7114 .amp { '&' }
7115 .pipe { '|' }
7116 .xor { '^' }
7117 .left_shift { '<<' }
7118 .right_shift { '>>' }
7119 .right_shift_unsigned { '>>' }
7120 .logical_and { '&&' }
7121 .logical_or { '||' }
7122 .not { '!' }
7123 .bit_not { '~' }
7124 .assign { '=' }
7125 .plus_assign { '+=' }
7126 .minus_assign { '-=' }
7127 .mul_assign { '*=' }
7128 .div_assign { '/=' }
7129 .mod_assign { '%=' }
7130 .amp_assign { '&=' }
7131 .pipe_assign { '|=' }
7132 .xor_assign { '^=' }
7133 .left_shift_assign { '<<=' }
7134 .right_shift_assign { '>>=' }
7135 .right_shift_unsigned_assign { '>>=' }
7136 .inc { '++' }
7137 .dec { '--' }
7138 .dot { '.' }
7139 .arrow { '->' }
7140 .none { '' }
7141 }
7142}
7143
7144fn (mut g FlatGen) write(s string) {
7145 if g.line_start {
7146 g.write_indent()
7147 }
7148 if s.len == 0 {
7149 if g.indent > 0 {
7150 g.line_start = false
7151 }
7152 return
7153 }
7154 g.sb.write_string(s)
7155 g.line_start = s[s.len - 1] == `\n`
7156}
7157
7158fn (mut g FlatGen) writeln(s string) {
7159 if s.len > 0 {
7160 if g.line_start {
7161 g.write_indent()
7162 }
7163 g.sb.write_string(s)
7164 }
7165 g.sb.write_string('\n')
7166 g.line_start = true
7167}
7168
7169fn (mut g FlatGen) write_indent() {
7170 for _ in 0 .. g.indent {
7171 g.sb.write_string('\t')
7172 }
7173}
7174