v / vlib / v2 / builder / freestanding.v
1030 lines · 992 sloc · 28.68 KB · 34038bec7b93f4e3ddbbdcbe88ea21f4693eee43
Raw
1// Copyright (c) 2020-2024 Joe Conigliaro. All rights reserved.
2// Use of this source code is governed by an MIT license
3// that can be found in the LICENSE file.
4module builder
5
6import v2.ast
7import v2.pref
8import v2.token
9
10fn (b &Builder) validate_freestanding_cleanc_contract() bool {
11 if b.pref == unsafe { nil } || !b.pref.is_freestanding() {
12 return true
13 }
14 mut diagnostics := []string{}
15 mut seen := map[string]bool{}
16 target_os := b.pref.target_os_or_host()
17 if b.pref.prealloc {
18 msg := 'error: freestanding target cannot use -prealloc because it requires hosted allocation support'
19 diagnostics << msg
20 seen[msg] = true
21 }
22 if b.pref.is_shared_lib {
23 msg := 'error: freestanding target cannot use -shared because dynamic library output requires hosted loader support'
24 if !seen[msg] {
25 diagnostics << msg
26 seen[msg] = true
27 }
28 }
29 if b.pref.hot_fn.len > 0 {
30 msg := 'error: freestanding target cannot use -hot-fn because live code reload needs hosted OS services'
31 if !seen[msg] {
32 diagnostics << msg
33 seen[msg] = true
34 }
35 }
36 if b.pref.has_freestanding_hooks() && (!b.pref.skip_builtin || !b.pref.skip_type_check) {
37 msg := 'error: freestanding target platform hooks currently require --skip-builtin and --skip-type-check until cleanc builtin hook signatures are implemented'
38 if !seen[msg] {
39 diagnostics << msg
40 seen[msg] = true
41 }
42 }
43 scan_ctx := freestanding_scan_context(b.pref, target_os)
44 allow_pkgconfig_imports := !b.pref.is_cross_target()
45 for i, ff in b.flat.files {
46 if !b.should_scan_freestanding_diagnostic_file(b.flat.file_name(ff)) {
47 continue
48 }
49 for imported in active_file_imports_from_flat_with_options(&b.flat, ff,
50 b.pref.user_defines, b.pref.explicit_user_defines, target_os, allow_pkgconfig_imports) {
51 if msg := freestanding_restricted_import_diagnostic(imported.name) {
52 if !seen[msg] {
53 diagnostics << msg
54 seen[msg] = true
55 }
56 }
57 }
58 call_name := freestanding_restricted_call_in_cursor_stmts(b.flat.file_cursor(i).stmts(),
59 scan_ctx)
60 if call_name != '' {
61 msg := freestanding_restricted_call_diagnostic(call_name)
62 if !seen[msg] {
63 diagnostics << msg
64 seen[msg] = true
65 }
66 }
67 }
68 for msg in diagnostics {
69 eprintln(msg)
70 }
71 if diagnostics.len > 0 {
72 eprintln('hint: provide platform bindings or build without -freestanding')
73 return false
74 }
75 return true
76}
77
78fn (b &Builder) should_scan_freestanding_diagnostic_file(file_name string) bool {
79 if file_name == '' || b.pref == unsafe { nil } || b.pref.vroot == '' {
80 return true
81 }
82 path := file_name.replace('\\', '/')
83 vroot := b.pref.vroot.replace('\\', '/').trim_right('/')
84 return !path.starts_with('${vroot}/vlib/')
85}
86
87fn freestanding_restricted_import_diagnostic(import_name string) ?string {
88 root := import_name.all_before('.')
89 return match root {
90 'os' {
91 'error: freestanding target cannot use module os without a platform implementation'
92 }
93 'time' {
94 'error: freestanding target cannot use module time without a platform time source'
95 }
96 'term' {
97 'error: freestanding target cannot use module term without terminal support'
98 }
99 'net' {
100 'error: freestanding target cannot use module net without platform networking support'
101 }
102 'sync' {
103 'error: freestanding target cannot use module sync without threading/locking support'
104 }
105 else {
106 none
107 }
108 }
109}
110
111fn freestanding_restricted_call_diagnostic(call_name string) string {
112 return match call_name {
113 'panic' {
114 'error: freestanding target cannot use builtin panic without panic platform hook'
115 }
116 'spawn' {
117 'error: freestanding target cannot use spawn because threading support is not provided'
118 }
119 'go' {
120 'error: freestanding target cannot use go because threading support is not provided'
121 }
122 'lock' {
123 'error: freestanding target cannot use lock/rlock because locking support is not provided'
124 }
125 'shared' {
126 'error: freestanding target cannot use shared data because locking support is not provided'
127 }
128 'live' {
129 'error: freestanding target cannot use @[live] because live reload needs hosted OS services'
130 }
131 'assert' {
132 'error: freestanding target cannot use assert because failed assertions need hosted output/exit support'
133 }
134 else {
135 'error: freestanding target cannot use builtin ${call_name} without output platform hook'
136 }
137 }
138}
139
140struct FreestandingScanContext {
141 user_defines []string
142 explicit_defines []string
143 target_os string
144 freestanding_hooks []string
145}
146
147fn freestanding_scan_context(p &pref.Preferences, target_os string) FreestandingScanContext {
148 return FreestandingScanContext{
149 user_defines: p.user_defines
150 explicit_defines: p.explicit_user_defines
151 target_os: target_os
152 freestanding_hooks: p.freestanding_hook_list()
153 }
154}
155
156fn (ctx FreestandingScanContext) has_hook(hook string) bool {
157 return hook in ctx.freestanding_hooks
158}
159
160fn freestanding_output_builtin_call_name(name string, ctx FreestandingScanContext) string {
161 if name in ['print', 'println', 'eprint', 'eprintln'] && !ctx.has_hook('output') {
162 return name
163 }
164 if name == 'panic' && !ctx.has_hook('panic') {
165 return name
166 }
167 return ''
168}
169
170fn freestanding_attributes_are_inactive(attributes []ast.Attribute, ctx FreestandingScanContext) bool {
171 for attr in attributes {
172 if attr.comptime_cond !is ast.EmptyExpr
173 && !ast_comptime_cond_matches_with_explicit(attr.comptime_cond, ctx.user_defines, ctx.explicit_defines, ctx.target_os) {
174 return true
175 }
176 }
177 return false
178}
179
180fn freestanding_channel_scan_options(ctx FreestandingScanContext) ChannelScanOptions {
181 return ChannelScanOptions{
182 user_defines: ctx.user_defines
183 explicit_user_defines: ctx.explicit_defines
184 target_os: ctx.target_os
185 allow_pkgconfig: true
186 filter_comptime: true
187 }
188}
189
190fn freestanding_cursor_attributes_are_inactive(attributes ast.CursorList, ctx FreestandingScanContext) bool {
191 options := freestanding_channel_scan_options(ctx)
192 for i in 0 .. attributes.len() {
193 attr := attributes.at(i)
194 if !attr.is_valid() || attr.kind() != .aux_attribute {
195 continue
196 }
197 cond := attr.edge(1)
198 if cond.is_valid() && cond.kind() != .expr_empty
199 && !flat_comptime_cond_matches(cond, options) {
200 return true
201 }
202 }
203 return false
204}
205
206fn freestanding_cursor_attributes_has(attributes ast.CursorList, name string) bool {
207 for i in 0 .. attributes.len() {
208 attr := attributes.at(i)
209 if !attr.is_valid() || attr.kind() != .aux_attribute {
210 continue
211 }
212 if attr.name() == name {
213 return true
214 }
215 value := attr.edge(0)
216 if attr.name() == '' && value.is_valid() && value.kind() == .expr_ident
217 && value.name() == name {
218 return true
219 }
220 }
221 return false
222}
223
224fn freestanding_restricted_call_in_stmts(stmts []ast.Stmt, ctx FreestandingScanContext) string {
225 for stmt in stmts {
226 call_name := freestanding_restricted_call_in_stmt(stmt, ctx)
227 if call_name != '' {
228 return call_name
229 }
230 }
231 return ''
232}
233
234fn freestanding_restricted_call_in_cursor_stmts(stmts ast.CursorList, ctx FreestandingScanContext) string {
235 for i in 0 .. stmts.len() {
236 call_name := freestanding_restricted_call_in_cursor_stmt(stmts.at(i), ctx)
237 if call_name != '' {
238 return call_name
239 }
240 }
241 return ''
242}
243
244fn freestanding_restricted_call_in_cursor_stmt(stmt ast.Cursor, ctx FreestandingScanContext) string {
245 if !stmt.is_valid() {
246 return ''
247 }
248 return match stmt.kind() {
249 .stmt_assert {
250 expr_call :=
251 freestanding_restricted_call_in_cursor_edges(stmt, 0, stmt.edge_count(), ctx)
252 if expr_call != '' {
253 expr_call
254 } else {
255 'assert'
256 }
257 }
258 .stmt_assign {
259 freestanding_restricted_call_in_cursor_edges(stmt, 0, stmt.edge_count(), ctx)
260 }
261 .stmt_block, .stmt_defer {
262 freestanding_restricted_call_in_cursor_stmt_edges(stmt, 0, stmt.edge_count(), ctx)
263 }
264 .stmt_comptime {
265 freestanding_restricted_call_in_cursor_stmt(stmt.edge(0), ctx)
266 }
267 .stmt_const_decl {
268 freestanding_restricted_call_in_cursor_field_inits(stmt.list_at(0), ctx)
269 }
270 .stmt_expr {
271 freestanding_restricted_call_in_cursor_expr(stmt.edge(0), ctx)
272 }
273 .stmt_fn_decl {
274 attributes := stmt.list_at(2)
275 if freestanding_cursor_attributes_are_inactive(attributes, ctx) {
276 ''
277 } else if freestanding_cursor_attributes_has(attributes, 'live') {
278 'live'
279 } else {
280 freestanding_restricted_call_in_cursor_stmts(stmt.list_at(3), ctx)
281 }
282 }
283 .stmt_for_in {
284 freestanding_restricted_call_in_cursor_edges(stmt, 0, stmt.edge_count(), ctx)
285 }
286 .stmt_for {
287 init_call := freestanding_restricted_call_in_cursor_stmt(stmt.edge(0), ctx)
288 if init_call != '' {
289 init_call
290 } else {
291 cond_call := freestanding_restricted_call_in_cursor_expr(stmt.edge(1), ctx)
292 if cond_call != '' {
293 cond_call
294 } else {
295 post_call := freestanding_restricted_call_in_cursor_stmt(stmt.edge(2), ctx)
296 if post_call != '' {
297 post_call
298 } else {
299 freestanding_restricted_call_in_cursor_stmts(stmt.for_body_list(), ctx)
300 }
301 }
302 }
303 }
304 .stmt_global_decl {
305 freestanding_restricted_call_in_cursor_field_decls(stmt.list_at(1), ctx)
306 }
307 .stmt_interface_decl {
308 freestanding_restricted_call_in_cursor_field_decls(stmt.list_at(3), ctx)
309 }
310 .stmt_label {
311 freestanding_restricted_call_in_cursor_stmt(stmt.edge(0), ctx)
312 }
313 .stmt_return {
314 freestanding_restricted_call_in_cursor_edges(stmt, 0, stmt.edge_count(), ctx)
315 }
316 .stmt_struct_decl {
317 freestanding_restricted_call_in_cursor_field_decls(stmt.list_at(4), ctx)
318 }
319 else {
320 ''
321 }
322 }
323}
324
325fn freestanding_restricted_call_in_cursor_stmt_edges(stmt ast.Cursor, start int, end int, ctx FreestandingScanContext) string {
326 for i in start .. end {
327 call_name := freestanding_restricted_call_in_cursor_stmt(stmt.edge(i), ctx)
328 if call_name != '' {
329 return call_name
330 }
331 }
332 return ''
333}
334
335fn freestanding_restricted_call_in_cursor_edges(expr_parent ast.Cursor, start int, end int, ctx FreestandingScanContext) string {
336 for i in start .. end {
337 call_name := freestanding_restricted_call_in_cursor_expr(expr_parent.edge(i), ctx)
338 if call_name != '' {
339 return call_name
340 }
341 }
342 return ''
343}
344
345fn freestanding_restricted_call_in_cursor_expr_list(exprs ast.CursorList, ctx FreestandingScanContext) string {
346 for i in 0 .. exprs.len() {
347 call_name := freestanding_restricted_call_in_cursor_expr(exprs.at(i), ctx)
348 if call_name != '' {
349 return call_name
350 }
351 }
352 return ''
353}
354
355fn freestanding_restricted_call_in_stmt(stmt ast.Stmt, ctx FreestandingScanContext) string {
356 return match stmt {
357 ast.AssertStmt {
358 expr_call := freestanding_restricted_call_in_exprs([stmt.expr, stmt.extra], ctx)
359 if expr_call != '' {
360 expr_call
361 } else {
362 'assert'
363 }
364 }
365 ast.AssignStmt {
366 lhs_call := freestanding_restricted_call_in_exprs(stmt.lhs, ctx)
367 if lhs_call != '' {
368 lhs_call
369 } else {
370 freestanding_restricted_call_in_exprs(stmt.rhs, ctx)
371 }
372 }
373 ast.BlockStmt {
374 freestanding_restricted_call_in_stmts(stmt.stmts, ctx)
375 }
376 ast.ComptimeStmt {
377 freestanding_restricted_call_in_stmt(stmt.stmt, ctx)
378 }
379 ast.ConstDecl {
380 freestanding_restricted_call_in_field_inits(stmt.fields, ctx)
381 }
382 ast.DeferStmt {
383 freestanding_restricted_call_in_stmts(stmt.stmts, ctx)
384 }
385 ast.ExprStmt {
386 freestanding_restricted_call_in_expr(stmt.expr, ctx)
387 }
388 ast.FnDecl {
389 if freestanding_attributes_are_inactive(stmt.attributes, ctx) {
390 ''
391 } else if stmt.attributes.has('live') {
392 'live'
393 } else {
394 freestanding_restricted_call_in_stmts(stmt.stmts, ctx)
395 }
396 }
397 ast.ForInStmt {
398 freestanding_restricted_call_in_exprs([stmt.key, stmt.value, stmt.expr], ctx)
399 }
400 ast.ForStmt {
401 init_call := freestanding_restricted_call_in_stmt(stmt.init, ctx)
402 if init_call != '' {
403 init_call
404 } else {
405 cond_call := freestanding_restricted_call_in_expr(stmt.cond, ctx)
406 if cond_call != '' {
407 cond_call
408 } else {
409 post_call := freestanding_restricted_call_in_stmt(stmt.post, ctx)
410 if post_call != '' {
411 post_call
412 } else {
413 freestanding_restricted_call_in_stmts(stmt.stmts, ctx)
414 }
415 }
416 }
417 }
418 ast.GlobalDecl {
419 freestanding_restricted_call_in_field_decls(stmt.fields, ctx)
420 }
421 ast.InterfaceDecl {
422 freestanding_restricted_call_in_field_decls(stmt.fields, ctx)
423 }
424 ast.LabelStmt {
425 freestanding_restricted_call_in_stmt(stmt.stmt, ctx)
426 }
427 ast.ReturnStmt {
428 freestanding_restricted_call_in_exprs(stmt.exprs, ctx)
429 }
430 ast.StructDecl {
431 freestanding_restricted_call_in_field_decls(stmt.fields, ctx)
432 }
433 else {
434 ''
435 }
436 }
437}
438
439fn freestanding_restricted_call_in_exprs(exprs []ast.Expr, ctx FreestandingScanContext) string {
440 for expr in exprs {
441 call_name := freestanding_restricted_call_in_expr(expr, ctx)
442 if call_name != '' {
443 return call_name
444 }
445 }
446 return ''
447}
448
449fn freestanding_restricted_call_in_cursor_field_inits(fields ast.CursorList, ctx FreestandingScanContext) string {
450 for i in 0 .. fields.len() {
451 call_name := freestanding_restricted_call_in_cursor_expr(fields.at(i).edge(0), ctx)
452 if call_name != '' {
453 return call_name
454 }
455 }
456 return ''
457}
458
459fn freestanding_restricted_call_in_field_inits(fields []ast.FieldInit, ctx FreestandingScanContext) string {
460 for field in fields {
461 call_name := freestanding_restricted_call_in_expr(field.value, ctx)
462 if call_name != '' {
463 return call_name
464 }
465 }
466 return ''
467}
468
469fn freestanding_restricted_call_in_cursor_field_decls(fields ast.CursorList, ctx FreestandingScanContext) string {
470 for i in 0 .. fields.len() {
471 field := fields.at(i)
472 typ_call := freestanding_restricted_call_in_cursor_expr(field.edge(0), ctx)
473 if typ_call != '' {
474 return typ_call
475 }
476 value_call := freestanding_restricted_call_in_cursor_expr(field.edge(1), ctx)
477 if value_call != '' {
478 return value_call
479 }
480 }
481 return ''
482}
483
484fn freestanding_restricted_call_in_field_decls(fields []ast.FieldDecl, ctx FreestandingScanContext) string {
485 for field in fields {
486 typ_call := freestanding_restricted_call_in_expr(field.typ, ctx)
487 if typ_call != '' {
488 return typ_call
489 }
490 value_call := freestanding_restricted_call_in_expr(field.value, ctx)
491 if value_call != '' {
492 return value_call
493 }
494 }
495 return ''
496}
497
498fn freestanding_restricted_call_in_cursor_expr(expr ast.Cursor, ctx FreestandingScanContext) string {
499 if !expr.is_valid() {
500 return ''
501 }
502 return match expr.kind() {
503 .expr_array_init {
504 meta_call := freestanding_restricted_call_in_cursor_edges(expr, 0, 5, ctx)
505 if meta_call != '' {
506 meta_call
507 } else {
508 freestanding_restricted_call_in_cursor_edges(expr, 5, expr.edge_count(), ctx)
509 }
510 }
511 .expr_as_cast {
512 freestanding_restricted_call_in_cursor_expr(expr.edge(0), ctx)
513 }
514 .expr_cast {
515 freestanding_restricted_call_in_cursor_expr(expr.edge(1), ctx)
516 }
517 .expr_assoc {
518 base_call := freestanding_restricted_call_in_cursor_expr(expr.edge(1), ctx)
519 if base_call != '' {
520 base_call
521 } else {
522 freestanding_restricted_call_in_cursor_field_inits(ast.CursorList{
523 flat: expr.flat
524 parent_id: expr.id
525 offset: 2
526 }, ctx)
527 }
528 }
529 .expr_call {
530 call_name := freestanding_restricted_builtin_call_name_cursor(expr.edge(0), ctx)
531 if call_name != '' {
532 call_name
533 } else {
534 lhs_call := freestanding_restricted_call_in_cursor_expr(expr.edge(0), ctx)
535 if lhs_call != '' {
536 lhs_call
537 } else {
538 freestanding_restricted_call_in_cursor_edges(expr, 1, expr.edge_count(), ctx)
539 }
540 }
541 }
542 .expr_call_or_cast {
543 call_name := freestanding_restricted_builtin_call_name_cursor(expr.edge(0), ctx)
544 if call_name != '' {
545 call_name
546 } else {
547 lhs_call := freestanding_restricted_call_in_cursor_expr(expr.edge(0), ctx)
548 if lhs_call != '' {
549 lhs_call
550 } else {
551 freestanding_restricted_call_in_cursor_expr(expr.edge(1), ctx)
552 }
553 }
554 }
555 .expr_comptime {
556 freestanding_restricted_call_in_cursor_comptime_expr(expr, ctx)
557 }
558 .expr_fn_literal {
559 captured_len := expr.extra_int()
560 capture_call :=
561 freestanding_restricted_call_in_cursor_edges(expr, 1, 1 + captured_len, ctx)
562 if capture_call != '' {
563 capture_call
564 } else {
565 freestanding_restricted_call_in_cursor_stmt_edges(expr, 1 + captured_len,
566 expr.edge_count(), ctx)
567 }
568 }
569 .expr_generic_arg_or_index, .expr_index, .expr_infix {
570 lhs_call := freestanding_restricted_call_in_cursor_expr(expr.edge(0), ctx)
571 if lhs_call != '' {
572 lhs_call
573 } else {
574 freestanding_restricted_call_in_cursor_expr(expr.edge(1), ctx)
575 }
576 }
577 .expr_generic_args {
578 lhs_call := freestanding_restricted_call_in_cursor_expr(expr.edge(0), ctx)
579 if lhs_call != '' {
580 lhs_call
581 } else {
582 freestanding_restricted_call_in_cursor_edges(expr, 1, expr.edge_count(), ctx)
583 }
584 }
585 .expr_if {
586 cond_call := freestanding_restricted_call_in_cursor_expr(expr.edge(0), ctx)
587 if cond_call != '' {
588 cond_call
589 } else {
590 stmts_call := freestanding_restricted_call_in_cursor_stmt_edges(expr, 2,
591 expr.edge_count(), ctx)
592 if stmts_call != '' {
593 stmts_call
594 } else {
595 freestanding_restricted_call_in_cursor_expr(expr.edge(1), ctx)
596 }
597 }
598 }
599 .expr_if_guard {
600 freestanding_restricted_call_in_cursor_stmt(expr.edge(0), ctx)
601 }
602 .expr_init {
603 typ_call := freestanding_restricted_call_in_cursor_expr(expr.edge(0), ctx)
604 if typ_call != '' {
605 typ_call
606 } else {
607 freestanding_restricted_call_in_cursor_field_inits(ast.CursorList{
608 flat: expr.flat
609 parent_id: expr.id
610 offset: 1
611 }, ctx)
612 }
613 }
614 .expr_keyword_operator {
615 op := unsafe { token.Token(int(expr.aux())) }
616 if op in [.key_go, .key_spawn] {
617 op.str()
618 } else {
619 freestanding_restricted_call_in_cursor_edges(expr, 0, expr.edge_count(), ctx)
620 }
621 }
622 .expr_lambda, .expr_paren, .expr_postfix, .expr_prefix, .expr_selector {
623 freestanding_restricted_call_in_cursor_expr(expr.edge(0), ctx)
624 }
625 .expr_lock {
626 'lock'
627 }
628 .expr_map_init {
629 keys_len := expr.extra_int()
630 key_call := freestanding_restricted_call_in_cursor_edges(expr, 1, 1 + keys_len, ctx)
631 if key_call != '' {
632 key_call
633 } else {
634 freestanding_restricted_call_in_cursor_edges(expr, 1 + keys_len, expr.edge_count(),
635 ctx)
636 }
637 }
638 .expr_match {
639 expr_call := freestanding_restricted_call_in_cursor_expr(expr.edge(0), ctx)
640 if expr_call != '' {
641 expr_call
642 } else {
643 freestanding_restricted_call_in_cursor_match_branch_edges(expr, 1,
644 expr.edge_count(), ctx)
645 }
646 }
647 .expr_modifier {
648 kind := unsafe { token.Token(int(expr.aux())) }
649 if kind == .key_shared {
650 'shared'
651 } else {
652 freestanding_restricted_call_in_cursor_expr(expr.edge(0), ctx)
653 }
654 }
655 .expr_or {
656 expr_call := freestanding_restricted_call_in_cursor_expr(expr.edge(0), ctx)
657 if expr_call != '' {
658 expr_call
659 } else {
660 freestanding_restricted_call_in_cursor_stmt_edges(expr, 1, expr.edge_count(), ctx)
661 }
662 }
663 .expr_range {
664 start_call := freestanding_restricted_call_in_cursor_expr(expr.edge(0), ctx)
665 if start_call != '' {
666 start_call
667 } else {
668 freestanding_restricted_call_in_cursor_expr(expr.edge(1), ctx)
669 }
670 }
671 .expr_select {
672 stmt_call := freestanding_restricted_call_in_cursor_stmt(expr.edge(0), ctx)
673 if stmt_call != '' {
674 stmt_call
675 } else {
676 freestanding_restricted_call_in_cursor_stmt_edges(expr, 2, expr.edge_count(), ctx)
677 }
678 }
679 .expr_string_inter {
680 freestanding_restricted_call_in_cursor_string_inters(expr.list_at(1), ctx)
681 }
682 .expr_tuple {
683 freestanding_restricted_call_in_cursor_edges(expr, 0, expr.edge_count(), ctx)
684 }
685 .expr_unsafe {
686 freestanding_restricted_call_in_cursor_stmt_edges(expr, 0, expr.edge_count(), ctx)
687 }
688 .aux_field_init {
689 freestanding_restricted_call_in_cursor_expr(expr.edge(0), ctx)
690 }
691 else {
692 ''
693 }
694 }
695}
696
697fn freestanding_restricted_call_in_cursor_comptime_expr(expr ast.Cursor, ctx FreestandingScanContext) string {
698 inner := expr.edge(0)
699 if inner.is_valid() && inner.kind() == .expr_if {
700 return freestanding_restricted_call_in_cursor_active_comptime_if(inner, ctx)
701 }
702 return freestanding_restricted_call_in_cursor_expr(inner, ctx)
703}
704
705fn freestanding_restricted_call_in_cursor_active_comptime_if(node ast.Cursor, ctx FreestandingScanContext) string {
706 options := freestanding_channel_scan_options(ctx)
707 if flat_comptime_cond_matches(node.edge(0), options) {
708 return freestanding_restricted_call_in_cursor_stmt_edges(node, 2, node.edge_count(), ctx)
709 }
710 else_expr := node.edge(1)
711 if else_expr.is_valid() && else_expr.kind() == .expr_if {
712 if else_expr.edge(0).is_valid() && else_expr.edge(0).kind() == .expr_empty {
713 return freestanding_restricted_call_in_cursor_stmt_edges(else_expr, 2,
714 else_expr.edge_count(), ctx)
715 }
716 return freestanding_restricted_call_in_cursor_active_comptime_if(else_expr, ctx)
717 }
718 return ''
719}
720
721fn freestanding_restricted_call_in_cursor_match_branch_edges(expr ast.Cursor, start int, end int, ctx FreestandingScanContext) string {
722 for i in start .. end {
723 call_name := freestanding_restricted_call_in_cursor_match_branch(expr.edge(i), ctx)
724 if call_name != '' {
725 return call_name
726 }
727 }
728 return ''
729}
730
731fn freestanding_restricted_call_in_cursor_match_branch(branch ast.Cursor, ctx FreestandingScanContext) string {
732 if !branch.is_valid() || branch.kind() != .aux_match_branch {
733 return ''
734 }
735 cond_call := freestanding_restricted_call_in_cursor_expr_list(branch.list_at(0), ctx)
736 if cond_call != '' {
737 return cond_call
738 }
739 return freestanding_restricted_call_in_cursor_stmts(branch.list_at(1), ctx)
740}
741
742fn freestanding_restricted_call_in_cursor_string_inters(inters ast.CursorList, ctx FreestandingScanContext) string {
743 for i in 0 .. inters.len() {
744 inter := inters.at(i)
745 if !inter.is_valid() || inter.kind() != .aux_string_inter {
746 continue
747 }
748 expr_call := freestanding_restricted_call_in_cursor_expr(inter.edge(0), ctx)
749 if expr_call != '' {
750 return expr_call
751 }
752 format_call := freestanding_restricted_call_in_cursor_expr(inter.edge(1), ctx)
753 if format_call != '' {
754 return format_call
755 }
756 }
757 return ''
758}
759
760fn freestanding_restricted_call_in_expr(expr ast.Expr, ctx FreestandingScanContext) string {
761 return match expr {
762 ast.ArrayInitExpr {
763 meta_call := freestanding_restricted_call_in_exprs([expr.typ, expr.init, expr.cap,
764 expr.len, expr.update_expr], ctx)
765 if meta_call != '' {
766 meta_call
767 } else {
768 freestanding_restricted_call_in_exprs(expr.exprs, ctx)
769 }
770 }
771 ast.AsCastExpr {
772 freestanding_restricted_call_in_expr(expr.expr, ctx)
773 }
774 ast.AssocExpr {
775 base_call := freestanding_restricted_call_in_expr(expr.expr, ctx)
776 if base_call != '' {
777 base_call
778 } else {
779 freestanding_restricted_call_in_field_inits(expr.fields, ctx)
780 }
781 }
782 ast.CallExpr {
783 call_name := freestanding_restricted_builtin_call_name(expr.lhs, ctx)
784 if call_name != '' {
785 call_name
786 } else {
787 lhs_call := freestanding_restricted_call_in_expr(expr.lhs, ctx)
788 if lhs_call != '' {
789 lhs_call
790 } else {
791 freestanding_restricted_call_in_exprs(expr.args, ctx)
792 }
793 }
794 }
795 ast.CallOrCastExpr {
796 call_name := freestanding_restricted_builtin_call_name(expr.lhs, ctx)
797 if call_name != '' {
798 call_name
799 } else {
800 lhs_call := freestanding_restricted_call_in_expr(expr.lhs, ctx)
801 if lhs_call != '' {
802 lhs_call
803 } else {
804 freestanding_restricted_call_in_expr(expr.expr, ctx)
805 }
806 }
807 }
808 ast.CastExpr {
809 freestanding_restricted_call_in_expr(expr.expr, ctx)
810 }
811 ast.ComptimeExpr {
812 freestanding_restricted_call_in_comptime_expr(expr, ctx)
813 }
814 ast.FieldInit {
815 freestanding_restricted_call_in_expr(expr.value, ctx)
816 }
817 ast.FnLiteral {
818 capture_call := freestanding_restricted_call_in_exprs(expr.captured_vars, ctx)
819 if capture_call != '' {
820 capture_call
821 } else {
822 freestanding_restricted_call_in_stmts(expr.stmts, ctx)
823 }
824 }
825 ast.GenericArgOrIndexExpr {
826 lhs_call := freestanding_restricted_call_in_expr(expr.lhs, ctx)
827 if lhs_call != '' {
828 lhs_call
829 } else {
830 freestanding_restricted_call_in_expr(expr.expr, ctx)
831 }
832 }
833 ast.GenericArgs {
834 lhs_call := freestanding_restricted_call_in_expr(expr.lhs, ctx)
835 if lhs_call != '' {
836 lhs_call
837 } else {
838 freestanding_restricted_call_in_exprs(expr.args, ctx)
839 }
840 }
841 ast.IfExpr {
842 cond_call := freestanding_restricted_call_in_expr(expr.cond, ctx)
843 if cond_call != '' {
844 cond_call
845 } else {
846 stmts_call := freestanding_restricted_call_in_stmts(expr.stmts, ctx)
847 if stmts_call != '' {
848 stmts_call
849 } else {
850 freestanding_restricted_call_in_expr(expr.else_expr, ctx)
851 }
852 }
853 }
854 ast.IfGuardExpr {
855 freestanding_restricted_call_in_stmt(ast.Stmt(expr.stmt), ctx)
856 }
857 ast.IndexExpr {
858 lhs_call := freestanding_restricted_call_in_expr(expr.lhs, ctx)
859 if lhs_call != '' {
860 lhs_call
861 } else {
862 freestanding_restricted_call_in_expr(expr.expr, ctx)
863 }
864 }
865 ast.InfixExpr {
866 lhs_call := freestanding_restricted_call_in_expr(expr.lhs, ctx)
867 if lhs_call != '' {
868 lhs_call
869 } else {
870 freestanding_restricted_call_in_expr(expr.rhs, ctx)
871 }
872 }
873 ast.InitExpr {
874 typ_call := freestanding_restricted_call_in_expr(expr.typ, ctx)
875 if typ_call != '' {
876 typ_call
877 } else {
878 freestanding_restricted_call_in_field_inits(expr.fields, ctx)
879 }
880 }
881 ast.KeywordOperator {
882 if expr.op in [.key_go, .key_spawn] {
883 expr.op.str()
884 } else {
885 freestanding_restricted_call_in_exprs(expr.exprs, ctx)
886 }
887 }
888 ast.LambdaExpr {
889 freestanding_restricted_call_in_expr(expr.expr, ctx)
890 }
891 ast.LockExpr {
892 'lock'
893 }
894 ast.MapInitExpr {
895 key_call := freestanding_restricted_call_in_exprs(expr.keys, ctx)
896 if key_call != '' {
897 key_call
898 } else {
899 freestanding_restricted_call_in_exprs(expr.vals, ctx)
900 }
901 }
902 ast.MatchExpr {
903 expr_call := freestanding_restricted_call_in_expr(expr.expr, ctx)
904 if expr_call != '' {
905 expr_call
906 } else {
907 freestanding_restricted_call_in_match_branches(expr.branches, ctx)
908 }
909 }
910 ast.ModifierExpr {
911 if expr.kind == .key_shared {
912 'shared'
913 } else {
914 freestanding_restricted_call_in_expr(expr.expr, ctx)
915 }
916 }
917 ast.OrExpr {
918 expr_call := freestanding_restricted_call_in_expr(expr.expr, ctx)
919 if expr_call != '' {
920 expr_call
921 } else {
922 freestanding_restricted_call_in_stmts(expr.stmts, ctx)
923 }
924 }
925 ast.ParenExpr {
926 freestanding_restricted_call_in_expr(expr.expr, ctx)
927 }
928 ast.PostfixExpr {
929 freestanding_restricted_call_in_expr(expr.expr, ctx)
930 }
931 ast.PrefixExpr {
932 freestanding_restricted_call_in_expr(expr.expr, ctx)
933 }
934 ast.RangeExpr {
935 start_call := freestanding_restricted_call_in_expr(expr.start, ctx)
936 if start_call != '' {
937 start_call
938 } else {
939 freestanding_restricted_call_in_expr(expr.end, ctx)
940 }
941 }
942 ast.SelectExpr {
943 stmt_call := freestanding_restricted_call_in_stmt(expr.stmt, ctx)
944 if stmt_call != '' {
945 stmt_call
946 } else {
947 freestanding_restricted_call_in_stmts(expr.stmts, ctx)
948 }
949 }
950 ast.SelectorExpr {
951 freestanding_restricted_call_in_expr(expr.lhs, ctx)
952 }
953 ast.StringInterLiteral {
954 freestanding_restricted_call_in_string_inters(expr.inters, ctx)
955 }
956 ast.Tuple {
957 freestanding_restricted_call_in_exprs(expr.exprs, ctx)
958 }
959 ast.UnsafeExpr {
960 freestanding_restricted_call_in_stmts(expr.stmts, ctx)
961 }
962 else {
963 ''
964 }
965 }
966}
967
968fn freestanding_restricted_call_in_comptime_expr(expr ast.ComptimeExpr, ctx FreestandingScanContext) string {
969 if expr.expr is ast.IfExpr {
970 return freestanding_restricted_call_in_active_comptime_if(expr.expr, ctx)
971 }
972 return freestanding_restricted_call_in_expr(expr.expr, ctx)
973}
974
975fn freestanding_restricted_call_in_active_comptime_if(node ast.IfExpr, ctx FreestandingScanContext) string {
976 if ast_comptime_cond_matches_with_explicit(node.cond, ctx.user_defines, ctx.explicit_defines,
977 ctx.target_os)
978 {
979 return freestanding_restricted_call_in_stmts(node.stmts, ctx)
980 }
981 if node.else_expr is ast.IfExpr {
982 if node.else_expr.cond is ast.EmptyExpr {
983 return freestanding_restricted_call_in_stmts(node.else_expr.stmts, ctx)
984 }
985 return freestanding_restricted_call_in_active_comptime_if(node.else_expr, ctx)
986 }
987 return ''
988}
989
990fn freestanding_restricted_call_in_match_branches(branches []ast.MatchBranch, ctx FreestandingScanContext) string {
991 for branch in branches {
992 cond_call := freestanding_restricted_call_in_exprs(branch.cond, ctx)
993 if cond_call != '' {
994 return cond_call
995 }
996 stmts_call := freestanding_restricted_call_in_stmts(branch.stmts, ctx)
997 if stmts_call != '' {
998 return stmts_call
999 }
1000 }
1001 return ''
1002}
1003
1004fn freestanding_restricted_call_in_string_inters(inters []ast.StringInter, ctx FreestandingScanContext) string {
1005 for inter in inters {
1006 expr_call := freestanding_restricted_call_in_expr(inter.expr, ctx)
1007 if expr_call != '' {
1008 return expr_call
1009 }
1010 format_call := freestanding_restricted_call_in_expr(inter.format_expr, ctx)
1011 if format_call != '' {
1012 return format_call
1013 }
1014 }
1015 return ''
1016}
1017
1018fn freestanding_restricted_builtin_call_name(lhs ast.Expr, ctx FreestandingScanContext) string {
1019 if lhs is ast.Ident {
1020 return freestanding_output_builtin_call_name(lhs.name, ctx)
1021 }
1022 return ''
1023}
1024
1025fn freestanding_restricted_builtin_call_name_cursor(lhs ast.Cursor, ctx FreestandingScanContext) string {
1026 if lhs.is_valid() && lhs.kind() == .expr_ident {
1027 return freestanding_output_builtin_call_name(lhs.name(), ctx)
1028 }
1029 return ''
1030}
1031