Files
agila_open_tool/tools/v/vlib/v3/gen/c/if.v
T

411 lines
11 KiB
V

module c
import v3.flat
import v3.types
fn (mut g FlatGen) gen_if(node flat.Node) {
if node.children_count < 2 {
return
}
cond_id := g.a.child(&node, 0)
if !g.valid_node_id(cond_id) {
return
}
cond := g.a.nodes[int(cond_id)]
if cond.kind == .decl_assign {
g.gen_if_guard(node, cond)
return
}
if cond.kind != .empty {
g.write('if (')
g.gen_expr(cond_id)
g.writeln(') {')
} else {
g.writeln('{')
}
g.tc.push_scope()
defer_start := g.defers.len
g.indent++
if cond.kind == .is_expr {
g.smartcast_is_expr(&cond)
}
then_id := g.a.child(&node, 1)
if g.valid_node_id(then_id) {
then_block := g.a.nodes[int(then_id)]
for i in 0 .. then_block.children_count {
child_id := g.a.child(&then_block, i)
if g.valid_node_id(child_id) {
g.gen_node(child_id)
}
}
}
g.gen_defers_from(defer_start)
g.trim_defers(defer_start)
g.indent--
g.tc.pop_scope()
g.gen_if_else(node)
}
fn (mut g FlatGen) smartcast_is_expr(cond &flat.Node) {
expr_id := g.a.child(cond, 0)
expr_node := g.a.nodes[int(expr_id)]
if expr_node.kind == .ident {
sum_type := g.tc.resolve_type(expr_id)
clean_sum0 := types.unwrap_pointer(sum_type)
mut clean_sum := clean_sum0
if clean_sum0 is types.Alias {
clean_sum = clean_sum0.base_type
}
if clean_sum is types.SumType {
variant_name := g.resolve_variant(clean_sum.name, cond.value)
variant_type := g.tc.parse_type(variant_name)
if variant_type is types.Void {
return
}
variant_ct := g.tc.c_type(variant_type)
field_name := g.sum_field_name(variant_name)
is_ptr_variant := g.variant_references_sum(variant_name, clean_sum.name)
var_name := c_name(expr_node.value)
tmp := g.tmp_name()
if is_ptr_variant {
g.writeln('${variant_ct} ${tmp} = *${var_name}.${field_name};')
} else {
g.writeln('${variant_ct} ${tmp} = ${var_name}.${field_name};')
}
g.writeln('${variant_ct} ${var_name} = ${tmp};')
g.tc.cur_scope.insert(expr_node.value, variant_type)
}
}
}
fn (g &FlatGen) expr_key(id flat.NodeId) string {
node := g.a.nodes[int(id)]
if node.kind == .ident {
return node.value
}
if node.kind == .selector && node.children_count > 0 {
base_key := g.expr_key(g.a.child(&node, 0))
if base_key.len > 0 {
return '${base_key}.${node.value}'
}
}
return ''
}
fn (mut g FlatGen) gen_if_guard(node flat.Node, cond flat.Node) {
if cond.children_count < 2 {
return
}
lhs_id := g.a.child(&cond, 0)
rhs_id := g.a.child(&cond, 1)
if !g.valid_node_id(lhs_id) || !g.valid_node_id(rhs_id) {
return
}
lhs := g.a.nodes[int(lhs_id)]
rhs := g.a.nodes[int(rhs_id)]
var_name := c_name(lhs.value)
tmp := g.tmp_name()
defer_start := g.defers.len
if rhs.kind == .index {
base_id := g.a.child(rhs, 0)
base_type := g.tc.resolve_type(base_id)
if base_type is types.Map {
c_val_type := g.tc.c_type(base_type.value_type)
c_key_type := g.tc.c_type(base_type.key_type)
g.write('void* ${tmp} = map__get_check(&')
g.gen_expr(base_id)
g.write(', &(${c_key_type}[]){')
g.gen_expr(g.a.child(rhs, 1))
g.writeln('});')
g.writeln('if (${tmp} != NULL) {')
g.tc.push_scope()
g.indent++
g.writeln('${c_val_type} ${var_name} = *(${c_val_type}*)${tmp};')
g.tc.cur_scope.insert(lhs.value, base_type.value_type)
} else {
rhs_type := g.tc.resolve_type(rhs_id)
opt_ct := g.optional_type_name(rhs_type)
val_ct, val_type := g.optional_value_ct(rhs_type)
g.write('${opt_ct} ${tmp} = ')
g.gen_expr(rhs_id)
g.writeln(';')
g.writeln('if (${tmp}.ok) {')
g.tc.push_scope()
g.indent++
g.writeln('${val_ct} ${var_name} = ${tmp}.value;')
g.tc.cur_scope.insert(lhs.value, val_type)
}
} else {
rhs_type := g.tc.resolve_type(rhs_id)
opt_ct := g.optional_type_name(rhs_type)
val_ct, val_type := g.optional_value_ct(rhs_type)
g.write('${opt_ct} ${tmp} = ')
g.gen_expr(rhs_id)
g.writeln(';')
g.writeln('if (${tmp}.ok) {')
g.tc.push_scope()
g.indent++
g.writeln('${val_ct} ${var_name} = ${tmp}.value;')
g.tc.cur_scope.insert(lhs.value, val_type)
}
then_id := g.a.child(&node, 1)
if g.valid_node_id(then_id) {
then_block := g.a.nodes[int(then_id)]
for i in 0 .. then_block.children_count {
child_id := g.a.child(&then_block, i)
if g.valid_node_id(child_id) {
g.gen_node(child_id)
}
}
}
g.gen_defers_from(defer_start)
g.trim_defers(defer_start)
g.indent--
g.tc.pop_scope()
g.gen_if_else(node)
}
fn (mut g FlatGen) gen_if_else(node flat.Node) {
if node.children_count > 2 {
else_id := g.a.child(&node, 2)
if !g.valid_node_id(else_id) {
g.writeln('}')
return
}
else_node := g.a.nodes[int(else_id)]
if else_node.kind == .if_expr {
else_cond_id := g.a.child(&else_node, 0)
else_cond_is_guard := if g.valid_node_id(else_cond_id) {
g.a.nodes[int(else_cond_id)].kind == .decl_assign
} else {
false
}
if else_cond_is_guard {
g.writeln('} else {')
g.tc.push_scope()
g.indent++
g.gen_if(else_node)
g.indent--
g.tc.pop_scope()
g.writeln('}')
} else {
g.write('} else ')
g.gen_if(else_node)
}
} else if else_node.kind == .block {
g.writeln('} else {')
g.tc.push_scope()
defer_start := g.defers.len
g.indent++
for i in 0 .. else_node.children_count {
child_id := g.a.child(&else_node, i)
if g.valid_node_id(child_id) {
g.gen_node(child_id)
}
}
g.gen_defers_from(defer_start)
g.trim_defers(defer_start)
g.indent--
g.tc.pop_scope()
g.writeln('}')
} else {
g.writeln('}')
}
} else {
g.writeln('}')
}
}
fn (mut g FlatGen) gen_if_expr(node flat.Node) {
then_block := g.a.child_node(&node, 1)
mut needs_stmt_expr := then_block.children_count > 1
if !needs_stmt_expr && node.children_count > 2 {
else_node := g.a.child_node(&node, 2)
if else_node.kind == .block && else_node.children_count > 1 {
needs_stmt_expr = true
} else if else_node.kind == .if_expr {
needs_stmt_expr = true
}
}
if needs_stmt_expr {
g.gen_if_expr_stmt(node)
return
}
g.write('(')
g.gen_expr(g.a.child(&node, 0))
g.write(' ? ')
if then_block.children_count > 0 {
last := g.a.child_node(then_block, then_block.children_count - 1)
if last.kind == .expr_stmt {
g.gen_expr(g.a.child(last, 0))
} else {
g.gen_expr(g.a.child(then_block, then_block.children_count - 1))
}
}
g.write(' : ')
if node.children_count > 2 {
else_node := g.a.child_node(&node, 2)
if else_node.kind == .if_expr {
g.gen_if_expr(*else_node)
} else if else_node.kind == .block {
if else_node.children_count > 0 {
last := g.a.child_node(else_node, else_node.children_count - 1)
if last.kind == .expr_stmt {
g.gen_expr(g.a.child(last, 0))
} else {
g.gen_expr(g.a.child(else_node, else_node.children_count - 1))
}
} else {
g.write('0')
}
}
} else {
g.write('0')
}
g.write(')')
}
fn (mut g FlatGen) gen_if_expr_block(block &flat.Node) {
for i in 0 .. block.children_count {
child_id := g.a.child(block, i)
child := g.a.nodes[int(child_id)]
if i == block.children_count - 1 {
if child.kind == .expr_stmt {
g.write('_ifexpr = ')
g.gen_expr(g.a.child(child, 0))
g.writeln(';')
} else if child.kind == .if_expr {
g.write('_ifexpr = ')
g.gen_if_expr(child)
g.writeln(';')
} else if g.is_expr_kind(child.kind) {
g.write('_ifexpr = ')
g.gen_expr(child_id)
g.writeln(';')
} else {
g.gen_node(child_id)
}
} else {
g.gen_node(child_id)
}
}
}
fn (g &FlatGen) is_expr_kind(kind flat.NodeKind) bool {
return match kind {
.int_literal, .float_literal, .bool_literal, .char_literal, .string_literal,
.string_interp, .ident, .infix, .prefix, .postfix, .paren, .call, .selector, .index,
.if_expr, .struct_init, .field_init, .array_literal, .array_init, .map_init, .fn_literal,
.or_expr, .cast_expr, .as_expr, .enum_val, .assoc, .range, .nil_literal, .none_expr,
.spawn_expr, .lock_expr, .lambda_expr, .sizeof_expr, .typeof_expr, .dump_expr,
.offsetof_expr, .is_expr, .in_expr {
true
}
else {
false
}
}
}
fn (mut g FlatGen) seed_scope_from_decl(node flat.Node) {
if node.kind != .decl_assign || node.children_count < 2 {
return
}
lhs := g.a.child_node(&node, 0)
if lhs.kind != .ident || lhs.value.len == 0 {
return
}
rhs_id := g.a.child(&node, 1)
g.tc.cur_scope.insert(lhs.value, g.tc.resolve_type(rhs_id))
}
fn (mut g FlatGen) if_expr_block_tail_type(block &flat.Node) types.Type {
if block.children_count == 0 {
return types.Type(types.void_)
}
g.tc.push_scope()
for i in 0 .. block.children_count - 1 {
g.seed_scope_from_decl(*g.a.child_node(block, i))
}
last := g.a.child_node(block, block.children_count - 1)
ret := if last.kind == .expr_stmt {
g.tc.resolve_type(g.a.child(last, 0))
} else {
g.tc.resolve_type(g.a.child(block, block.children_count - 1))
}
g.tc.pop_scope()
return ret
}
fn (mut g FlatGen) if_expr_type(node &flat.Node) types.Type {
if node.children_count < 2 {
return types.Type(types.void_)
}
then_block := g.a.child_node(node, 1)
mut ret_type := g.if_expr_block_tail_type(then_block)
if ret_type is types.Primitive && node.children_count > 2 {
else_node := g.a.child_node(node, 2)
if else_node.kind == .block && else_node.children_count > 0 {
et := g.if_expr_block_tail_type(else_node)
if et !is types.Primitive {
ret_type = et
}
} else if else_node.kind == .if_expr && else_node.children_count > 2 {
inner_else := g.a.child_node(else_node, 2)
if inner_else.kind == .block && inner_else.children_count > 0 {
et := g.if_expr_block_tail_type(inner_else)
if et !is types.Primitive {
ret_type = et
}
}
}
}
return ret_type
}
fn (mut g FlatGen) gen_if_expr_stmt(node flat.Node) {
ret_type := g.if_expr_type(&node)
then_block := g.a.child_node(&node, 1)
ct := g.tc.c_type(ret_type)
g.writeln('({${ct} _ifexpr;')
g.write('if (')
g.gen_expr(g.a.child(&node, 0))
g.writeln(') {')
g.gen_if_expr_block(then_block)
g.write('} else ')
if node.children_count > 2 {
else_node := g.a.child_node(&node, 2)
if else_node.kind == .if_expr {
g.gen_if_expr_else_if(*else_node)
} else if else_node.kind == .block {
g.writeln('{')
g.gen_if_expr_block(else_node)
g.writeln('}')
}
} else {
g.writeln('{ _ifexpr = (${ct}){0}; }')
}
g.write('_ifexpr;})')
}
fn (mut g FlatGen) gen_if_expr_else_if(node flat.Node) {
then_block := g.a.child_node(&node, 1)
g.write('if (')
g.gen_expr(g.a.child(&node, 0))
g.writeln(') {')
g.gen_if_expr_block(then_block)
g.write('} else ')
if node.children_count > 2 {
else_node := g.a.child_node(&node, 2)
if else_node.kind == .if_expr {
g.gen_if_expr_else_if(*else_node)
} else if else_node.kind == .block {
g.writeln('{')
g.gen_if_expr_block(else_node)
g.writeln('}')
}
} else {
g.writeln('{ _ifexpr = (typeof(_ifexpr)){0}; }')
}
}