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`
|
||||
// multi return
|
||||
if assign_stmt.left.len > assign_stmt.right.len {
|
||||
right := c.expr(assign_stmt.right[0])
|
||||
right_sym := c.table.get_type_symbol(right)
|
||||
mr_info := right_sym.mr_info()
|
||||
if right_sym.kind != .multi_return {
|
||||
match assign_stmt.right[0] {
|
||||
ast.CallExpr {}
|
||||
else {
|
||||
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)
|
||||
}
|
||||
mut scope := c.file.scope.innermost(assign_stmt.pos.pos)
|
||||
for i, _ in assign_stmt.left {
|
||||
mut ident := assign_stmt.left[i]
|
||||
mut ident_var_info := ident.var_info()
|
||||
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 {
|
||||
var_type := c.expr(ident)
|
||||
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)
|
||||
}
|
||||
}
|
||||
ident_var_info.typ = val_type
|
||||
ident.info = ident_var_info
|
||||
assign_stmt.left[i] = ident
|
||||
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`
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
assign_stmt.right_types << val_type
|
||||
ident_var_info.typ = val_type
|
||||
ident.info = ident_var_info
|
||||
assign_stmt.left[i] = ident
|
||||
assign_stmt.right_types << val_type
|
||||
scope.update_var_type(ident.name, val_type)
|
||||
}
|
||||
}
|
||||
|
@ -538,7 +544,6 @@ fn (c mut Checker) stmt(node ast.Stmt) {
|
|||
}
|
||||
ast.AssignStmt {
|
||||
c.assign_stmt(mut it)
|
||||
c.expected_type = table.void_type
|
||||
}
|
||||
ast.Block {
|
||||
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
|
||||
for i, branch in node.branches {
|
||||
match branch.cond {
|
||||
ast.ParExpr{
|
||||
c.error('unnecessary `()` in an if condition. use `if expr {` instead of `if (expr) {`.', node.pos)
|
||||
ast.ParExpr {
|
||||
c.error('unnecessary `()` in an if condition. use `if expr {` instead of `if (expr) {`.', node.pos)
|
||||
}
|
||||
else {}
|
||||
}
|
||||
}
|
||||
typ := c.expr(branch.cond)
|
||||
if i < node.branches.len - 1 || !node.has_else {
|
||||
typ_sym := c.table.get_type_symbol(typ)
|
||||
|
|
|
@ -32,6 +32,7 @@ mut:
|
|||
tmp_count int
|
||||
variadic_args map[string]int
|
||||
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_array_set bool
|
||||
is_amp bool // for `&Foo{}` to merge PrefixExpr `&` and StructInit `Foo{}`; also for `&byte(0)` etc
|
||||
|
@ -43,7 +44,6 @@ mut:
|
|||
indent int
|
||||
empty_line bool
|
||||
is_test bool
|
||||
expr_var_name string
|
||||
assign_op token.Kind // *=, =, etc (for array_set)
|
||||
defer_stmts []ast.DeferStmt
|
||||
defer_ifdef string
|
||||
|
@ -122,7 +122,7 @@ pub fn (g mut Gen) write_typeof_functions() {
|
|||
for typ in g.table.types {
|
||||
if typ.kind == .sum_type {
|
||||
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(' switch(sidx) {')
|
||||
g.writeln(' case $tidx: return "$typ.name";')
|
||||
|
@ -163,12 +163,6 @@ pub fn (g mut Gen) typ(t table.Type) string {
|
|||
return styp
|
||||
}
|
||||
|
||||
/*
|
||||
pub fn (g &Gen) styp(t string) string {
|
||||
return t.replace('.', '__')
|
||||
}
|
||||
*/
|
||||
|
||||
//
|
||||
pub fn (g mut Gen) write_typedef_types() {
|
||||
for typ in g.table.types {
|
||||
|
@ -213,7 +207,7 @@ pub fn (g mut Gen) write_typedef_types() {
|
|||
else {
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -578,28 +572,24 @@ fn (g mut Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
|||
// g.write('/*assign_stmt*/')
|
||||
if assign_stmt.left.len > assign_stmt.right.len {
|
||||
// multi return
|
||||
mut or_stmts := []ast.Stmt
|
||||
mut return_type := table.void_type
|
||||
match assign_stmt.right[0] {
|
||||
ast.CallExpr {
|
||||
or_stmts = it.or_block.stmts
|
||||
return_type = it.return_type
|
||||
}
|
||||
else {
|
||||
panic('expected call')
|
||||
}
|
||||
else {}
|
||||
}
|
||||
is_optional := table.type_is_optional(return_type)
|
||||
mr_var_name := 'mr_$assign_stmt.pos.pos'
|
||||
g.expr_var_name = mr_var_name
|
||||
if table.type_is_optional(return_type) {
|
||||
return_type = table.type_clear_extra(return_type)
|
||||
mr_styp := g.typ(return_type)
|
||||
g.write('$mr_styp $mr_var_name = (*(${mr_styp}*)')
|
||||
g.expr(assign_stmt.right[0])
|
||||
g.write('.data)')
|
||||
}
|
||||
else {
|
||||
mr_styp := g.typ(return_type)
|
||||
g.write('$mr_styp $mr_var_name = ')
|
||||
g.expr(assign_stmt.right[0])
|
||||
mr_styp := g.typ(return_type)
|
||||
g.write('$mr_styp $mr_var_name = ')
|
||||
g.is_assign = true
|
||||
g.expr(assign_stmt.right[0])
|
||||
g.is_assign = false
|
||||
if is_optional {
|
||||
g.or_block(mr_var_name, or_stmts, return_type)
|
||||
}
|
||||
g.writeln(';')
|
||||
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.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`
|
||||
|
@ -621,8 +617,21 @@ fn (g mut Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
|||
val := assign_stmt.right[i]
|
||||
ident_var_info := ident.var_info()
|
||||
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 ast.expr_is_call(val) {
|
||||
if is_call {
|
||||
g.expr(val)
|
||||
}
|
||||
else {
|
||||
|
@ -648,7 +657,6 @@ fn (g mut Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
|||
if is_decl {
|
||||
g.write('$styp ')
|
||||
}
|
||||
g.expr_var_name = ident.name
|
||||
g.expr(ident)
|
||||
if g.autofree && right_sym.kind == .array && is_ident {
|
||||
// `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 {
|
||||
g.write('= {0}')
|
||||
}
|
||||
if gen_or {
|
||||
g.or_block(ident.name, or_stmts, return_type)
|
||||
}
|
||||
}
|
||||
g.is_assign = false
|
||||
g.writeln(';')
|
||||
}
|
||||
}
|
||||
g.expr_var_name = ''
|
||||
}
|
||||
|
||||
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.typ)
|
||||
// if var.typ == 0 {
|
||||
// // TODO why 0?
|
||||
// continue
|
||||
// // TODO why 0?
|
||||
// continue
|
||||
// }
|
||||
sym := g.table.get_type_symbol(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
|
||||
}
|
||||
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)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
g.writeln('string_free($var.name); // autofreed')
|
||||
}
|
||||
}
|
||||
|
@ -888,49 +902,7 @@ fn (g mut Gen) expr(node ast.Expr) {
|
|||
}
|
||||
}
|
||||
ast.AssignExpr {
|
||||
// g.write('/*assign_expr*/')
|
||||
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
|
||||
}
|
||||
g.assign_expr(it)
|
||||
}
|
||||
ast.Assoc {
|
||||
g.assoc(it)
|
||||
|
@ -1139,15 +1111,84 @@ fn (g mut Gen) typeof_expr(node ast.TypeOf) {
|
|||
if sym.kind == .sum_type {
|
||||
// When encountering a .sum_type, typeof() should be done at runtime,
|
||||
// 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.expr(node.expr)
|
||||
g.write(').typ ))')
|
||||
}else{
|
||||
}
|
||||
else {
|
||||
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) {
|
||||
// println('infix_expr() op="$node.op.str()" line_nr=$node.pos.line_nr')
|
||||
// g.write('/*infix*/')
|
||||
|
@ -1638,7 +1679,7 @@ fn (g mut Gen) return_statement(node ast.Return) {
|
|||
}
|
||||
g.write('}')
|
||||
if fn_return_is_optional {
|
||||
g.writeln(' }, sizeof($styp));')
|
||||
g.write(' }, sizeof($styp))')
|
||||
}
|
||||
}
|
||||
// normal return
|
||||
|
@ -2146,6 +2187,12 @@ fn (g mut Gen) insert_before(s string) {
|
|||
}
|
||||
|
||||
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 {
|
||||
// TODO: there are still due to unchecked exprs (opt/some fn arg)
|
||||
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.write(')')
|
||||
if node.or_block.stmts.len > 0 {
|
||||
g.or_block(node.or_block.stmts, node.return_type)
|
||||
}
|
||||
}
|
||||
else {
|
||||
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.write(')')
|
||||
}
|
||||
if node.or_block.stmts.len > 0 {
|
||||
g.or_block(node.or_block.stmts, node.return_type)
|
||||
}
|
||||
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) {
|
||||
// `foo() or { return }`
|
||||
var_name := if g.expr_var_name != '' { g.expr_var_name } else { g.new_tmp_var() }
|
||||
if g.expr_var_name == '' {
|
||||
// The user is not using the optional return value. We need to use a temp var
|
||||
// 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 = ')
|
||||
}
|
||||
// If user is accessing the return value eg. in assigment, pass the variable name.
|
||||
// If the user is not using the optional return value. We need to pass a temp var
|
||||
// to access its fields (`.ok`, `.error` etc)
|
||||
// `os.cp(...)` => `Option bool tmp = os__cp(...); if (!tmp.ok) { ... }`
|
||||
fn (g mut Gen) or_block(var_name string, stmts []ast.Stmt, return_type table.Type) {
|
||||
g.writeln(';') // or')
|
||||
g.writeln('if (!${var_name}.ok) {')
|
||||
g.writeln('string err = ${var_name}.v_error;')
|
||||
g.writeln('int errcode = ${var_name}.ecode;')
|
||||
g.stmts(stmts)
|
||||
g.writeln('}')
|
||||
g.write('}')
|
||||
}
|
||||
|
||||
// `a in [1,2,3]` => `a == 1 || a == 2 || a == 3`
|
||||
|
|
|
@ -54,6 +54,9 @@ struct varg_int {
|
|||
int args[0];
|
||||
};
|
||||
|
||||
// >> typeof() support for sum types
|
||||
// << typeof() support for sum types
|
||||
|
||||
//
|
||||
int main(int argc, char** argv) {
|
||||
_vinit();
|
||||
|
|
|
@ -12,7 +12,75 @@ void puts(string s);
|
|||
void function2();
|
||||
void init_array();
|
||||
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 println(string s);
|
||||
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
|
||||
|
||||
Option_int get_opt() {
|
||||
|
@ -76,8 +87,7 @@ int main(int argc, char** argv) {
|
|||
string err = n.v_error;
|
||||
int errcode = n.ecode;
|
||||
return 0;
|
||||
}
|
||||
;
|
||||
};
|
||||
int a = /*opt*/(*(int*)n.data) + 3;
|
||||
handle_expr(/* sum type cast */ (Expr) {.obj = memdup(&(IfExpr[]) {(IfExpr){
|
||||
0}}, sizeof(IfExpr)), .typ = 26 /* IfExpr */});
|
||||
|
|
|
@ -14,6 +14,8 @@ typedef struct {
|
|||
} multi_return_int_string;
|
||||
|
||||
// end of definitions #endif
|
||||
typedef Option Option_string;
|
||||
typedef Option Option_multi_return_int_string;
|
||||
multi_return_int_string mr_test();
|
||||
int testa();
|
||||
string testb(int a);
|
||||
|
@ -21,6 +23,11 @@ int testc(int a);
|
|||
int Foo_testa(Foo* f);
|
||||
int Foo_testb(Foo* f);
|
||||
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) {
|
||||
_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, });
|
||||
string ma1 = tos3("hello");
|
||||
string ma2 = tos3("vlang");
|
||||
multi_return_int_string mr_578 = mr_test();
|
||||
int mr1 = mr_578.arg0;
|
||||
string mr2 = mr_578.arg1;
|
||||
multi_return_int_string mr_566 = mr_test();
|
||||
int mr1 = mr_566.arg0;
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -93,5 +119,18 @@ int Bar_testa(Bar* b) {
|
|||
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'
|
||||
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) {
|
||||
|
@ -82,3 +87,16 @@ struct Foo{
|
|||
a string
|
||||
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 {
|
||||
idents := p.parse_assign_lhs()
|
||||
pos := p.tok.position()
|
||||
op := p.tok.kind
|
||||
p.next() // :=, =
|
||||
exprs := p.parse_assign_rhs()
|
||||
|
@ -1676,7 +1677,7 @@ fn (p mut Parser) assign_stmt() ast.Stmt {
|
|||
left: idents
|
||||
right: exprs
|
||||
op: op
|
||||
pos: p.tok.position()
|
||||
pos: pos
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue