gen: fix nested `or`
parent
d3ce6fd2e7
commit
1633675c11
|
@ -2,7 +2,7 @@ import json
|
||||||
|
|
||||||
struct Employee {
|
struct Employee {
|
||||||
name string
|
name string
|
||||||
age int
|
age int
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_simple() {
|
fn test_simple() {
|
||||||
|
@ -11,23 +11,24 @@ fn test_simple() {
|
||||||
assert s == '{"name":"Peter","age":28}'
|
assert s == '{"name":"Peter","age":28}'
|
||||||
y := json.decode(Employee, s) or {
|
y := json.decode(Employee, s) or {
|
||||||
assert false
|
assert false
|
||||||
|
Employee{}
|
||||||
}
|
}
|
||||||
assert y.name == 'Peter'
|
assert y.name == 'Peter'
|
||||||
assert y.age == 28
|
assert y.age == 28
|
||||||
}
|
}
|
||||||
|
|
||||||
struct User2 {
|
struct User2 {
|
||||||
age int
|
age int
|
||||||
nums []int
|
nums []int
|
||||||
}
|
}
|
||||||
|
|
||||||
struct User {
|
struct User {
|
||||||
age int
|
age int
|
||||||
nums []int
|
nums []int
|
||||||
last_name string [json:lastName]
|
last_name string [json:lastName]
|
||||||
is_registered bool [json:IsRegistered]
|
is_registered bool [json:IsRegistered]
|
||||||
typ int [json:'type']
|
typ int [json:'type']
|
||||||
pets string [raw; json:'pet_animals']
|
pets string [raw; json:'pet_animals']
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_parse_user() {
|
fn test_parse_user() {
|
||||||
|
@ -51,8 +52,15 @@ fn test_parse_user() {
|
||||||
assert u.pets == '{"name":"Bob","animal":"Dog"}'
|
assert u.pets == '{"name":"Bob","animal":"Dog"}'
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_encode_user(){
|
fn test_encode_user() {
|
||||||
usr := User{ age: 10, nums: [1,2,3], last_name: 'Johnson', is_registered: true, typ: 0, pets: 'foo'}
|
usr := User{
|
||||||
|
age: 10
|
||||||
|
nums: [1, 2, 3]
|
||||||
|
last_name: 'Johnson'
|
||||||
|
is_registered: true
|
||||||
|
typ: 0
|
||||||
|
pets: 'foo'
|
||||||
|
}
|
||||||
expected := '{"age":10,"nums":[1,2,3],"lastName":"Johnson","IsRegistered":true,"type":0,"pet_animals":"foo"}'
|
expected := '{"age":10,"nums":[1,2,3],"lastName":"Johnson","IsRegistered":true,"type":0,"pet_animals":"foo"}'
|
||||||
out := json.encode(usr)
|
out := json.encode(usr)
|
||||||
println(out)
|
println(out)
|
||||||
|
@ -60,17 +68,17 @@ fn test_encode_user(){
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Color {
|
struct Color {
|
||||||
space string
|
space string
|
||||||
point string [raw]
|
point string [raw]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_raw_json_field() {
|
fn test_raw_json_field() {
|
||||||
color := json.decode(Color, '{"space": "YCbCr", "point": {"Y": 123}}') or {
|
color := json.decode(Color, '{"space": "YCbCr", "point": {"Y": 123}}') or {
|
||||||
println('text')
|
println('text')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
assert color.point == '{"Y":123}'
|
assert color.point == '{"Y":123}'
|
||||||
assert color.space == 'YCbCr'
|
assert color.space == 'YCbCr'
|
||||||
}
|
}
|
||||||
|
|
||||||
struct City {
|
struct City {
|
||||||
|
@ -79,7 +87,7 @@ struct City {
|
||||||
|
|
||||||
struct Country {
|
struct Country {
|
||||||
cities []City
|
cities []City
|
||||||
name string
|
name string
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_struct_in_struct() {
|
fn test_struct_in_struct() {
|
||||||
|
@ -92,6 +100,4 @@ fn test_struct_in_struct() {
|
||||||
assert country.cities[0].name == 'London'
|
assert country.cities[0].name == 'London'
|
||||||
assert country.cities[1].name == 'Manchester'
|
assert country.cities[1].name == 'Manchester'
|
||||||
println(country.cities)
|
println(country.cities)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,8 +43,9 @@ pub:
|
||||||
pub struct ExprStmt {
|
pub struct ExprStmt {
|
||||||
pub:
|
pub:
|
||||||
expr Expr
|
expr Expr
|
||||||
typ table.Type
|
|
||||||
pos token.Position
|
pos token.Position
|
||||||
|
pub mut:
|
||||||
|
typ table.Type
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct IntegerLiteral {
|
pub struct IntegerLiteral {
|
||||||
|
|
|
@ -848,7 +848,9 @@ pub fn (mut c Checker) call_fn(mut call_expr ast.CallExpr) table.Type {
|
||||||
c.error('json.decode: second argument needs to be a string', call_expr.pos)
|
c.error('json.decode: second argument needs to be a string', call_expr.pos)
|
||||||
}
|
}
|
||||||
typ := expr as ast.Type
|
typ := expr as ast.Type
|
||||||
return typ.typ.set_flag(.optional)
|
ret_type := typ.typ.set_flag(.optional)
|
||||||
|
call_expr.return_type = ret_type
|
||||||
|
return ret_type
|
||||||
}
|
}
|
||||||
// look for function in format `mod.fn` or `fn` (main/builtin)
|
// look for function in format `mod.fn` or `fn` (main/builtin)
|
||||||
mut f := table.Fn{}
|
mut f := table.Fn{}
|
||||||
|
@ -1012,17 +1014,15 @@ fn (mut c Checker) type_implements(typ, inter_typ table.Type, pos token.Position
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn (mut c Checker) check_expr_opt_call(x ast.Expr, xtype table.Type, is_return_used bool) {
|
pub fn (mut c Checker) check_expr_opt_call(expr ast.Expr, xtype table.Type, is_return_used bool) {
|
||||||
match x {
|
if expr is ast.CallExpr {
|
||||||
ast.CallExpr {
|
call_expr := expr as ast.CallExpr
|
||||||
if it.return_type.flag_is(.optional) {
|
if call_expr.return_type.flag_is(.optional) {
|
||||||
c.check_or_block(it, xtype, is_return_used)
|
c.check_or_block(call_expr, xtype, is_return_used)
|
||||||
} else if it.or_block.is_used && it.name != 'json.decode' { // TODO remove decode hack
|
} else if call_expr.or_block.is_used {
|
||||||
c.error('unexpected `or` block, the function `$it.name` does not return an optional',
|
c.error('unexpected `or` block, the function `$call_expr.name` does not return an optional',
|
||||||
it.pos)
|
call_expr.pos)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1052,12 +1052,13 @@ pub fn (mut c Checker) check_or_block(mut call_expr ast.CallExpr, ret_type table
|
||||||
}
|
}
|
||||||
match last_stmt {
|
match last_stmt {
|
||||||
ast.ExprStmt {
|
ast.ExprStmt {
|
||||||
type_fits := c.table.check(c.expr(it.expr), ret_type)
|
it.typ = c.expr(it.expr)
|
||||||
|
type_fits := c.table.check(it.typ, ret_type)
|
||||||
is_panic_or_exit := is_expr_panic_or_exit(it.expr)
|
is_panic_or_exit := is_expr_panic_or_exit(it.expr)
|
||||||
if type_fits || is_panic_or_exit {
|
if type_fits || is_panic_or_exit {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
type_name := c.table.get_type_symbol(c.expr(it.expr)).name
|
type_name := c.table.get_type_symbol(it.typ).name
|
||||||
expected_type_name := c.table.get_type_symbol(ret_type).name
|
expected_type_name := c.table.get_type_symbol(ret_type).name
|
||||||
c.error('wrong return type `$type_name` in the `or {}` block, expected `$expected_type_name`',
|
c.error('wrong return type `$type_name` in the `or {}` block, expected `$expected_type_name`',
|
||||||
it.pos)
|
it.pos)
|
||||||
|
@ -1509,9 +1510,9 @@ fn (mut c Checker) stmt(node ast.Stmt) {
|
||||||
c.enum_decl(it)
|
c.enum_decl(it)
|
||||||
}
|
}
|
||||||
ast.ExprStmt {
|
ast.ExprStmt {
|
||||||
etype := c.expr(it.expr)
|
it.typ = c.expr(it.expr)
|
||||||
c.expected_type = table.void_type
|
c.expected_type = table.void_type
|
||||||
c.check_expr_opt_call(it.expr, etype, false)
|
c.check_expr_opt_call(it.expr, it.typ, false)
|
||||||
}
|
}
|
||||||
ast.FnDecl {
|
ast.FnDecl {
|
||||||
c.fn_decl(it)
|
c.fn_decl(it)
|
||||||
|
@ -1986,6 +1987,7 @@ pub fn (mut c Checker) match_expr(mut node ast.MatchExpr) table.Type {
|
||||||
match branch.stmts[branch.stmts.len - 1] {
|
match branch.stmts[branch.stmts.len - 1] {
|
||||||
ast.ExprStmt {
|
ast.ExprStmt {
|
||||||
ret_type = c.expr(it.expr)
|
ret_type = c.expr(it.expr)
|
||||||
|
it.typ = ret_type
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// TODO: ask alex about this
|
// TODO: ask alex about this
|
||||||
|
@ -2106,14 +2108,14 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) table.Type {
|
||||||
if branch.stmts.len > 0 && branch.stmts[branch.stmts.len - 1] is ast.ExprStmt {
|
if branch.stmts.len > 0 && branch.stmts[branch.stmts.len - 1] is ast.ExprStmt {
|
||||||
last_expr := branch.stmts[branch.stmts.len - 1] as ast.ExprStmt
|
last_expr := branch.stmts[branch.stmts.len - 1] as ast.ExprStmt
|
||||||
c.expected_type = former_expected_type
|
c.expected_type = former_expected_type
|
||||||
expr_type := c.expr(last_expr.expr)
|
last_expr.typ = c.expr(last_expr.expr)
|
||||||
if expr_type != node.typ {
|
if last_expr.typ != node.typ {
|
||||||
// first branch of if expression
|
|
||||||
if node.typ == table.void_type {
|
if node.typ == table.void_type {
|
||||||
|
// first branch of if expression
|
||||||
node.is_expr = true
|
node.is_expr = true
|
||||||
node.typ = expr_type
|
node.typ = last_expr.typ
|
||||||
} else {
|
} else {
|
||||||
c.error('mismatched types `${c.table.type_to_str(node.typ)}` and `${c.table.type_to_str(expr_type)}`',
|
c.error('mismatched types `${c.table.type_to_str(node.typ)}` and `${c.table.type_to_str(last_expr.typ)}`',
|
||||||
node.pos)
|
node.pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -903,16 +903,11 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
||||||
g.is_assign_rhs = true
|
g.is_assign_rhs = true
|
||||||
g.expr(assign_stmt.right[0])
|
g.expr(assign_stmt.right[0])
|
||||||
g.is_assign_rhs = false
|
g.is_assign_rhs = false
|
||||||
if is_optional {
|
if is_optional && assign_stmt.right[0] is ast.CallExpr {
|
||||||
val := assign_stmt.right[0]
|
val := assign_stmt.right[0] as ast.CallExpr
|
||||||
match val {
|
or_stmts = val.or_block.stmts
|
||||||
ast.CallExpr {
|
return_type = val.return_type
|
||||||
or_stmts = it.or_block.stmts
|
g.or_block(mr_var_name, or_stmts, return_type)
|
||||||
return_type = it.return_type
|
|
||||||
g.or_block(mr_var_name, or_stmts, return_type)
|
|
||||||
}
|
|
||||||
else {}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
g.writeln(';')
|
g.writeln(';')
|
||||||
for i, ident in assign_stmt.left {
|
for i, ident in assign_stmt.left {
|
||||||
|
@ -969,7 +964,6 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
||||||
}
|
}
|
||||||
else {}
|
else {}
|
||||||
}
|
}
|
||||||
gen_or := is_call && return_type.flag_is(.optional)
|
|
||||||
g.is_assign_rhs = true
|
g.is_assign_rhs = true
|
||||||
if blank_assign {
|
if blank_assign {
|
||||||
if is_call {
|
if is_call {
|
||||||
|
@ -1060,9 +1054,6 @@ fn (mut g Gen) gen_assign_stmt(assign_stmt ast.AssignStmt) {
|
||||||
g.expr_with_cast(val, assign_stmt.left_types[i], ident_var_info.typ)
|
g.expr_with_cast(val, assign_stmt.left_types[i], ident_var_info.typ)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if gen_or {
|
|
||||||
g.or_block(ident.name, or_stmts, return_type)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
g.is_assign_rhs = false
|
g.is_assign_rhs = false
|
||||||
if g.inside_ternary == 0 {
|
if g.inside_ternary == 0 {
|
||||||
|
@ -2945,6 +2936,7 @@ fn (mut g Gen) insert_before_stmt(s string) {
|
||||||
// If the user is not using the optional return value. We need to pass a temp var
|
// If the user is not using the optional return value. We need to pass a temp var
|
||||||
// to access its fields (`.ok`, `.error` etc)
|
// to access its fields (`.ok`, `.error` etc)
|
||||||
// `os.cp(...)` => `Option bool tmp = os__cp(...); if (!tmp.ok) { ... }`
|
// `os.cp(...)` => `Option bool tmp = os__cp(...); if (!tmp.ok) { ... }`
|
||||||
|
// Returns the type of the last stmt
|
||||||
fn (mut g Gen) or_block(var_name string, stmts []ast.Stmt, return_type table.Type) {
|
fn (mut g Gen) or_block(var_name string, stmts []ast.Stmt, return_type table.Type) {
|
||||||
cvar_name := c_name(var_name)
|
cvar_name := c_name(var_name)
|
||||||
mr_styp := g.base_type(return_type)
|
mr_styp := g.base_type(return_type)
|
||||||
|
@ -2952,50 +2944,37 @@ fn (mut g Gen) or_block(var_name string, stmts []ast.Stmt, return_type table.Typ
|
||||||
g.writeln('if (!${cvar_name}.ok) {')
|
g.writeln('if (!${cvar_name}.ok) {')
|
||||||
g.writeln('\tstring err = ${cvar_name}.v_error;')
|
g.writeln('\tstring err = ${cvar_name}.v_error;')
|
||||||
g.writeln('\tint errcode = ${cvar_name}.ecode;')
|
g.writeln('\tint errcode = ${cvar_name}.ecode;')
|
||||||
last_type, type_of_last_expression := g.type_of_last_statement(stmts)
|
if stmts.len > 0 && stmts[stmts.len - 1] is ast.ExprStmt && (stmts[stmts.len - 1] as ast.ExprStmt).typ !=
|
||||||
if last_type == 'v.ast.ExprStmt' && type_of_last_expression != 'void' {
|
table.void_type {
|
||||||
g.indent++
|
g.indent++
|
||||||
for i, stmt in stmts {
|
for i, stmt in stmts {
|
||||||
if i == stmts.len - 1 {
|
if i == stmts.len - 1 {
|
||||||
g.indent--
|
expr_stmt := stmt as ast.ExprStmt
|
||||||
g.write('\t*(${mr_styp}*) ${cvar_name}.data = ')
|
g.stmt_path_pos << g.out.len
|
||||||
|
g.write('*(${mr_styp}*) ${cvar_name}.data = ')
|
||||||
|
is_opt_call := expr_stmt.expr is ast.CallExpr && expr_stmt.typ.flag_is(.optional)
|
||||||
|
if is_opt_call {
|
||||||
|
g.write('*(${mr_styp}*) ')
|
||||||
|
}
|
||||||
|
g.expr(expr_stmt.expr)
|
||||||
|
if is_opt_call {
|
||||||
|
g.write('.data')
|
||||||
|
}
|
||||||
|
if g.inside_ternary == 0 && !(expr_stmt.expr is ast.IfExpr) {
|
||||||
|
g.writeln(';')
|
||||||
|
}
|
||||||
|
g.stmt_path_pos.delete(g.stmt_path_pos.len - 1)
|
||||||
|
} else {
|
||||||
|
g.stmt(stmt)
|
||||||
}
|
}
|
||||||
g.stmt(stmt)
|
|
||||||
}
|
}
|
||||||
|
g.indent--
|
||||||
} else {
|
} else {
|
||||||
g.stmts(stmts)
|
g.stmts(stmts)
|
||||||
}
|
}
|
||||||
g.write('}')
|
g.write('}')
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) type_of_last_statement(stmts []ast.Stmt) (string, string) {
|
|
||||||
mut last_type := ''
|
|
||||||
mut last_expr_result_type := ''
|
|
||||||
if stmts.len > 0 {
|
|
||||||
last_stmt := stmts[stmts.len - 1]
|
|
||||||
last_type = typeof(last_stmt)
|
|
||||||
if last_type == 'v.ast.ExprStmt' {
|
|
||||||
match last_stmt {
|
|
||||||
ast.ExprStmt {
|
|
||||||
it_expr_type := typeof(it.expr)
|
|
||||||
if it_expr_type == 'v.ast.CallExpr' {
|
|
||||||
g.writeln('\t // typeof it_expr_type: $it_expr_type')
|
|
||||||
last_expr_result_type = g.type_of_call_expr(it.expr)
|
|
||||||
} else {
|
|
||||||
last_expr_result_type = it_expr_type
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
last_expr_result_type = last_type
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
g.writeln('\t// last_type: $last_type')
|
|
||||||
g.writeln('\t// last_expr_result_type: $last_expr_result_type')
|
|
||||||
return last_type, last_expr_result_type
|
|
||||||
}
|
|
||||||
|
|
||||||
fn (mut g Gen) type_of_call_expr(node ast.Expr) string {
|
fn (mut g Gen) type_of_call_expr(node ast.Expr) string {
|
||||||
match node {
|
match node {
|
||||||
ast.CallExpr { return g.typ(it.return_type) }
|
ast.CallExpr { return g.typ(it.return_type) }
|
||||||
|
|
|
@ -284,7 +284,14 @@ fn (mut g Gen) call_expr(node ast.CallExpr) {
|
||||||
if node.should_be_skipped {
|
if node.should_be_skipped {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
gen_or := !g.is_assign_rhs && node.or_block.stmts.len > 0
|
gen_or := node.or_block.stmts.len > 0
|
||||||
|
cur_line := if gen_or && g.is_assign_rhs {
|
||||||
|
line := g.go_before_stmt(0)
|
||||||
|
g.out.write(tabs[g.indent])
|
||||||
|
line
|
||||||
|
} else {
|
||||||
|
''
|
||||||
|
}
|
||||||
tmp_opt := if gen_or { g.new_tmp_var() } else { '' }
|
tmp_opt := if gen_or { g.new_tmp_var() } else { '' }
|
||||||
if gen_or {
|
if gen_or {
|
||||||
styp := g.typ(node.return_type)
|
styp := g.typ(node.return_type)
|
||||||
|
@ -297,6 +304,7 @@ fn (mut g Gen) call_expr(node ast.CallExpr) {
|
||||||
}
|
}
|
||||||
if gen_or {
|
if gen_or {
|
||||||
g.or_block(tmp_opt, node.or_block.stmts, node.return_type)
|
g.or_block(tmp_opt, node.or_block.stmts, node.return_type)
|
||||||
|
g.write('\n${cur_line}${tmp_opt}')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,7 @@ pub fn (mut p Parser) call_expr(language table.Language, mod string) ast.CallExp
|
||||||
// `foo() or {}``
|
// `foo() or {}``
|
||||||
mut or_stmts := []ast.Stmt{}
|
mut or_stmts := []ast.Stmt{}
|
||||||
if p.tok.kind == .key_orelse {
|
if p.tok.kind == .key_orelse {
|
||||||
|
was_inside_or_expr := p.inside_or_expr
|
||||||
p.inside_or_expr = true
|
p.inside_or_expr = true
|
||||||
p.next()
|
p.next()
|
||||||
p.open_scope()
|
p.open_scope()
|
||||||
|
@ -63,7 +64,7 @@ pub fn (mut p Parser) call_expr(language table.Language, mod string) ast.CallExp
|
||||||
is_or_block_used = true
|
is_or_block_used = true
|
||||||
or_stmts = p.parse_block_no_scope()
|
or_stmts = p.parse_block_no_scope()
|
||||||
p.close_scope()
|
p.close_scope()
|
||||||
p.inside_or_expr = false
|
p.inside_or_expr = was_inside_or_expr
|
||||||
}
|
}
|
||||||
if p.tok.kind == .question {
|
if p.tok.kind == .question {
|
||||||
// `foo()?`
|
// `foo()?`
|
||||||
|
|
|
@ -668,13 +668,12 @@ fn (mut p Parser) parse_multi_expr() ast.Stmt {
|
||||||
expr: p.assign_expr(collected[0])
|
expr: p.assign_expr(collected[0])
|
||||||
pos: epos
|
pos: epos
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
return ast.ExprStmt{
|
return ast.ExprStmt{
|
||||||
expr: p.assign_expr(ast.ConcatExpr{
|
expr: p.assign_expr(ast.ConcatExpr{
|
||||||
vals: collected
|
vals: collected
|
||||||
})
|
})
|
||||||
pos: epos
|
pos: epos
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if collected.len == 1 {
|
if collected.len == 1 {
|
||||||
|
@ -1000,12 +999,10 @@ fn (mut p Parser) dot_expr(left ast.Expr) ast.Expr {
|
||||||
is_used: is_or_block_used
|
is_used: is_or_block_used
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mut node := ast.Expr{}
|
|
||||||
node = mcall_expr
|
|
||||||
if is_filter {
|
if is_filter {
|
||||||
p.close_scope()
|
p.close_scope()
|
||||||
}
|
}
|
||||||
return node
|
return mcall_expr
|
||||||
}
|
}
|
||||||
sel_expr := ast.SelectorExpr{
|
sel_expr := ast.SelectorExpr{
|
||||||
expr: left
|
expr: left
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
struct Abc {
|
struct Abc {
|
||||||
x int
|
x int
|
||||||
}
|
}
|
||||||
|
@ -24,12 +23,18 @@ fn string_0(x int) ?string {
|
||||||
return '$x'
|
return '$x'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn b_0(b bool) ?bool {
|
||||||
|
if b == false {
|
||||||
|
return error('my error 4')
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
fn return_a_string() string {
|
fn return_a_string() string {
|
||||||
return 'abcdef'
|
return 'abcdef'
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
fn test_optional_int() {
|
fn test_optional_int() {
|
||||||
a := i_0(0) or {
|
a := i_0(0) or {
|
||||||
4999
|
4999
|
||||||
|
@ -41,6 +46,18 @@ fn test_optional_int() {
|
||||||
assert b == 4123
|
assert b == 4123
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
fn test_optional_bool() {
|
||||||
|
a := true && b_0(false) {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
assert a == true
|
||||||
|
b := false || b_0(true) {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
assert b == true
|
||||||
|
}
|
||||||
|
*/
|
||||||
fn test_optional_struct() {
|
fn test_optional_struct() {
|
||||||
sa := struct_0(0) or {
|
sa := struct_0(0) or {
|
||||||
Abc{7999}
|
Abc{7999}
|
||||||
|
@ -58,6 +75,10 @@ fn test_optional_with_statements_before_last_expression() {
|
||||||
Abc{12345}
|
Abc{12345}
|
||||||
}
|
}
|
||||||
assert s.x == 12345
|
assert s.x == 12345
|
||||||
|
b := b_0(true) or {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
assert b == true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_optional_with_fn_call_as_last_expression() {
|
fn test_optional_with_fn_call_as_last_expression() {
|
||||||
|
@ -75,3 +96,61 @@ fn test_optional_with_fn_call_last_expr_and_preceding_statements() {
|
||||||
}
|
}
|
||||||
assert s == 'abcdef'
|
assert s == 'abcdef'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn test_nested_optional() {
|
||||||
|
a := i_0(1) or {
|
||||||
|
b := i_0(0) or {
|
||||||
|
3
|
||||||
|
}
|
||||||
|
b
|
||||||
|
}
|
||||||
|
assert a == 1
|
||||||
|
b := i_0(0) or {
|
||||||
|
c := i_0(1) or {
|
||||||
|
3
|
||||||
|
}
|
||||||
|
c
|
||||||
|
}
|
||||||
|
assert b == 1
|
||||||
|
c := i_0(0) or {
|
||||||
|
d := i_0(0) or {
|
||||||
|
3
|
||||||
|
}
|
||||||
|
d
|
||||||
|
}
|
||||||
|
assert c == 3
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_nested_optional_with_opt_fn_call_as_last_value() {
|
||||||
|
a := i_0(1) or {
|
||||||
|
i_0(0) or {
|
||||||
|
3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert a == 1
|
||||||
|
b := i_0(0) or {
|
||||||
|
i_0(1) or {
|
||||||
|
3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert b == 1
|
||||||
|
c := i_0(0) or {
|
||||||
|
i_0(0) or {
|
||||||
|
3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert c == 3
|
||||||
|
// TODO Enable once optional in boolean expressions are working
|
||||||
|
// d := b_0(true) or {
|
||||||
|
// false && b_0(true) or {
|
||||||
|
// true
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// assert d == false
|
||||||
|
// e := b_0(true) or {
|
||||||
|
// true && b_0(true) or {
|
||||||
|
// false
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// assert e == false
|
||||||
|
}
|
||||||
|
|
|
@ -97,6 +97,41 @@ fn test_q() {
|
||||||
// assert foo_ok()? == true
|
// assert foo_ok()? == true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn or_return_val() int {
|
||||||
|
a := ret_none() or {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
fn or_return_error() ?int {
|
||||||
|
a := ret_none() or {
|
||||||
|
return error('Nope')
|
||||||
|
}
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
fn or_return_none() ?int {
|
||||||
|
a := ret_none() or {
|
||||||
|
return none
|
||||||
|
}
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_or_return() {
|
||||||
|
assert or_return_val() == 1
|
||||||
|
if _ := or_return_error() {
|
||||||
|
assert false
|
||||||
|
} else {
|
||||||
|
assert true
|
||||||
|
}
|
||||||
|
if _ := or_return_none() {
|
||||||
|
assert false
|
||||||
|
} else {
|
||||||
|
assert true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn test_reassignment() {
|
fn test_reassignment() {
|
||||||
mut x2 := foo_ok() or {
|
mut x2 := foo_ok() or {
|
||||||
assert false
|
assert false
|
||||||
|
@ -107,7 +142,7 @@ fn test_reassignment() {
|
||||||
assert x2 == 100
|
assert x2 == 100
|
||||||
x2 += 1
|
x2 += 1
|
||||||
assert x2 == 101
|
assert x2 == 101
|
||||||
///
|
//
|
||||||
mut x3 := 0
|
mut x3 := 0
|
||||||
x3 = foo_ok() or {
|
x3 = foo_ok() or {
|
||||||
assert false
|
assert false
|
||||||
|
@ -170,11 +205,9 @@ fn opt_ptr(a &int) ?&int {
|
||||||
|
|
||||||
fn test_opt_ptr() {
|
fn test_opt_ptr() {
|
||||||
if true {
|
if true {
|
||||||
|
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
else{
|
else {
|
||||||
|
|
||||||
}
|
}
|
||||||
a := 3
|
a := 3
|
||||||
mut r := opt_ptr(&a) or {
|
mut r := opt_ptr(&a) or {
|
||||||
|
@ -207,7 +240,6 @@ fn test_multi_return_opt() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
fn foo() ?void {
|
fn foo() ?void {
|
||||||
return error('something')
|
return error('something')
|
||||||
}
|
}
|
||||||
|
@ -220,7 +252,6 @@ fn test_optional_void() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn bar() ? {
|
fn bar() ? {
|
||||||
return error('bar error')
|
return error('bar error')
|
||||||
}
|
}
|
||||||
|
@ -232,3 +263,13 @@ fn test_optional_void_only_question() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn test_optional_void_with_empty_or() {
|
||||||
|
foo() or {}
|
||||||
|
assert true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_optional_val_with_empty_or() {
|
||||||
|
ret_none() or {}
|
||||||
|
assert true
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue