1031 lines
29 KiB
V
1031 lines
29 KiB
V
// Copyright (c) 2020-2024 Joe Conigliaro. All rights reserved.
|
|
// Use of this source code is governed by an MIT license
|
|
// that can be found in the LICENSE file.
|
|
module builder
|
|
|
|
import v2.ast
|
|
import v2.pref
|
|
import v2.token
|
|
|
|
fn (b &Builder) validate_freestanding_cleanc_contract() bool {
|
|
if b.pref == unsafe { nil } || !b.pref.is_freestanding() {
|
|
return true
|
|
}
|
|
mut diagnostics := []string{}
|
|
mut seen := map[string]bool{}
|
|
target_os := b.pref.target_os_or_host()
|
|
if b.pref.prealloc {
|
|
msg := 'error: freestanding target cannot use -prealloc because it requires hosted allocation support'
|
|
diagnostics << msg
|
|
seen[msg] = true
|
|
}
|
|
if b.pref.is_shared_lib {
|
|
msg := 'error: freestanding target cannot use -shared because dynamic library output requires hosted loader support'
|
|
if !seen[msg] {
|
|
diagnostics << msg
|
|
seen[msg] = true
|
|
}
|
|
}
|
|
if b.pref.hot_fn.len > 0 {
|
|
msg := 'error: freestanding target cannot use -hot-fn because live code reload needs hosted OS services'
|
|
if !seen[msg] {
|
|
diagnostics << msg
|
|
seen[msg] = true
|
|
}
|
|
}
|
|
if b.pref.has_freestanding_hooks() && (!b.pref.skip_builtin || !b.pref.skip_type_check) {
|
|
msg := 'error: freestanding target platform hooks currently require --skip-builtin and --skip-type-check until cleanc builtin hook signatures are implemented'
|
|
if !seen[msg] {
|
|
diagnostics << msg
|
|
seen[msg] = true
|
|
}
|
|
}
|
|
scan_ctx := freestanding_scan_context(b.pref, target_os)
|
|
allow_pkgconfig_imports := !b.pref.is_cross_target()
|
|
for i, ff in b.flat.files {
|
|
if !b.should_scan_freestanding_diagnostic_file(b.flat.file_name(ff)) {
|
|
continue
|
|
}
|
|
for imported in active_file_imports_from_flat_with_options(&b.flat, ff,
|
|
b.pref.user_defines, b.pref.explicit_user_defines, target_os, allow_pkgconfig_imports) {
|
|
if msg := freestanding_restricted_import_diagnostic(imported.name) {
|
|
if !seen[msg] {
|
|
diagnostics << msg
|
|
seen[msg] = true
|
|
}
|
|
}
|
|
}
|
|
call_name := freestanding_restricted_call_in_cursor_stmts(b.flat.file_cursor(i).stmts(),
|
|
scan_ctx)
|
|
if call_name != '' {
|
|
msg := freestanding_restricted_call_diagnostic(call_name)
|
|
if !seen[msg] {
|
|
diagnostics << msg
|
|
seen[msg] = true
|
|
}
|
|
}
|
|
}
|
|
for msg in diagnostics {
|
|
eprintln(msg)
|
|
}
|
|
if diagnostics.len > 0 {
|
|
eprintln('hint: provide platform bindings or build without -freestanding')
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
fn (b &Builder) should_scan_freestanding_diagnostic_file(file_name string) bool {
|
|
if file_name == '' || b.pref == unsafe { nil } || b.pref.vroot == '' {
|
|
return true
|
|
}
|
|
path := file_name.replace('\\', '/')
|
|
vroot := b.pref.vroot.replace('\\', '/').trim_right('/')
|
|
return !path.starts_with('${vroot}/vlib/')
|
|
}
|
|
|
|
fn freestanding_restricted_import_diagnostic(import_name string) ?string {
|
|
root := import_name.all_before('.')
|
|
return match root {
|
|
'os' {
|
|
'error: freestanding target cannot use module os without a platform implementation'
|
|
}
|
|
'time' {
|
|
'error: freestanding target cannot use module time without a platform time source'
|
|
}
|
|
'term' {
|
|
'error: freestanding target cannot use module term without terminal support'
|
|
}
|
|
'net' {
|
|
'error: freestanding target cannot use module net without platform networking support'
|
|
}
|
|
'sync' {
|
|
'error: freestanding target cannot use module sync without threading/locking support'
|
|
}
|
|
else {
|
|
none
|
|
}
|
|
}
|
|
}
|
|
|
|
fn freestanding_restricted_call_diagnostic(call_name string) string {
|
|
return match call_name {
|
|
'panic' {
|
|
'error: freestanding target cannot use builtin panic without panic platform hook'
|
|
}
|
|
'spawn' {
|
|
'error: freestanding target cannot use spawn because threading support is not provided'
|
|
}
|
|
'go' {
|
|
'error: freestanding target cannot use go because threading support is not provided'
|
|
}
|
|
'lock' {
|
|
'error: freestanding target cannot use lock/rlock because locking support is not provided'
|
|
}
|
|
'shared' {
|
|
'error: freestanding target cannot use shared data because locking support is not provided'
|
|
}
|
|
'live' {
|
|
'error: freestanding target cannot use @[live] because live reload needs hosted OS services'
|
|
}
|
|
'assert' {
|
|
'error: freestanding target cannot use assert because failed assertions need hosted output/exit support'
|
|
}
|
|
else {
|
|
'error: freestanding target cannot use builtin ${call_name} without output platform hook'
|
|
}
|
|
}
|
|
}
|
|
|
|
struct FreestandingScanContext {
|
|
user_defines []string
|
|
explicit_defines []string
|
|
target_os string
|
|
freestanding_hooks []string
|
|
}
|
|
|
|
fn freestanding_scan_context(p &pref.Preferences, target_os string) FreestandingScanContext {
|
|
return FreestandingScanContext{
|
|
user_defines: p.user_defines
|
|
explicit_defines: p.explicit_user_defines
|
|
target_os: target_os
|
|
freestanding_hooks: p.freestanding_hook_list()
|
|
}
|
|
}
|
|
|
|
fn (ctx FreestandingScanContext) has_hook(hook string) bool {
|
|
return hook in ctx.freestanding_hooks
|
|
}
|
|
|
|
fn freestanding_output_builtin_call_name(name string, ctx FreestandingScanContext) string {
|
|
if name in ['print', 'println', 'eprint', 'eprintln'] && !ctx.has_hook('output') {
|
|
return name
|
|
}
|
|
if name == 'panic' && !ctx.has_hook('panic') {
|
|
return name
|
|
}
|
|
return ''
|
|
}
|
|
|
|
fn freestanding_attributes_are_inactive(attributes []ast.Attribute, ctx FreestandingScanContext) bool {
|
|
for attr in attributes {
|
|
if attr.comptime_cond !is ast.EmptyExpr
|
|
&& !ast_comptime_cond_matches_with_explicit(attr.comptime_cond, ctx.user_defines, ctx.explicit_defines, ctx.target_os) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
fn freestanding_channel_scan_options(ctx FreestandingScanContext) ChannelScanOptions {
|
|
return ChannelScanOptions{
|
|
user_defines: ctx.user_defines
|
|
explicit_user_defines: ctx.explicit_defines
|
|
target_os: ctx.target_os
|
|
allow_pkgconfig: true
|
|
filter_comptime: true
|
|
}
|
|
}
|
|
|
|
fn freestanding_cursor_attributes_are_inactive(attributes ast.CursorList, ctx FreestandingScanContext) bool {
|
|
options := freestanding_channel_scan_options(ctx)
|
|
for i in 0 .. attributes.len() {
|
|
attr := attributes.at(i)
|
|
if !attr.is_valid() || attr.kind() != .aux_attribute {
|
|
continue
|
|
}
|
|
cond := attr.edge(1)
|
|
if cond.is_valid() && cond.kind() != .expr_empty
|
|
&& !flat_comptime_cond_matches(cond, options) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
fn freestanding_cursor_attributes_has(attributes ast.CursorList, name string) bool {
|
|
for i in 0 .. attributes.len() {
|
|
attr := attributes.at(i)
|
|
if !attr.is_valid() || attr.kind() != .aux_attribute {
|
|
continue
|
|
}
|
|
if attr.name() == name {
|
|
return true
|
|
}
|
|
value := attr.edge(0)
|
|
if attr.name() == '' && value.is_valid() && value.kind() == .expr_ident
|
|
&& value.name() == name {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
fn freestanding_restricted_call_in_stmts(stmts []ast.Stmt, ctx FreestandingScanContext) string {
|
|
for stmt in stmts {
|
|
call_name := freestanding_restricted_call_in_stmt(stmt, ctx)
|
|
if call_name != '' {
|
|
return call_name
|
|
}
|
|
}
|
|
return ''
|
|
}
|
|
|
|
fn freestanding_restricted_call_in_cursor_stmts(stmts ast.CursorList, ctx FreestandingScanContext) string {
|
|
for i in 0 .. stmts.len() {
|
|
call_name := freestanding_restricted_call_in_cursor_stmt(stmts.at(i), ctx)
|
|
if call_name != '' {
|
|
return call_name
|
|
}
|
|
}
|
|
return ''
|
|
}
|
|
|
|
fn freestanding_restricted_call_in_cursor_stmt(stmt ast.Cursor, ctx FreestandingScanContext) string {
|
|
if !stmt.is_valid() {
|
|
return ''
|
|
}
|
|
return match stmt.kind() {
|
|
.stmt_assert {
|
|
expr_call :=
|
|
freestanding_restricted_call_in_cursor_edges(stmt, 0, stmt.edge_count(), ctx)
|
|
if expr_call != '' {
|
|
expr_call
|
|
} else {
|
|
'assert'
|
|
}
|
|
}
|
|
.stmt_assign {
|
|
freestanding_restricted_call_in_cursor_edges(stmt, 0, stmt.edge_count(), ctx)
|
|
}
|
|
.stmt_block, .stmt_defer {
|
|
freestanding_restricted_call_in_cursor_stmt_edges(stmt, 0, stmt.edge_count(), ctx)
|
|
}
|
|
.stmt_comptime {
|
|
freestanding_restricted_call_in_cursor_stmt(stmt.edge(0), ctx)
|
|
}
|
|
.stmt_const_decl {
|
|
freestanding_restricted_call_in_cursor_field_inits(stmt.list_at(0), ctx)
|
|
}
|
|
.stmt_expr {
|
|
freestanding_restricted_call_in_cursor_expr(stmt.edge(0), ctx)
|
|
}
|
|
.stmt_fn_decl {
|
|
attributes := stmt.list_at(2)
|
|
if freestanding_cursor_attributes_are_inactive(attributes, ctx) {
|
|
''
|
|
} else if freestanding_cursor_attributes_has(attributes, 'live') {
|
|
'live'
|
|
} else {
|
|
freestanding_restricted_call_in_cursor_stmts(stmt.list_at(3), ctx)
|
|
}
|
|
}
|
|
.stmt_for_in {
|
|
freestanding_restricted_call_in_cursor_edges(stmt, 0, stmt.edge_count(), ctx)
|
|
}
|
|
.stmt_for {
|
|
init_call := freestanding_restricted_call_in_cursor_stmt(stmt.edge(0), ctx)
|
|
if init_call != '' {
|
|
init_call
|
|
} else {
|
|
cond_call := freestanding_restricted_call_in_cursor_expr(stmt.edge(1), ctx)
|
|
if cond_call != '' {
|
|
cond_call
|
|
} else {
|
|
post_call := freestanding_restricted_call_in_cursor_stmt(stmt.edge(2), ctx)
|
|
if post_call != '' {
|
|
post_call
|
|
} else {
|
|
freestanding_restricted_call_in_cursor_stmts(stmt.for_body_list(), ctx)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
.stmt_global_decl {
|
|
freestanding_restricted_call_in_cursor_field_decls(stmt.list_at(1), ctx)
|
|
}
|
|
.stmt_interface_decl {
|
|
freestanding_restricted_call_in_cursor_field_decls(stmt.list_at(3), ctx)
|
|
}
|
|
.stmt_label {
|
|
freestanding_restricted_call_in_cursor_stmt(stmt.edge(0), ctx)
|
|
}
|
|
.stmt_return {
|
|
freestanding_restricted_call_in_cursor_edges(stmt, 0, stmt.edge_count(), ctx)
|
|
}
|
|
.stmt_struct_decl {
|
|
freestanding_restricted_call_in_cursor_field_decls(stmt.list_at(4), ctx)
|
|
}
|
|
else {
|
|
''
|
|
}
|
|
}
|
|
}
|
|
|
|
fn freestanding_restricted_call_in_cursor_stmt_edges(stmt ast.Cursor, start int, end int, ctx FreestandingScanContext) string {
|
|
for i in start .. end {
|
|
call_name := freestanding_restricted_call_in_cursor_stmt(stmt.edge(i), ctx)
|
|
if call_name != '' {
|
|
return call_name
|
|
}
|
|
}
|
|
return ''
|
|
}
|
|
|
|
fn freestanding_restricted_call_in_cursor_edges(expr_parent ast.Cursor, start int, end int, ctx FreestandingScanContext) string {
|
|
for i in start .. end {
|
|
call_name := freestanding_restricted_call_in_cursor_expr(expr_parent.edge(i), ctx)
|
|
if call_name != '' {
|
|
return call_name
|
|
}
|
|
}
|
|
return ''
|
|
}
|
|
|
|
fn freestanding_restricted_call_in_cursor_expr_list(exprs ast.CursorList, ctx FreestandingScanContext) string {
|
|
for i in 0 .. exprs.len() {
|
|
call_name := freestanding_restricted_call_in_cursor_expr(exprs.at(i), ctx)
|
|
if call_name != '' {
|
|
return call_name
|
|
}
|
|
}
|
|
return ''
|
|
}
|
|
|
|
fn freestanding_restricted_call_in_stmt(stmt ast.Stmt, ctx FreestandingScanContext) string {
|
|
return match stmt {
|
|
ast.AssertStmt {
|
|
expr_call := freestanding_restricted_call_in_exprs([stmt.expr, stmt.extra], ctx)
|
|
if expr_call != '' {
|
|
expr_call
|
|
} else {
|
|
'assert'
|
|
}
|
|
}
|
|
ast.AssignStmt {
|
|
lhs_call := freestanding_restricted_call_in_exprs(stmt.lhs, ctx)
|
|
if lhs_call != '' {
|
|
lhs_call
|
|
} else {
|
|
freestanding_restricted_call_in_exprs(stmt.rhs, ctx)
|
|
}
|
|
}
|
|
ast.BlockStmt {
|
|
freestanding_restricted_call_in_stmts(stmt.stmts, ctx)
|
|
}
|
|
ast.ComptimeStmt {
|
|
freestanding_restricted_call_in_stmt(stmt.stmt, ctx)
|
|
}
|
|
ast.ConstDecl {
|
|
freestanding_restricted_call_in_field_inits(stmt.fields, ctx)
|
|
}
|
|
ast.DeferStmt {
|
|
freestanding_restricted_call_in_stmts(stmt.stmts, ctx)
|
|
}
|
|
ast.ExprStmt {
|
|
freestanding_restricted_call_in_expr(stmt.expr, ctx)
|
|
}
|
|
ast.FnDecl {
|
|
if freestanding_attributes_are_inactive(stmt.attributes, ctx) {
|
|
''
|
|
} else if stmt.attributes.has('live') {
|
|
'live'
|
|
} else {
|
|
freestanding_restricted_call_in_stmts(stmt.stmts, ctx)
|
|
}
|
|
}
|
|
ast.ForInStmt {
|
|
freestanding_restricted_call_in_exprs([stmt.key, stmt.value, stmt.expr], ctx)
|
|
}
|
|
ast.ForStmt {
|
|
init_call := freestanding_restricted_call_in_stmt(stmt.init, ctx)
|
|
if init_call != '' {
|
|
init_call
|
|
} else {
|
|
cond_call := freestanding_restricted_call_in_expr(stmt.cond, ctx)
|
|
if cond_call != '' {
|
|
cond_call
|
|
} else {
|
|
post_call := freestanding_restricted_call_in_stmt(stmt.post, ctx)
|
|
if post_call != '' {
|
|
post_call
|
|
} else {
|
|
freestanding_restricted_call_in_stmts(stmt.stmts, ctx)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
ast.GlobalDecl {
|
|
freestanding_restricted_call_in_field_decls(stmt.fields, ctx)
|
|
}
|
|
ast.InterfaceDecl {
|
|
freestanding_restricted_call_in_field_decls(stmt.fields, ctx)
|
|
}
|
|
ast.LabelStmt {
|
|
freestanding_restricted_call_in_stmt(stmt.stmt, ctx)
|
|
}
|
|
ast.ReturnStmt {
|
|
freestanding_restricted_call_in_exprs(stmt.exprs, ctx)
|
|
}
|
|
ast.StructDecl {
|
|
freestanding_restricted_call_in_field_decls(stmt.fields, ctx)
|
|
}
|
|
else {
|
|
''
|
|
}
|
|
}
|
|
}
|
|
|
|
fn freestanding_restricted_call_in_exprs(exprs []ast.Expr, ctx FreestandingScanContext) string {
|
|
for expr in exprs {
|
|
call_name := freestanding_restricted_call_in_expr(expr, ctx)
|
|
if call_name != '' {
|
|
return call_name
|
|
}
|
|
}
|
|
return ''
|
|
}
|
|
|
|
fn freestanding_restricted_call_in_cursor_field_inits(fields ast.CursorList, ctx FreestandingScanContext) string {
|
|
for i in 0 .. fields.len() {
|
|
call_name := freestanding_restricted_call_in_cursor_expr(fields.at(i).edge(0), ctx)
|
|
if call_name != '' {
|
|
return call_name
|
|
}
|
|
}
|
|
return ''
|
|
}
|
|
|
|
fn freestanding_restricted_call_in_field_inits(fields []ast.FieldInit, ctx FreestandingScanContext) string {
|
|
for field in fields {
|
|
call_name := freestanding_restricted_call_in_expr(field.value, ctx)
|
|
if call_name != '' {
|
|
return call_name
|
|
}
|
|
}
|
|
return ''
|
|
}
|
|
|
|
fn freestanding_restricted_call_in_cursor_field_decls(fields ast.CursorList, ctx FreestandingScanContext) string {
|
|
for i in 0 .. fields.len() {
|
|
field := fields.at(i)
|
|
typ_call := freestanding_restricted_call_in_cursor_expr(field.edge(0), ctx)
|
|
if typ_call != '' {
|
|
return typ_call
|
|
}
|
|
value_call := freestanding_restricted_call_in_cursor_expr(field.edge(1), ctx)
|
|
if value_call != '' {
|
|
return value_call
|
|
}
|
|
}
|
|
return ''
|
|
}
|
|
|
|
fn freestanding_restricted_call_in_field_decls(fields []ast.FieldDecl, ctx FreestandingScanContext) string {
|
|
for field in fields {
|
|
typ_call := freestanding_restricted_call_in_expr(field.typ, ctx)
|
|
if typ_call != '' {
|
|
return typ_call
|
|
}
|
|
value_call := freestanding_restricted_call_in_expr(field.value, ctx)
|
|
if value_call != '' {
|
|
return value_call
|
|
}
|
|
}
|
|
return ''
|
|
}
|
|
|
|
fn freestanding_restricted_call_in_cursor_expr(expr ast.Cursor, ctx FreestandingScanContext) string {
|
|
if !expr.is_valid() {
|
|
return ''
|
|
}
|
|
return match expr.kind() {
|
|
.expr_array_init {
|
|
meta_call := freestanding_restricted_call_in_cursor_edges(expr, 0, 5, ctx)
|
|
if meta_call != '' {
|
|
meta_call
|
|
} else {
|
|
freestanding_restricted_call_in_cursor_edges(expr, 5, expr.edge_count(), ctx)
|
|
}
|
|
}
|
|
.expr_as_cast {
|
|
freestanding_restricted_call_in_cursor_expr(expr.edge(0), ctx)
|
|
}
|
|
.expr_cast {
|
|
freestanding_restricted_call_in_cursor_expr(expr.edge(1), ctx)
|
|
}
|
|
.expr_assoc {
|
|
base_call := freestanding_restricted_call_in_cursor_expr(expr.edge(1), ctx)
|
|
if base_call != '' {
|
|
base_call
|
|
} else {
|
|
freestanding_restricted_call_in_cursor_field_inits(ast.CursorList{
|
|
flat: expr.flat
|
|
parent_id: expr.id
|
|
offset: 2
|
|
}, ctx)
|
|
}
|
|
}
|
|
.expr_call {
|
|
call_name := freestanding_restricted_builtin_call_name_cursor(expr.edge(0), ctx)
|
|
if call_name != '' {
|
|
call_name
|
|
} else {
|
|
lhs_call := freestanding_restricted_call_in_cursor_expr(expr.edge(0), ctx)
|
|
if lhs_call != '' {
|
|
lhs_call
|
|
} else {
|
|
freestanding_restricted_call_in_cursor_edges(expr, 1, expr.edge_count(), ctx)
|
|
}
|
|
}
|
|
}
|
|
.expr_call_or_cast {
|
|
call_name := freestanding_restricted_builtin_call_name_cursor(expr.edge(0), ctx)
|
|
if call_name != '' {
|
|
call_name
|
|
} else {
|
|
lhs_call := freestanding_restricted_call_in_cursor_expr(expr.edge(0), ctx)
|
|
if lhs_call != '' {
|
|
lhs_call
|
|
} else {
|
|
freestanding_restricted_call_in_cursor_expr(expr.edge(1), ctx)
|
|
}
|
|
}
|
|
}
|
|
.expr_comptime {
|
|
freestanding_restricted_call_in_cursor_comptime_expr(expr, ctx)
|
|
}
|
|
.expr_fn_literal {
|
|
captured_len := expr.extra_int()
|
|
capture_call :=
|
|
freestanding_restricted_call_in_cursor_edges(expr, 1, 1 + captured_len, ctx)
|
|
if capture_call != '' {
|
|
capture_call
|
|
} else {
|
|
freestanding_restricted_call_in_cursor_stmt_edges(expr, 1 + captured_len,
|
|
expr.edge_count(), ctx)
|
|
}
|
|
}
|
|
.expr_generic_arg_or_index, .expr_index, .expr_infix {
|
|
lhs_call := freestanding_restricted_call_in_cursor_expr(expr.edge(0), ctx)
|
|
if lhs_call != '' {
|
|
lhs_call
|
|
} else {
|
|
freestanding_restricted_call_in_cursor_expr(expr.edge(1), ctx)
|
|
}
|
|
}
|
|
.expr_generic_args {
|
|
lhs_call := freestanding_restricted_call_in_cursor_expr(expr.edge(0), ctx)
|
|
if lhs_call != '' {
|
|
lhs_call
|
|
} else {
|
|
freestanding_restricted_call_in_cursor_edges(expr, 1, expr.edge_count(), ctx)
|
|
}
|
|
}
|
|
.expr_if {
|
|
cond_call := freestanding_restricted_call_in_cursor_expr(expr.edge(0), ctx)
|
|
if cond_call != '' {
|
|
cond_call
|
|
} else {
|
|
stmts_call := freestanding_restricted_call_in_cursor_stmt_edges(expr, 2,
|
|
expr.edge_count(), ctx)
|
|
if stmts_call != '' {
|
|
stmts_call
|
|
} else {
|
|
freestanding_restricted_call_in_cursor_expr(expr.edge(1), ctx)
|
|
}
|
|
}
|
|
}
|
|
.expr_if_guard {
|
|
freestanding_restricted_call_in_cursor_stmt(expr.edge(0), ctx)
|
|
}
|
|
.expr_init {
|
|
typ_call := freestanding_restricted_call_in_cursor_expr(expr.edge(0), ctx)
|
|
if typ_call != '' {
|
|
typ_call
|
|
} else {
|
|
freestanding_restricted_call_in_cursor_field_inits(ast.CursorList{
|
|
flat: expr.flat
|
|
parent_id: expr.id
|
|
offset: 1
|
|
}, ctx)
|
|
}
|
|
}
|
|
.expr_keyword_operator {
|
|
op := unsafe { token.Token(int(expr.aux())) }
|
|
if op in [.key_go, .key_spawn] {
|
|
op.str()
|
|
} else {
|
|
freestanding_restricted_call_in_cursor_edges(expr, 0, expr.edge_count(), ctx)
|
|
}
|
|
}
|
|
.expr_lambda, .expr_paren, .expr_postfix, .expr_prefix, .expr_selector {
|
|
freestanding_restricted_call_in_cursor_expr(expr.edge(0), ctx)
|
|
}
|
|
.expr_lock {
|
|
'lock'
|
|
}
|
|
.expr_map_init {
|
|
keys_len := expr.extra_int()
|
|
key_call := freestanding_restricted_call_in_cursor_edges(expr, 1, 1 + keys_len, ctx)
|
|
if key_call != '' {
|
|
key_call
|
|
} else {
|
|
freestanding_restricted_call_in_cursor_edges(expr, 1 + keys_len, expr.edge_count(),
|
|
ctx)
|
|
}
|
|
}
|
|
.expr_match {
|
|
expr_call := freestanding_restricted_call_in_cursor_expr(expr.edge(0), ctx)
|
|
if expr_call != '' {
|
|
expr_call
|
|
} else {
|
|
freestanding_restricted_call_in_cursor_match_branch_edges(expr, 1,
|
|
expr.edge_count(), ctx)
|
|
}
|
|
}
|
|
.expr_modifier {
|
|
kind := unsafe { token.Token(int(expr.aux())) }
|
|
if kind == .key_shared {
|
|
'shared'
|
|
} else {
|
|
freestanding_restricted_call_in_cursor_expr(expr.edge(0), ctx)
|
|
}
|
|
}
|
|
.expr_or {
|
|
expr_call := freestanding_restricted_call_in_cursor_expr(expr.edge(0), ctx)
|
|
if expr_call != '' {
|
|
expr_call
|
|
} else {
|
|
freestanding_restricted_call_in_cursor_stmt_edges(expr, 1, expr.edge_count(), ctx)
|
|
}
|
|
}
|
|
.expr_range {
|
|
start_call := freestanding_restricted_call_in_cursor_expr(expr.edge(0), ctx)
|
|
if start_call != '' {
|
|
start_call
|
|
} else {
|
|
freestanding_restricted_call_in_cursor_expr(expr.edge(1), ctx)
|
|
}
|
|
}
|
|
.expr_select {
|
|
stmt_call := freestanding_restricted_call_in_cursor_stmt(expr.edge(0), ctx)
|
|
if stmt_call != '' {
|
|
stmt_call
|
|
} else {
|
|
freestanding_restricted_call_in_cursor_stmt_edges(expr, 2, expr.edge_count(), ctx)
|
|
}
|
|
}
|
|
.expr_string_inter {
|
|
freestanding_restricted_call_in_cursor_string_inters(expr.list_at(1), ctx)
|
|
}
|
|
.expr_tuple {
|
|
freestanding_restricted_call_in_cursor_edges(expr, 0, expr.edge_count(), ctx)
|
|
}
|
|
.expr_unsafe {
|
|
freestanding_restricted_call_in_cursor_stmt_edges(expr, 0, expr.edge_count(), ctx)
|
|
}
|
|
.aux_field_init {
|
|
freestanding_restricted_call_in_cursor_expr(expr.edge(0), ctx)
|
|
}
|
|
else {
|
|
''
|
|
}
|
|
}
|
|
}
|
|
|
|
fn freestanding_restricted_call_in_cursor_comptime_expr(expr ast.Cursor, ctx FreestandingScanContext) string {
|
|
inner := expr.edge(0)
|
|
if inner.is_valid() && inner.kind() == .expr_if {
|
|
return freestanding_restricted_call_in_cursor_active_comptime_if(inner, ctx)
|
|
}
|
|
return freestanding_restricted_call_in_cursor_expr(inner, ctx)
|
|
}
|
|
|
|
fn freestanding_restricted_call_in_cursor_active_comptime_if(node ast.Cursor, ctx FreestandingScanContext) string {
|
|
options := freestanding_channel_scan_options(ctx)
|
|
if flat_comptime_cond_matches(node.edge(0), options) {
|
|
return freestanding_restricted_call_in_cursor_stmt_edges(node, 2, node.edge_count(), ctx)
|
|
}
|
|
else_expr := node.edge(1)
|
|
if else_expr.is_valid() && else_expr.kind() == .expr_if {
|
|
if else_expr.edge(0).is_valid() && else_expr.edge(0).kind() == .expr_empty {
|
|
return freestanding_restricted_call_in_cursor_stmt_edges(else_expr, 2,
|
|
else_expr.edge_count(), ctx)
|
|
}
|
|
return freestanding_restricted_call_in_cursor_active_comptime_if(else_expr, ctx)
|
|
}
|
|
return ''
|
|
}
|
|
|
|
fn freestanding_restricted_call_in_cursor_match_branch_edges(expr ast.Cursor, start int, end int, ctx FreestandingScanContext) string {
|
|
for i in start .. end {
|
|
call_name := freestanding_restricted_call_in_cursor_match_branch(expr.edge(i), ctx)
|
|
if call_name != '' {
|
|
return call_name
|
|
}
|
|
}
|
|
return ''
|
|
}
|
|
|
|
fn freestanding_restricted_call_in_cursor_match_branch(branch ast.Cursor, ctx FreestandingScanContext) string {
|
|
if !branch.is_valid() || branch.kind() != .aux_match_branch {
|
|
return ''
|
|
}
|
|
cond_call := freestanding_restricted_call_in_cursor_expr_list(branch.list_at(0), ctx)
|
|
if cond_call != '' {
|
|
return cond_call
|
|
}
|
|
return freestanding_restricted_call_in_cursor_stmts(branch.list_at(1), ctx)
|
|
}
|
|
|
|
fn freestanding_restricted_call_in_cursor_string_inters(inters ast.CursorList, ctx FreestandingScanContext) string {
|
|
for i in 0 .. inters.len() {
|
|
inter := inters.at(i)
|
|
if !inter.is_valid() || inter.kind() != .aux_string_inter {
|
|
continue
|
|
}
|
|
expr_call := freestanding_restricted_call_in_cursor_expr(inter.edge(0), ctx)
|
|
if expr_call != '' {
|
|
return expr_call
|
|
}
|
|
format_call := freestanding_restricted_call_in_cursor_expr(inter.edge(1), ctx)
|
|
if format_call != '' {
|
|
return format_call
|
|
}
|
|
}
|
|
return ''
|
|
}
|
|
|
|
fn freestanding_restricted_call_in_expr(expr ast.Expr, ctx FreestandingScanContext) string {
|
|
return match expr {
|
|
ast.ArrayInitExpr {
|
|
meta_call := freestanding_restricted_call_in_exprs([expr.typ, expr.init, expr.cap,
|
|
expr.len, expr.update_expr], ctx)
|
|
if meta_call != '' {
|
|
meta_call
|
|
} else {
|
|
freestanding_restricted_call_in_exprs(expr.exprs, ctx)
|
|
}
|
|
}
|
|
ast.AsCastExpr {
|
|
freestanding_restricted_call_in_expr(expr.expr, ctx)
|
|
}
|
|
ast.AssocExpr {
|
|
base_call := freestanding_restricted_call_in_expr(expr.expr, ctx)
|
|
if base_call != '' {
|
|
base_call
|
|
} else {
|
|
freestanding_restricted_call_in_field_inits(expr.fields, ctx)
|
|
}
|
|
}
|
|
ast.CallExpr {
|
|
call_name := freestanding_restricted_builtin_call_name(expr.lhs, ctx)
|
|
if call_name != '' {
|
|
call_name
|
|
} else {
|
|
lhs_call := freestanding_restricted_call_in_expr(expr.lhs, ctx)
|
|
if lhs_call != '' {
|
|
lhs_call
|
|
} else {
|
|
freestanding_restricted_call_in_exprs(expr.args, ctx)
|
|
}
|
|
}
|
|
}
|
|
ast.CallOrCastExpr {
|
|
call_name := freestanding_restricted_builtin_call_name(expr.lhs, ctx)
|
|
if call_name != '' {
|
|
call_name
|
|
} else {
|
|
lhs_call := freestanding_restricted_call_in_expr(expr.lhs, ctx)
|
|
if lhs_call != '' {
|
|
lhs_call
|
|
} else {
|
|
freestanding_restricted_call_in_expr(expr.expr, ctx)
|
|
}
|
|
}
|
|
}
|
|
ast.CastExpr {
|
|
freestanding_restricted_call_in_expr(expr.expr, ctx)
|
|
}
|
|
ast.ComptimeExpr {
|
|
freestanding_restricted_call_in_comptime_expr(expr, ctx)
|
|
}
|
|
ast.FieldInit {
|
|
freestanding_restricted_call_in_expr(expr.value, ctx)
|
|
}
|
|
ast.FnLiteral {
|
|
capture_call := freestanding_restricted_call_in_exprs(expr.captured_vars, ctx)
|
|
if capture_call != '' {
|
|
capture_call
|
|
} else {
|
|
freestanding_restricted_call_in_stmts(expr.stmts, ctx)
|
|
}
|
|
}
|
|
ast.GenericArgOrIndexExpr {
|
|
lhs_call := freestanding_restricted_call_in_expr(expr.lhs, ctx)
|
|
if lhs_call != '' {
|
|
lhs_call
|
|
} else {
|
|
freestanding_restricted_call_in_expr(expr.expr, ctx)
|
|
}
|
|
}
|
|
ast.GenericArgs {
|
|
lhs_call := freestanding_restricted_call_in_expr(expr.lhs, ctx)
|
|
if lhs_call != '' {
|
|
lhs_call
|
|
} else {
|
|
freestanding_restricted_call_in_exprs(expr.args, ctx)
|
|
}
|
|
}
|
|
ast.IfExpr {
|
|
cond_call := freestanding_restricted_call_in_expr(expr.cond, ctx)
|
|
if cond_call != '' {
|
|
cond_call
|
|
} else {
|
|
stmts_call := freestanding_restricted_call_in_stmts(expr.stmts, ctx)
|
|
if stmts_call != '' {
|
|
stmts_call
|
|
} else {
|
|
freestanding_restricted_call_in_expr(expr.else_expr, ctx)
|
|
}
|
|
}
|
|
}
|
|
ast.IfGuardExpr {
|
|
freestanding_restricted_call_in_stmt(ast.Stmt(expr.stmt), ctx)
|
|
}
|
|
ast.IndexExpr {
|
|
lhs_call := freestanding_restricted_call_in_expr(expr.lhs, ctx)
|
|
if lhs_call != '' {
|
|
lhs_call
|
|
} else {
|
|
freestanding_restricted_call_in_expr(expr.expr, ctx)
|
|
}
|
|
}
|
|
ast.InfixExpr {
|
|
lhs_call := freestanding_restricted_call_in_expr(expr.lhs, ctx)
|
|
if lhs_call != '' {
|
|
lhs_call
|
|
} else {
|
|
freestanding_restricted_call_in_expr(expr.rhs, ctx)
|
|
}
|
|
}
|
|
ast.InitExpr {
|
|
typ_call := freestanding_restricted_call_in_expr(expr.typ, ctx)
|
|
if typ_call != '' {
|
|
typ_call
|
|
} else {
|
|
freestanding_restricted_call_in_field_inits(expr.fields, ctx)
|
|
}
|
|
}
|
|
ast.KeywordOperator {
|
|
if expr.op in [.key_go, .key_spawn] {
|
|
expr.op.str()
|
|
} else {
|
|
freestanding_restricted_call_in_exprs(expr.exprs, ctx)
|
|
}
|
|
}
|
|
ast.LambdaExpr {
|
|
freestanding_restricted_call_in_expr(expr.expr, ctx)
|
|
}
|
|
ast.LockExpr {
|
|
'lock'
|
|
}
|
|
ast.MapInitExpr {
|
|
key_call := freestanding_restricted_call_in_exprs(expr.keys, ctx)
|
|
if key_call != '' {
|
|
key_call
|
|
} else {
|
|
freestanding_restricted_call_in_exprs(expr.vals, ctx)
|
|
}
|
|
}
|
|
ast.MatchExpr {
|
|
expr_call := freestanding_restricted_call_in_expr(expr.expr, ctx)
|
|
if expr_call != '' {
|
|
expr_call
|
|
} else {
|
|
freestanding_restricted_call_in_match_branches(expr.branches, ctx)
|
|
}
|
|
}
|
|
ast.ModifierExpr {
|
|
if expr.kind == .key_shared {
|
|
'shared'
|
|
} else {
|
|
freestanding_restricted_call_in_expr(expr.expr, ctx)
|
|
}
|
|
}
|
|
ast.OrExpr {
|
|
expr_call := freestanding_restricted_call_in_expr(expr.expr, ctx)
|
|
if expr_call != '' {
|
|
expr_call
|
|
} else {
|
|
freestanding_restricted_call_in_stmts(expr.stmts, ctx)
|
|
}
|
|
}
|
|
ast.ParenExpr {
|
|
freestanding_restricted_call_in_expr(expr.expr, ctx)
|
|
}
|
|
ast.PostfixExpr {
|
|
freestanding_restricted_call_in_expr(expr.expr, ctx)
|
|
}
|
|
ast.PrefixExpr {
|
|
freestanding_restricted_call_in_expr(expr.expr, ctx)
|
|
}
|
|
ast.RangeExpr {
|
|
start_call := freestanding_restricted_call_in_expr(expr.start, ctx)
|
|
if start_call != '' {
|
|
start_call
|
|
} else {
|
|
freestanding_restricted_call_in_expr(expr.end, ctx)
|
|
}
|
|
}
|
|
ast.SelectExpr {
|
|
stmt_call := freestanding_restricted_call_in_stmt(expr.stmt, ctx)
|
|
if stmt_call != '' {
|
|
stmt_call
|
|
} else {
|
|
freestanding_restricted_call_in_stmts(expr.stmts, ctx)
|
|
}
|
|
}
|
|
ast.SelectorExpr {
|
|
freestanding_restricted_call_in_expr(expr.lhs, ctx)
|
|
}
|
|
ast.StringInterLiteral {
|
|
freestanding_restricted_call_in_string_inters(expr.inters, ctx)
|
|
}
|
|
ast.Tuple {
|
|
freestanding_restricted_call_in_exprs(expr.exprs, ctx)
|
|
}
|
|
ast.UnsafeExpr {
|
|
freestanding_restricted_call_in_stmts(expr.stmts, ctx)
|
|
}
|
|
else {
|
|
''
|
|
}
|
|
}
|
|
}
|
|
|
|
fn freestanding_restricted_call_in_comptime_expr(expr ast.ComptimeExpr, ctx FreestandingScanContext) string {
|
|
if expr.expr is ast.IfExpr {
|
|
return freestanding_restricted_call_in_active_comptime_if(expr.expr, ctx)
|
|
}
|
|
return freestanding_restricted_call_in_expr(expr.expr, ctx)
|
|
}
|
|
|
|
fn freestanding_restricted_call_in_active_comptime_if(node ast.IfExpr, ctx FreestandingScanContext) string {
|
|
if ast_comptime_cond_matches_with_explicit(node.cond, ctx.user_defines, ctx.explicit_defines,
|
|
ctx.target_os)
|
|
{
|
|
return freestanding_restricted_call_in_stmts(node.stmts, ctx)
|
|
}
|
|
if node.else_expr is ast.IfExpr {
|
|
if node.else_expr.cond is ast.EmptyExpr {
|
|
return freestanding_restricted_call_in_stmts(node.else_expr.stmts, ctx)
|
|
}
|
|
return freestanding_restricted_call_in_active_comptime_if(node.else_expr, ctx)
|
|
}
|
|
return ''
|
|
}
|
|
|
|
fn freestanding_restricted_call_in_match_branches(branches []ast.MatchBranch, ctx FreestandingScanContext) string {
|
|
for branch in branches {
|
|
cond_call := freestanding_restricted_call_in_exprs(branch.cond, ctx)
|
|
if cond_call != '' {
|
|
return cond_call
|
|
}
|
|
stmts_call := freestanding_restricted_call_in_stmts(branch.stmts, ctx)
|
|
if stmts_call != '' {
|
|
return stmts_call
|
|
}
|
|
}
|
|
return ''
|
|
}
|
|
|
|
fn freestanding_restricted_call_in_string_inters(inters []ast.StringInter, ctx FreestandingScanContext) string {
|
|
for inter in inters {
|
|
expr_call := freestanding_restricted_call_in_expr(inter.expr, ctx)
|
|
if expr_call != '' {
|
|
return expr_call
|
|
}
|
|
format_call := freestanding_restricted_call_in_expr(inter.format_expr, ctx)
|
|
if format_call != '' {
|
|
return format_call
|
|
}
|
|
}
|
|
return ''
|
|
}
|
|
|
|
fn freestanding_restricted_builtin_call_name(lhs ast.Expr, ctx FreestandingScanContext) string {
|
|
if lhs is ast.Ident {
|
|
return freestanding_output_builtin_call_name(lhs.name, ctx)
|
|
}
|
|
return ''
|
|
}
|
|
|
|
fn freestanding_restricted_builtin_call_name_cursor(lhs ast.Cursor, ctx FreestandingScanContext) string {
|
|
if lhs.is_valid() && lhs.kind() == .expr_ident {
|
|
return freestanding_output_builtin_call_name(lhs.name(), ctx)
|
|
}
|
|
return ''
|
|
}
|