cgen: multi return/assign optionals
parent
07de351546
commit
71ca553190
|
@ -423,20 +423,23 @@ pub fn (c mut Checker) assign_stmt(assign_stmt mut ast.AssignStmt) {
|
||||||
c.expected_type = table.none_type // TODO a hack to make `x := if ... work`
|
c.expected_type = table.none_type // TODO a hack to make `x := if ... work`
|
||||||
// multi return
|
// multi return
|
||||||
if assign_stmt.left.len > assign_stmt.right.len {
|
if assign_stmt.left.len > assign_stmt.right.len {
|
||||||
right := c.expr(assign_stmt.right[0])
|
match assign_stmt.right[0] {
|
||||||
right_sym := c.table.get_type_symbol(right)
|
ast.CallExpr {}
|
||||||
mr_info := right_sym.mr_info()
|
else {
|
||||||
if right_sym.kind != .multi_return {
|
c.error('assign_stmt: expected call', assign_stmt.pos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
right_type := c.expr(assign_stmt.right[0])
|
||||||
|
right_type_sym := c.table.get_type_symbol(right_type)
|
||||||
|
mr_info := right_type_sym.mr_info()
|
||||||
|
if right_type_sym.kind != .multi_return {
|
||||||
c.error('wrong number of vars', assign_stmt.pos)
|
c.error('wrong number of vars', assign_stmt.pos)
|
||||||
}
|
}
|
||||||
mut scope := c.file.scope.innermost(assign_stmt.pos.pos)
|
mut scope := c.file.scope.innermost(assign_stmt.pos.pos)
|
||||||
for i, _ in assign_stmt.left {
|
for i, _ in assign_stmt.left {
|
||||||
mut ident := assign_stmt.left[i]
|
mut ident := assign_stmt.left[i]
|
||||||
|
mut ident_var_info := ident.var_info()
|
||||||
val_type := mr_info.types[i]
|
val_type := mr_info.types[i]
|
||||||
mut var_info := ident.var_info()
|
|
||||||
var_info.typ = val_type
|
|
||||||
ident.info = var_info
|
|
||||||
assign_stmt.left[i] = ident
|
|
||||||
if assign_stmt.op == .assign {
|
if assign_stmt.op == .assign {
|
||||||
var_type := c.expr(ident)
|
var_type := c.expr(ident)
|
||||||
assign_stmt.left_types << var_type
|
assign_stmt.left_types << var_type
|
||||||
|
@ -446,8 +449,11 @@ pub fn (c mut Checker) assign_stmt(assign_stmt mut ast.AssignStmt) {
|
||||||
c.error('assign stmt: cannot use `$val_type_sym.name` as `$var_type_sym.name`', assign_stmt.pos)
|
c.error('assign stmt: cannot use `$val_type_sym.name` as `$var_type_sym.name`', assign_stmt.pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ident_var_info.typ = val_type
|
||||||
|
ident.info = ident_var_info
|
||||||
|
assign_stmt.left[i] = ident
|
||||||
assign_stmt.right_types << val_type
|
assign_stmt.right_types << val_type
|
||||||
scope.update_var_type(ident.name, mr_info.types[i])
|
scope.update_var_type(ident.name, val_type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// `a := 1` | `a,b := 1,2`
|
// `a := 1` | `a,b := 1,2`
|
||||||
|
@ -469,10 +475,10 @@ pub fn (c mut Checker) assign_stmt(assign_stmt mut ast.AssignStmt) {
|
||||||
c.error('assign stmt: cannot use `$val_type_sym.name` as `$var_type_sym.name`', assign_stmt.pos)
|
c.error('assign stmt: cannot use `$val_type_sym.name` as `$var_type_sym.name`', assign_stmt.pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assign_stmt.right_types << val_type
|
|
||||||
ident_var_info.typ = val_type
|
ident_var_info.typ = val_type
|
||||||
ident.info = ident_var_info
|
ident.info = ident_var_info
|
||||||
assign_stmt.left[i] = ident
|
assign_stmt.left[i] = ident
|
||||||
|
assign_stmt.right_types << val_type
|
||||||
scope.update_var_type(ident.name, val_type)
|
scope.update_var_type(ident.name, val_type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -538,7 +544,6 @@ fn (c mut Checker) stmt(node ast.Stmt) {
|
||||||
}
|
}
|
||||||
ast.AssignStmt {
|
ast.AssignStmt {
|
||||||
c.assign_stmt(mut it)
|
c.assign_stmt(mut it)
|
||||||
c.expected_type = table.void_type
|
|
||||||
}
|
}
|
||||||
ast.Block {
|
ast.Block {
|
||||||
c.stmts(it.stmts)
|
c.stmts(it.stmts)
|
||||||
|
@ -946,11 +951,11 @@ pub fn (c mut Checker) if_expr(node mut ast.IfExpr) table.Type {
|
||||||
node.typ = table.void_type
|
node.typ = table.void_type
|
||||||
for i, branch in node.branches {
|
for i, branch in node.branches {
|
||||||
match branch.cond {
|
match branch.cond {
|
||||||
ast.ParExpr{
|
ast.ParExpr {
|
||||||
c.error('unnecessary `()` in an if condition. use `if expr {` instead of `if (expr) {`.', node.pos)
|
c.error('unnecessary `()` in an if condition. use `if expr {` instead of `if (expr) {`.', node.pos)
|
||||||
}
|
}
|
||||||
else {}
|
else {}
|
||||||
}
|
}
|
||||||
typ := c.expr(branch.cond)
|
typ := c.expr(branch.cond)
|
||||||
if i < node.branches.len - 1 || !node.has_else {
|
if i < node.branches.len - 1 || !node.has_else {
|
||||||
typ_sym := c.table.get_type_symbol(typ)
|
typ_sym := c.table.get_type_symbol(typ)
|
||||||
|
|
|
@ -32,6 +32,7 @@ mut:
|
||||||
tmp_count int
|
tmp_count int
|
||||||
variadic_args map[string]int
|
variadic_args map[string]int
|
||||||
is_c_call bool // e.g. `C.printf("v")`
|
is_c_call bool // e.g. `C.printf("v")`
|
||||||
|
is_assign bool // inside right part of assign after `=` (val expr)
|
||||||
is_assign_expr bool // inside left part of assign expr (for array_set(), etc)
|
is_assign_expr bool // inside left part of assign expr (for array_set(), etc)
|
||||||
is_array_set bool
|
is_array_set bool
|
||||||
is_amp bool // for `&Foo{}` to merge PrefixExpr `&` and StructInit `Foo{}`; also for `&byte(0)` etc
|
is_amp bool // for `&Foo{}` to merge PrefixExpr `&` and StructInit `Foo{}`; also for `&byte(0)` etc
|
||||||
|
@ -43,7 +44,6 @@ mut:
|
||||||
indent int
|
indent int
|
||||||
empty_line bool
|
empty_line bool
|
||||||
is_test bool
|
is_test bool
|
||||||
expr_var_name string
|
|
||||||
assign_op token.Kind // *=, =, etc (for array_set)
|
assign_op token.Kind // *=, =, etc (for array_set)
|
||||||
defer_stmts []ast.DeferStmt
|
defer_stmts []ast.DeferStmt
|
||||||
defer_ifdef string
|
defer_ifdef string
|
||||||
|
@ -122,7 +122,7 @@ pub fn (g mut Gen) write_typeof_functions() {
|
||||||
for typ in g.table.types {
|
for typ in g.table.types {
|
||||||
if typ.kind == .sum_type {
|
if typ.kind == .sum_type {
|
||||||
sum_info := typ.info as table.SumType
|
sum_info := typ.info as table.SumType
|
||||||
tidx := g.table.find_type_idx( typ.name )
|
tidx := g.table.find_type_idx(typ.name)
|
||||||
g.writeln('char * v_typeof_sumtype_${tidx}(int sidx) { /* ${typ.name} */ ')
|
g.writeln('char * v_typeof_sumtype_${tidx}(int sidx) { /* ${typ.name} */ ')
|
||||||
g.writeln(' switch(sidx) {')
|
g.writeln(' switch(sidx) {')
|
||||||
g.writeln(' case $tidx: return "$typ.name";')
|
g.writeln(' case $tidx: return "$typ.name";')
|
||||||
|
@ -163,12 +163,6 @@ pub fn (g mut Gen) typ(t table.Type) string {
|
||||||
return styp
|
return styp
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
pub fn (g &Gen) styp(t string) string {
|
|
||||||
return t.replace('.', '__')
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
//
|
//
|
||||||
pub fn (g mut Gen) write_typedef_types() {
|
pub fn (g mut Gen) write_typedef_types() {
|
||||||
for typ in g.table.types {
|
for typ in g.table.types {
|
||||||
|
@ -213,7 +207,7 @@ pub fn (g mut Gen) write_typedef_types() {
|
||||||
else {
|
else {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -578,28 +572,24 @@ fn (g mut Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
||||||
// g.write('/*assign_stmt*/')
|
// g.write('/*assign_stmt*/')
|
||||||
if assign_stmt.left.len > assign_stmt.right.len {
|
if assign_stmt.left.len > assign_stmt.right.len {
|
||||||
// multi return
|
// multi return
|
||||||
|
mut or_stmts := []ast.Stmt
|
||||||
mut return_type := table.void_type
|
mut return_type := table.void_type
|
||||||
match assign_stmt.right[0] {
|
match assign_stmt.right[0] {
|
||||||
ast.CallExpr {
|
ast.CallExpr {
|
||||||
|
or_stmts = it.or_block.stmts
|
||||||
return_type = it.return_type
|
return_type = it.return_type
|
||||||
}
|
}
|
||||||
else {
|
else {}
|
||||||
panic('expected call')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
is_optional := table.type_is_optional(return_type)
|
||||||
mr_var_name := 'mr_$assign_stmt.pos.pos'
|
mr_var_name := 'mr_$assign_stmt.pos.pos'
|
||||||
g.expr_var_name = mr_var_name
|
mr_styp := g.typ(return_type)
|
||||||
if table.type_is_optional(return_type) {
|
g.write('$mr_styp $mr_var_name = ')
|
||||||
return_type = table.type_clear_extra(return_type)
|
g.is_assign = true
|
||||||
mr_styp := g.typ(return_type)
|
g.expr(assign_stmt.right[0])
|
||||||
g.write('$mr_styp $mr_var_name = (*(${mr_styp}*)')
|
g.is_assign = false
|
||||||
g.expr(assign_stmt.right[0])
|
if is_optional {
|
||||||
g.write('.data)')
|
g.or_block(mr_var_name, or_stmts, return_type)
|
||||||
}
|
|
||||||
else {
|
|
||||||
mr_styp := g.typ(return_type)
|
|
||||||
g.write('$mr_styp $mr_var_name = ')
|
|
||||||
g.expr(assign_stmt.right[0])
|
|
||||||
}
|
}
|
||||||
g.writeln(';')
|
g.writeln(';')
|
||||||
for i, ident in assign_stmt.left {
|
for i, ident in assign_stmt.left {
|
||||||
|
@ -612,7 +602,13 @@ fn (g mut Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
||||||
g.write('$styp ')
|
g.write('$styp ')
|
||||||
}
|
}
|
||||||
g.expr(ident)
|
g.expr(ident)
|
||||||
g.writeln(' = ${mr_var_name}.arg$i;')
|
if is_optional {
|
||||||
|
mr_styp2 := mr_styp[7..] // remove Option_
|
||||||
|
g.writeln(' = (*(${mr_styp2}*)${mr_var_name}.data).arg$i;')
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
g.writeln(' = ${mr_var_name}.arg$i;')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// `a := 1` | `a,b := 1,2`
|
// `a := 1` | `a,b := 1,2`
|
||||||
|
@ -621,8 +617,21 @@ fn (g mut Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
||||||
val := assign_stmt.right[i]
|
val := assign_stmt.right[i]
|
||||||
ident_var_info := ident.var_info()
|
ident_var_info := ident.var_info()
|
||||||
styp := g.typ(ident_var_info.typ)
|
styp := g.typ(ident_var_info.typ)
|
||||||
|
mut is_call := false
|
||||||
|
mut or_stmts := []ast.Stmt
|
||||||
|
mut return_type := table.void_type
|
||||||
|
match val {
|
||||||
|
ast.CallExpr {
|
||||||
|
is_call = true
|
||||||
|
or_stmts = it.or_block.stmts
|
||||||
|
return_type = it.return_type
|
||||||
|
}
|
||||||
|
else {}
|
||||||
|
}
|
||||||
|
gen_or := is_call && table.type_is_optional(return_type)
|
||||||
|
g.is_assign = true
|
||||||
if ident.kind == .blank_ident {
|
if ident.kind == .blank_ident {
|
||||||
if ast.expr_is_call(val) {
|
if is_call {
|
||||||
g.expr(val)
|
g.expr(val)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -648,7 +657,6 @@ fn (g mut Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
||||||
if is_decl {
|
if is_decl {
|
||||||
g.write('$styp ')
|
g.write('$styp ')
|
||||||
}
|
}
|
||||||
g.expr_var_name = ident.name
|
|
||||||
g.expr(ident)
|
g.expr(ident)
|
||||||
if g.autofree && right_sym.kind == .array && is_ident {
|
if g.autofree && right_sym.kind == .array && is_ident {
|
||||||
// `arr1 = arr2` => `arr1 = arr2.clone()`
|
// `arr1 = arr2` => `arr1 = arr2.clone()`
|
||||||
|
@ -674,11 +682,14 @@ fn (g mut Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
||||||
else if is_fixed_array_init {
|
else if is_fixed_array_init {
|
||||||
g.write('= {0}')
|
g.write('= {0}')
|
||||||
}
|
}
|
||||||
|
if gen_or {
|
||||||
|
g.or_block(ident.name, or_stmts, return_type)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
g.is_assign = false
|
||||||
g.writeln(';')
|
g.writeln(';')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
g.expr_var_name = ''
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (g mut Gen) gen_fn_decl(it ast.FnDecl) {
|
fn (g mut Gen) gen_fn_decl(it ast.FnDecl) {
|
||||||
|
@ -778,8 +789,8 @@ fn (g mut Gen) free_scope_vars(pos int) {
|
||||||
// println(var.name)
|
// println(var.name)
|
||||||
// println(var.typ)
|
// println(var.typ)
|
||||||
// if var.typ == 0 {
|
// if var.typ == 0 {
|
||||||
// // TODO why 0?
|
// // TODO why 0?
|
||||||
// continue
|
// continue
|
||||||
// }
|
// }
|
||||||
sym := g.table.get_type_symbol(var.typ)
|
sym := g.table.get_type_symbol(var.typ)
|
||||||
if sym.kind == .array && !table.type_is_optional(var.typ) {
|
if sym.kind == .array && !table.type_is_optional(var.typ) {
|
||||||
|
@ -794,9 +805,12 @@ fn (g mut Gen) free_scope_vars(pos int) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
// NOTE/TODO: assign_stmt multi returns variables have no expr
|
||||||
|
// since the type comes from the called fns return type
|
||||||
g.writeln('// other ' + t)
|
g.writeln('// other ' + t)
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
g.writeln('string_free($var.name); // autofreed')
|
g.writeln('string_free($var.name); // autofreed')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -888,49 +902,7 @@ fn (g mut Gen) expr(node ast.Expr) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast.AssignExpr {
|
ast.AssignExpr {
|
||||||
// g.write('/*assign_expr*/')
|
g.assign_expr(it)
|
||||||
if ast.expr_is_blank_ident(it.left) {
|
|
||||||
if ast.expr_is_call(it.val) {
|
|
||||||
g.expr(it.val)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
g.write('{${g.typ(it.left_type)} _ = ')
|
|
||||||
g.expr(it.val)
|
|
||||||
g.writeln(';}')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
g.is_assign_expr = true
|
|
||||||
if table.type_is_optional(it.right_type) {
|
|
||||||
g.right_is_opt = true
|
|
||||||
}
|
|
||||||
mut str_add := false
|
|
||||||
if it.left_type == table.string_type_idx && it.op == .plus_assign {
|
|
||||||
// str += str2 => `str = string_add(str, str2)`
|
|
||||||
g.expr(it.left)
|
|
||||||
g.write(' = string_add(')
|
|
||||||
str_add = true
|
|
||||||
}
|
|
||||||
g.assign_op = it.op
|
|
||||||
g.expr(it.left)
|
|
||||||
// arr[i] = val => `array_set(arr, i, val)`, not `array_get(arr, i) = val`
|
|
||||||
if !g.is_array_set && !str_add {
|
|
||||||
g.write(' $it.op.str() ')
|
|
||||||
}
|
|
||||||
else if str_add {
|
|
||||||
g.write(', ')
|
|
||||||
}
|
|
||||||
g.is_assign_expr = false
|
|
||||||
g.expr_with_cast(it.val, it.right_type, it.left_type)
|
|
||||||
if g.is_array_set {
|
|
||||||
g.write(' })')
|
|
||||||
g.is_array_set = false
|
|
||||||
}
|
|
||||||
else if str_add {
|
|
||||||
g.write(')')
|
|
||||||
}
|
|
||||||
g.right_is_opt = false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ast.Assoc {
|
ast.Assoc {
|
||||||
g.assoc(it)
|
g.assoc(it)
|
||||||
|
@ -1139,15 +1111,84 @@ fn (g mut Gen) typeof_expr(node ast.TypeOf) {
|
||||||
if sym.kind == .sum_type {
|
if sym.kind == .sum_type {
|
||||||
// When encountering a .sum_type, typeof() should be done at runtime,
|
// When encountering a .sum_type, typeof() should be done at runtime,
|
||||||
// because the subtype of the expression may change:
|
// because the subtype of the expression may change:
|
||||||
sum_type_idx := table.type_idx( node.expr_type )
|
sum_type_idx := table.type_idx(node.expr_type)
|
||||||
g.write('tos3( /* ${sym.name} */ v_typeof_sumtype_${sum_type_idx}( (')
|
g.write('tos3( /* ${sym.name} */ v_typeof_sumtype_${sum_type_idx}( (')
|
||||||
g.expr(node.expr)
|
g.expr(node.expr)
|
||||||
g.write(').typ ))')
|
g.write(').typ ))')
|
||||||
}else{
|
}
|
||||||
|
else {
|
||||||
g.write('tos3("${sym.name}")')
|
g.write('tos3("${sym.name}")')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn (g mut Gen) assign_expr(node ast.AssignExpr) {
|
||||||
|
// g.write('/*assign_expr*/')
|
||||||
|
mut is_call := false
|
||||||
|
mut or_stmts := []ast.Stmt
|
||||||
|
mut return_type := table.void_type
|
||||||
|
match node.val {
|
||||||
|
ast.CallExpr {
|
||||||
|
is_call = true
|
||||||
|
or_stmts = it.or_block.stmts
|
||||||
|
return_type = it.return_type
|
||||||
|
}
|
||||||
|
else {}
|
||||||
|
}
|
||||||
|
gen_or := is_call && table.type_is_optional(return_type)
|
||||||
|
tmp_opt := if gen_or { g.new_tmp_var() } else { '' }
|
||||||
|
if gen_or {
|
||||||
|
rstyp := g.typ(return_type)
|
||||||
|
g.write('$rstyp $tmp_opt =')
|
||||||
|
}
|
||||||
|
g.is_assign = true
|
||||||
|
if ast.expr_is_blank_ident(node.left) {
|
||||||
|
if is_call {
|
||||||
|
g.expr(node.val)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
g.write('{${g.typ(node.left_type)} _ = ')
|
||||||
|
g.expr(node.val)
|
||||||
|
g.writeln(';}')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
g.is_assign_expr = true
|
||||||
|
if table.type_is_optional(node.right_type) {
|
||||||
|
g.right_is_opt = true
|
||||||
|
}
|
||||||
|
mut str_add := false
|
||||||
|
if node.left_type == table.string_type_idx && node.op == .plus_assign {
|
||||||
|
// str += str2 => `str = string_add(str, str2)`
|
||||||
|
g.expr(node.left)
|
||||||
|
g.write(' = string_add(')
|
||||||
|
str_add = true
|
||||||
|
}
|
||||||
|
g.assign_op = node.op
|
||||||
|
g.expr(node.left)
|
||||||
|
// arr[i] = val => `array_set(arr, i, val)`, not `array_get(arr, i) = val`
|
||||||
|
if !g.is_array_set && !str_add {
|
||||||
|
g.write(' $node.op.str() ')
|
||||||
|
}
|
||||||
|
else if str_add {
|
||||||
|
g.write(', ')
|
||||||
|
}
|
||||||
|
g.is_assign_expr = false
|
||||||
|
g.expr_with_cast(node.val, node.right_type, node.left_type)
|
||||||
|
if g.is_array_set {
|
||||||
|
g.write(' })')
|
||||||
|
g.is_array_set = false
|
||||||
|
}
|
||||||
|
else if str_add {
|
||||||
|
g.write(')')
|
||||||
|
}
|
||||||
|
g.right_is_opt = false
|
||||||
|
}
|
||||||
|
if gen_or {
|
||||||
|
g.or_block(tmp_opt, or_stmts, return_type)
|
||||||
|
}
|
||||||
|
g.is_assign = false
|
||||||
|
}
|
||||||
|
|
||||||
fn (g mut Gen) infix_expr(node ast.InfixExpr) {
|
fn (g mut Gen) infix_expr(node ast.InfixExpr) {
|
||||||
// println('infix_expr() op="$node.op.str()" line_nr=$node.pos.line_nr')
|
// println('infix_expr() op="$node.op.str()" line_nr=$node.pos.line_nr')
|
||||||
// g.write('/*infix*/')
|
// g.write('/*infix*/')
|
||||||
|
@ -1638,7 +1679,7 @@ fn (g mut Gen) return_statement(node ast.Return) {
|
||||||
}
|
}
|
||||||
g.write('}')
|
g.write('}')
|
||||||
if fn_return_is_optional {
|
if fn_return_is_optional {
|
||||||
g.writeln(' }, sizeof($styp));')
|
g.write(' }, sizeof($styp))')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// normal return
|
// normal return
|
||||||
|
@ -2146,6 +2187,12 @@ fn (g mut Gen) insert_before(s string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (g mut Gen) call_expr(node ast.CallExpr) {
|
fn (g mut Gen) call_expr(node ast.CallExpr) {
|
||||||
|
gen_or := !g.is_assign && node.or_block.stmts.len > 0
|
||||||
|
tmp_opt := if gen_or { g.new_tmp_var() } else { '' }
|
||||||
|
if gen_or {
|
||||||
|
styp := g.typ(node.return_type)
|
||||||
|
g.write('$styp $tmp_opt = ')
|
||||||
|
}
|
||||||
if node.is_method {
|
if node.is_method {
|
||||||
// TODO: there are still due to unchecked exprs (opt/some fn arg)
|
// TODO: there are still due to unchecked exprs (opt/some fn arg)
|
||||||
if node.left_type == 0 {
|
if node.left_type == 0 {
|
||||||
|
@ -2206,9 +2253,6 @@ fn (g mut Gen) call_expr(node ast.CallExpr) {
|
||||||
// ///////
|
// ///////
|
||||||
g.call_args(node.args, node.exp_arg_types)
|
g.call_args(node.args, node.exp_arg_types)
|
||||||
g.write(')')
|
g.write(')')
|
||||||
if node.or_block.stmts.len > 0 {
|
|
||||||
g.or_block(node.or_block.stmts, node.return_type)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
mut name := node.name
|
mut name := node.name
|
||||||
|
@ -2267,29 +2311,24 @@ fn (g mut Gen) call_expr(node ast.CallExpr) {
|
||||||
g.call_args(node.args, node.exp_arg_types)
|
g.call_args(node.args, node.exp_arg_types)
|
||||||
g.write(')')
|
g.write(')')
|
||||||
}
|
}
|
||||||
if node.or_block.stmts.len > 0 {
|
|
||||||
g.or_block(node.or_block.stmts, node.return_type)
|
|
||||||
}
|
|
||||||
g.is_c_call = false
|
g.is_c_call = false
|
||||||
}
|
}
|
||||||
|
if gen_or {
|
||||||
|
g.or_block(tmp_opt, node.or_block.stmts, node.return_type)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (g mut Gen) or_block(stmts []ast.Stmt, return_type table.Type) {
|
// If user is accessing the return value eg. in assigment, pass the variable name.
|
||||||
// `foo() or { return }`
|
// If the user is not using the optional return value. We need to pass a temp var
|
||||||
var_name := if g.expr_var_name != '' { g.expr_var_name } else { g.new_tmp_var() }
|
// to access its fields (`.ok`, `.error` etc)
|
||||||
if g.expr_var_name == '' {
|
// `os.cp(...)` => `Option bool tmp = os__cp(...); if (!tmp.ok) { ... }`
|
||||||
// The user is not using the optional return value. We need to use a temp var
|
fn (g mut Gen) or_block(var_name string, stmts []ast.Stmt, return_type table.Type) {
|
||||||
// to access its fields (`.ok`, `.error` etc)
|
|
||||||
// `os.cp(...)` => `Option bool tmp = os__cp(...); if (!tmp.ok) { ... }`
|
|
||||||
styp := g.typ(return_type)
|
|
||||||
g.insert_before('$styp $var_name = ')
|
|
||||||
}
|
|
||||||
g.writeln(';') // or')
|
g.writeln(';') // or')
|
||||||
g.writeln('if (!${var_name}.ok) {')
|
g.writeln('if (!${var_name}.ok) {')
|
||||||
g.writeln('string err = ${var_name}.v_error;')
|
g.writeln('string err = ${var_name}.v_error;')
|
||||||
g.writeln('int errcode = ${var_name}.ecode;')
|
g.writeln('int errcode = ${var_name}.ecode;')
|
||||||
g.stmts(stmts)
|
g.stmts(stmts)
|
||||||
g.writeln('}')
|
g.write('}')
|
||||||
}
|
}
|
||||||
|
|
||||||
// `a in [1,2,3]` => `a == 1 || a == 2 || a == 3`
|
// `a in [1,2,3]` => `a == 1 || a == 2 || a == 3`
|
||||||
|
|
|
@ -54,6 +54,9 @@ struct varg_int {
|
||||||
int args[0];
|
int args[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// >> typeof() support for sum types
|
||||||
|
// << typeof() support for sum types
|
||||||
|
|
||||||
//
|
//
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
_vinit();
|
_vinit();
|
||||||
|
|
|
@ -12,7 +12,75 @@ void puts(string s);
|
||||||
void function2();
|
void function2();
|
||||||
void init_array();
|
void init_array();
|
||||||
void end();
|
void end();
|
||||||
|
// >> typeof() support for sum types
|
||||||
|
// << typeof() support for sum types
|
||||||
|
|
||||||
|
int function1() {
|
||||||
|
int a = 10 + 1;
|
||||||
|
int b = a + 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void foo(int a) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_user() {
|
||||||
|
User user = (User){
|
||||||
|
.name = tos3("Bob"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
User get_user() {
|
||||||
|
User user = (User){
|
||||||
|
.name = tos3(""),
|
||||||
|
};
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
void puts(string s) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void function2() {
|
||||||
|
int x = 0;
|
||||||
|
f64 f = 10.1;
|
||||||
|
string s = tos3("hi");
|
||||||
|
int m = 10;
|
||||||
|
x += 10;
|
||||||
|
x += 1;
|
||||||
|
m += 2;
|
||||||
|
function1();
|
||||||
|
if (true) {
|
||||||
|
foo(10);
|
||||||
|
x += 8;
|
||||||
|
}
|
||||||
|
if (false) {
|
||||||
|
foo(1);
|
||||||
|
} else {
|
||||||
|
puts(tos3("else"));
|
||||||
|
foo(100);
|
||||||
|
}
|
||||||
|
while (true) {
|
||||||
|
init_user();
|
||||||
|
}
|
||||||
|
bool e = 1 + 2 > 0;
|
||||||
|
bool e2 = 1 + 2 < 0;
|
||||||
|
int j = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_array() {
|
||||||
|
array_int nums = new_array_from_c_array(3, 3, sizeof(int), (int[3]){
|
||||||
|
4, 2, 3,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void end() {
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
_vinit();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _vinit() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -22,6 +22,17 @@ Option_int get_opt();
|
||||||
void User_foo(User* u);
|
void User_foo(User* u);
|
||||||
void println(string s);
|
void println(string s);
|
||||||
void handle_expr(Expr e);
|
void handle_expr(Expr e);
|
||||||
|
// >> typeof() support for sum types
|
||||||
|
char * v_typeof_sumtype_28(int sidx) { /* Expr */
|
||||||
|
switch(sidx) {
|
||||||
|
case 28: return "Expr";
|
||||||
|
case 26: return "IfExpr";
|
||||||
|
case 27: return "IntegerLiteral";
|
||||||
|
default: return "unknown Expr";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// << typeof() support for sum types
|
||||||
|
|
||||||
// TypeDecl
|
// TypeDecl
|
||||||
|
|
||||||
Option_int get_opt() {
|
Option_int get_opt() {
|
||||||
|
@ -76,8 +87,7 @@ int main(int argc, char** argv) {
|
||||||
string err = n.v_error;
|
string err = n.v_error;
|
||||||
int errcode = n.ecode;
|
int errcode = n.ecode;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
};
|
||||||
;
|
|
||||||
int a = /*opt*/(*(int*)n.data) + 3;
|
int a = /*opt*/(*(int*)n.data) + 3;
|
||||||
handle_expr(/* sum type cast */ (Expr) {.obj = memdup(&(IfExpr[]) {(IfExpr){
|
handle_expr(/* sum type cast */ (Expr) {.obj = memdup(&(IfExpr[]) {(IfExpr){
|
||||||
0}}, sizeof(IfExpr)), .typ = 26 /* IfExpr */});
|
0}}, sizeof(IfExpr)), .typ = 26 /* IfExpr */});
|
||||||
|
|
|
@ -14,6 +14,8 @@ typedef struct {
|
||||||
} multi_return_int_string;
|
} multi_return_int_string;
|
||||||
|
|
||||||
// end of definitions #endif
|
// end of definitions #endif
|
||||||
|
typedef Option Option_string;
|
||||||
|
typedef Option Option_multi_return_int_string;
|
||||||
multi_return_int_string mr_test();
|
multi_return_int_string mr_test();
|
||||||
int testa();
|
int testa();
|
||||||
string testb(int a);
|
string testb(int a);
|
||||||
|
@ -21,6 +23,11 @@ int testc(int a);
|
||||||
int Foo_testa(Foo* f);
|
int Foo_testa(Foo* f);
|
||||||
int Foo_testb(Foo* f);
|
int Foo_testb(Foo* f);
|
||||||
int Bar_testa(Bar* b);
|
int Bar_testa(Bar* b);
|
||||||
|
Option_string optional_a();
|
||||||
|
Option_string optional_b();
|
||||||
|
Option_multi_return_int_string optional_mr();
|
||||||
|
// >> typeof() support for sum types
|
||||||
|
// << typeof() support for sum types
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
_vinit();
|
_vinit();
|
||||||
|
@ -57,9 +64,28 @@ int main(int argc, char** argv) {
|
||||||
map_string_int m2 = new_map_init(2, sizeof(int), (string[2]){tos3("v"), tos3("lang"), }, (int[2]){1, 2, });
|
map_string_int m2 = new_map_init(2, sizeof(int), (string[2]){tos3("v"), tos3("lang"), }, (int[2]){1, 2, });
|
||||||
string ma1 = tos3("hello");
|
string ma1 = tos3("hello");
|
||||||
string ma2 = tos3("vlang");
|
string ma2 = tos3("vlang");
|
||||||
multi_return_int_string mr_578 = mr_test();
|
multi_return_int_string mr_566 = mr_test();
|
||||||
int mr1 = mr_578.arg0;
|
int mr1 = mr_566.arg0;
|
||||||
string mr2 = mr_578.arg1;
|
string mr2 = mr_566.arg1;
|
||||||
|
string opt1 = tos3("opt1");
|
||||||
|
Option_string opt2 = optional_a();
|
||||||
|
if (!opt2.ok) {
|
||||||
|
string err = opt2.v_error;
|
||||||
|
int errcode = opt2.ecode;
|
||||||
|
};
|
||||||
|
string opt3 = tos3("opt3");
|
||||||
|
Option_string opt4 = optional_b();
|
||||||
|
if (!opt4.ok) {
|
||||||
|
string err = opt4.v_error;
|
||||||
|
int errcode = opt4.ecode;
|
||||||
|
};
|
||||||
|
Option_multi_return_int_string mr_669 = optional_mr();
|
||||||
|
if (!mr_669.ok) {
|
||||||
|
string err = mr_669.v_error;
|
||||||
|
int errcode = mr_669.ecode;
|
||||||
|
};
|
||||||
|
int opt_mr1 = (*(multi_return_int_string*)mr_669.data).arg0;
|
||||||
|
string opt_mr12 = (*(multi_return_int_string*)mr_669.data).arg1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,5 +119,18 @@ int Bar_testa(Bar* b) {
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _vinit() {
|
Option_string optional_a() {
|
||||||
|
return opt_ok(& (string []) { tos3("111") }, sizeof(string));
|
||||||
|
}
|
||||||
|
|
||||||
|
Option_string optional_b() {
|
||||||
|
return opt_ok(& (string []) { tos3("222") }, sizeof(string));
|
||||||
|
}
|
||||||
|
|
||||||
|
Option_multi_return_int_string optional_mr() {
|
||||||
|
return opt_ok(& (multi_return_int_string []) { (multi_return_int_string){.arg0=1,.arg1=tos3("111")} }, sizeof(multi_return_int_string));
|
||||||
|
}
|
||||||
|
|
||||||
|
void _vinit() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,6 +42,11 @@ fn main() {
|
||||||
|
|
||||||
ma1, ma2 := 'hello', 'vlang'
|
ma1, ma2 := 'hello', 'vlang'
|
||||||
mr1, mr2 := mr_test()
|
mr1, mr2 := mr_test()
|
||||||
|
|
||||||
|
opt1, opt2, opt3, opt4 := 'opt1', optional_a(), 'opt3', optional_b()
|
||||||
|
opt_mr1, opt_mr12 := optional_mr() or {
|
||||||
|
// err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mr_test() (int, string) {
|
fn mr_test() (int, string) {
|
||||||
|
@ -82,3 +87,16 @@ struct Foo{
|
||||||
a string
|
a string
|
||||||
b Bar
|
b Bar
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn optional_a() ?string {
|
||||||
|
return '111'
|
||||||
|
}
|
||||||
|
|
||||||
|
fn optional_b() ?string {
|
||||||
|
return '222'
|
||||||
|
}
|
||||||
|
|
||||||
|
fn optional_mr() ?(int, string) {
|
||||||
|
return 1, '111'
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -1646,6 +1646,7 @@ fn (p mut Parser) parse_assign_rhs() []ast.Expr {
|
||||||
|
|
||||||
fn (p mut Parser) assign_stmt() ast.Stmt {
|
fn (p mut Parser) assign_stmt() ast.Stmt {
|
||||||
idents := p.parse_assign_lhs()
|
idents := p.parse_assign_lhs()
|
||||||
|
pos := p.tok.position()
|
||||||
op := p.tok.kind
|
op := p.tok.kind
|
||||||
p.next() // :=, =
|
p.next() // :=, =
|
||||||
exprs := p.parse_assign_rhs()
|
exprs := p.parse_assign_rhs()
|
||||||
|
@ -1676,7 +1677,7 @@ fn (p mut Parser) assign_stmt() ast.Stmt {
|
||||||
left: idents
|
left: idents
|
||||||
right: exprs
|
right: exprs
|
||||||
op: op
|
op: op
|
||||||
pos: p.tok.position()
|
pos: pos
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue