unify catch fallback value sources
This commit is contained in:
+1
-1
@@ -102,7 +102,7 @@ fields. `_` is not a keyword member name.
|
||||
- bare void `return`, same-line `return value`, value blocks, value `if` with implicit single-expression branches, value loops, value `match`, and strictly value-producing `yield value` / `yield :label value`
|
||||
- `match` statements/expressions over enums, tagged unions, and scalars, including exhaustiveness checks, payload captures, pointer payload captures, multi-pattern arms, and scalar range patterns
|
||||
- a final `expand |value|:` enum arm or `expand |payload[, tag]|:` tagged-union arm generates one specialized arm for each variant not covered earlier; enum values and optional tags are comptime-known, while union payloads keep their concrete variant type
|
||||
- fallible `try`, fallback `catch`, and `catch |e| { ... }` handler blocks
|
||||
- fallible `try` and uniform `catch [|e|] value_source` fallbacks; captures work with ordinary expressions, value blocks, and value-producing `if` / loops / `match`
|
||||
- direct `return match ...` and `yield match ...` value-control-flow operands
|
||||
|
||||
#### bitwise operations
|
||||
|
||||
@@ -955,6 +955,11 @@
|
||||
- `noreturn` expressions coerce to any expected value type and terminate path analysis
|
||||
- `unreachable` always traps at runtime and reports an error during comptime evaluation
|
||||
|
||||
49. unify catch fallback value sources (implemented)
|
||||
- `expr catch [|error|] value_source` uses the same ordinary expression, value block, and
|
||||
value-producing control-flow forms with or without an error capture
|
||||
- void fallthrough and diverging `noreturn` fallbacks remain valid
|
||||
|
||||
## A word on unchecked casts
|
||||
|
||||
For casts that bypass safety checks, Honey provides builtin functions:
|
||||
|
||||
@@ -4737,23 +4737,21 @@ infer_compound_expr :: proc(
|
||||
value := infer_nested_expr(checker, expr.left, locals, pkg, file, demanded, local_types, left_expected)
|
||||
success := types.fallible_success(value, store)
|
||||
error_type := types.fallible_error(value, store)
|
||||
fallback_locals: [dynamic]Infer_Local
|
||||
fallback_locals.allocator = checker.allocator
|
||||
defer delete(fallback_locals)
|
||||
append(&fallback_locals, ..locals)
|
||||
if symbol.is_valid(expr.name) && expr.name != checker.sink_symbol && types.is_valid(error_type) {
|
||||
append(&fallback_locals, Infer_Local{name=expr.name, type=error_type, declared=error_type, statement=ast.INVALID_STMT})
|
||||
}
|
||||
if expr.right != ast.INVALID_EXPR {
|
||||
fallback := infer_nested_expr(checker, expr.right, locals, pkg, file, demanded, local_types)
|
||||
fallback := infer_nested_expr(checker, expr.right, fallback_locals[:], pkg, file, demanded, local_types)
|
||||
if types.is_valid(success) && types.is_valid(fallback) && !types.equal(success, fallback) {
|
||||
return types.widest(success, fallback)
|
||||
}
|
||||
return success if types.is_valid(success) else fallback
|
||||
}
|
||||
block_locals: [dynamic]Infer_Local
|
||||
block_locals.allocator = checker.allocator
|
||||
defer delete(block_locals)
|
||||
append(&block_locals, ..locals)
|
||||
capture_start := len(block_locals)
|
||||
if symbol.is_valid(expr.name) && expr.name != checker.sink_symbol && types.is_valid(error_type) {
|
||||
append(&block_locals, Infer_Local{name=expr.name, type=error_type, declared=error_type, statement=ast.INVALID_STMT})
|
||||
}
|
||||
infer_statements(checker, expr.body, &block_locals, local_types, pkg, file, demanded, &success, success)
|
||||
resize(&block_locals, capture_start)
|
||||
infer_statements(checker, expr.body, &fallback_locals, local_types, pkg, file, demanded, &success, success)
|
||||
return success
|
||||
case .Struct_Literal:
|
||||
value := types.INVALID
|
||||
@@ -8139,26 +8137,37 @@ build_compound_expr :: proc(
|
||||
block_handler := false
|
||||
void_fallthrough := false
|
||||
fallback := hir.INVALID_EXPR
|
||||
ctx := checker.current_build_ctx
|
||||
capture_start := 0
|
||||
if symbol.is_valid(expr.name) && expr.name != checker.sink_symbol {
|
||||
if ctx == nil {
|
||||
id := source.add(checker.diagnostics, expr.span, "a captured catch fallback is only valid in a function body")
|
||||
return invalid_hir_expr(checker, expr.span, id, success)
|
||||
}
|
||||
capture_start = len(ctx.locals^)
|
||||
error_type := types.fallible_error(channel_type, store)
|
||||
capture = append_build_local(ctx, expr.name, error_type, false, expr.span)
|
||||
}
|
||||
if expr.right != ast.INVALID_EXPR {
|
||||
fallback = build_nested_expr(checker, expr.right, locals, global_reads, calls, success, pkg, file)
|
||||
fallback_locals := locals
|
||||
if capture != hir.INVALID_LOCAL {
|
||||
fallback_locals = ctx.locals^[:]
|
||||
}
|
||||
fallback = build_nested_expr(checker, expr.right, fallback_locals, global_reads, calls, success, pkg, file)
|
||||
fallback = coerce_expr(checker, fallback, success, checker.module.exprs[fallback].span)
|
||||
} else {
|
||||
block_handler = true
|
||||
ctx := checker.current_build_ctx
|
||||
if ctx == nil {
|
||||
id := source.add(checker.diagnostics, expr.span, "catch block form is only valid in a function body")
|
||||
return invalid_hir_expr(checker, expr.span, id, success)
|
||||
}
|
||||
capture_start := len(ctx.locals^)
|
||||
error_type := types.fallible_error(channel_type, store)
|
||||
if symbol.is_valid(expr.name) && expr.name != checker.sink_symbol {
|
||||
capture = append_build_local(ctx, expr.name, error_type, false, expr.span)
|
||||
}
|
||||
handler: [dynamic]hir.Stmt_Id
|
||||
handler.allocator = checker.allocator
|
||||
fallback, _ = build_value_source(ctx, &handler, expr.body, success, expr.span, allow_exit=true)
|
||||
fallback, _ = build_value_source(ctx, &handler, expr.body, success, expr.span, value_control_flow=expr.integer != 0, allow_exit=true)
|
||||
void_fallthrough = fallback == hir.INVALID_EXPR && !all_paths_exit(&checker.module, handler[:])
|
||||
body = handler[:]
|
||||
}
|
||||
if capture != hir.INVALID_LOCAL {
|
||||
resize(ctx.locals, capture_start)
|
||||
}
|
||||
catch_mode := hir.CATCH_EXPRESSION
|
||||
|
||||
@@ -3763,14 +3763,16 @@ ct_eval_catch_expr :: proc(state: ^Ct_State, expr: ast.Expr, expected: types.Typ
|
||||
if value.active == 0 {
|
||||
return payload, ct_flow(.Normal), true
|
||||
}
|
||||
if expr.right != ast.INVALID_EXPR {
|
||||
return ct_eval_expr(state, expr.right, success, depth+1)
|
||||
}
|
||||
scope_start := len(state.bindings)
|
||||
if symbol.is_valid(expr.name) && expr.name != checker.sink_symbol && payload != INVALID_CT_VALUE {
|
||||
error_type := types.fallible_error(value.type, &checker.module.types)
|
||||
ct_bind_value(state, expr.name, error_type, payload, false)
|
||||
}
|
||||
if expr.right != ast.INVALID_EXPR {
|
||||
result, result_flow, result_ok := ct_eval_expr(state, expr.right, success, depth+1)
|
||||
ct_pop_bindings(state, scope_start)
|
||||
return result, result_flow, result_ok
|
||||
}
|
||||
handler, handler_ok := ct_exec_statements(state, expr.body, true, depth+1)
|
||||
ct_pop_bindings(state, scope_start)
|
||||
if !handler_ok {
|
||||
|
||||
@@ -468,9 +468,8 @@ lower_compound_expr :: proc(state: ^State, expr_id: hir.Expr_Id) -> ir.Instructi
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
} else {
|
||||
if expr.integer != hir.CATCH_EXPRESSION {
|
||||
capture := hir.as_local(expr.target)
|
||||
if capture != hir.INVALID_LOCAL && int(capture) < len(state.func_locals) {
|
||||
capture := hir.as_local(expr.target)
|
||||
if capture != hir.INVALID_LOCAL && int(capture) < len(state.func_locals) {
|
||||
error_type := state.func_locals[capture].type
|
||||
error_value := append_instruction(state, ir.Instruction{
|
||||
op=.Fallible_Error, span=expr.span, type=error_type,
|
||||
@@ -489,7 +488,8 @@ lower_compound_expr :: proc(state: ^State, expr_id: hir.Expr_Id) -> ir.Instructi
|
||||
target=ir.INVALID_REF, a=capture_slot, b=error_value,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
}
|
||||
}
|
||||
if expr.integer != hir.CATCH_EXPRESSION {
|
||||
lower_statements(state, expr.body)
|
||||
if expr.integer == hir.CATCH_VOID_FALLTHROUGH {
|
||||
append_instruction(state, ir.Instruction{
|
||||
|
||||
@@ -1470,8 +1470,9 @@ parse_expression_bp :: proc(parser: ^Parser, minimum_binding_power, nesting: int
|
||||
skip_newlines(parser)
|
||||
if operator.kind == .Keyword_Catch {
|
||||
left_expr := parser.module.exprs[left]
|
||||
capture := token.Token{}
|
||||
if _, pipe_ok := allow(parser, .Pipe); pipe_ok {
|
||||
capture := current(parser)
|
||||
capture = current(parser)
|
||||
if capture.kind != .Identifier && capture.kind != .Underscore {
|
||||
source.add(parser.diagnostics, capture.span, "expected a catch capture name")
|
||||
} else {
|
||||
@@ -1480,6 +1481,9 @@ parse_expression_bp :: proc(parser: ^Parser, minimum_binding_power, nesting: int
|
||||
if _, close_ok := allow(parser, .Pipe); !close_ok {
|
||||
source.add(parser.diagnostics, current(parser).span, "expected '|' after catch capture")
|
||||
}
|
||||
skip_newlines(parser)
|
||||
}
|
||||
if current(parser).kind == .Left_Brace {
|
||||
body := parse_block(parser)
|
||||
end := previous(parser)
|
||||
left = add_expr(parser, ast.Expr{
|
||||
@@ -1493,11 +1497,27 @@ parse_expression_bp :: proc(parser: ^Parser, minimum_binding_power, nesting: int
|
||||
})
|
||||
continue
|
||||
}
|
||||
if cf, is_cf := parse_value_control_flow(parser); is_cf {
|
||||
body := make([]ast.Stmt_Id, 1, parser.module.allocator)
|
||||
body[0] = cf
|
||||
left = add_expr(parser, ast.Expr{
|
||||
kind=.Catch,
|
||||
span=span_from(left_expr.span, parser.module.statements[cf].span),
|
||||
name=capture.symbol,
|
||||
left=left,
|
||||
right=ast.INVALID_EXPR,
|
||||
body=body,
|
||||
integer=1,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
})
|
||||
continue
|
||||
}
|
||||
right := parse_expression_bp(parser, right_power, nesting+1)
|
||||
right_expr := parser.module.exprs[right]
|
||||
left = add_expr(parser, ast.Expr{
|
||||
kind=.Catch,
|
||||
span=span_from(left_expr.span, right_expr.span),
|
||||
name=capture.symbol,
|
||||
left=left,
|
||||
right=right,
|
||||
diagnostic=source.INVALID_DIAGNOSTIC,
|
||||
|
||||
@@ -6097,6 +6097,72 @@ main func() i32 {
|
||||
testing.expect_value(t, state.exit_code, 0)
|
||||
}
|
||||
|
||||
@(test)
|
||||
catch_fallback_value_sources_compile_and_run :: proc(t: ^testing.T) {
|
||||
text := `Failure :: enum {
|
||||
bad
|
||||
worse
|
||||
}
|
||||
value func(fail bool, worse bool) i32 ! Failure {
|
||||
if fail {
|
||||
if worse { return .worse }
|
||||
return .bad
|
||||
}
|
||||
return 10
|
||||
}
|
||||
void_value func(fail bool) void ! Failure {
|
||||
if fail { return .bad }
|
||||
}
|
||||
capture_score func(err Failure) i32 {
|
||||
return match err {
|
||||
.bad: 1
|
||||
.worse: 2
|
||||
}
|
||||
}
|
||||
consume func(err Failure) void { _ = err }
|
||||
comptime_recovery func() i32 {
|
||||
return value(true, false) catch |err| capture_score(err)
|
||||
}
|
||||
main func() i32 {
|
||||
a :: value(true, false) catch 3
|
||||
b :: value(true, false) catch |err| capture_score(err)
|
||||
c :: value(true, true) catch |err| match err {
|
||||
.bad: 4
|
||||
.worse: 5
|
||||
}
|
||||
d :: value(true, false) catch if true {
|
||||
yield 6
|
||||
} else {
|
||||
yield 7
|
||||
}
|
||||
e :: value(true, false) catch {
|
||||
yield 8
|
||||
}
|
||||
f :: value(true, false) catch |err| {
|
||||
_ = err
|
||||
yield 9
|
||||
}
|
||||
g :: value(false, false) catch unreachable
|
||||
h :: value(false, false) catch |_| unreachable
|
||||
void_value(true) catch |err| consume(err)
|
||||
void_value(false) catch {}
|
||||
ct i32 :: $comptime_recovery()
|
||||
return a + b + c + d + e + f + g + h + ct - 53
|
||||
}
|
||||
`
|
||||
directory := "/tmp/brolang-test-catch-value-sources"
|
||||
main_path := "/tmp/brolang-test-catch-value-sources/main.bro"
|
||||
output := "/tmp/brolang-test-catch-value-sources-output"
|
||||
_ = os2.remove_all(directory)
|
||||
defer _ = os2.remove_all(directory)
|
||||
defer _ = os.remove(output)
|
||||
testing.expect(t, os.make_directory(directory) == nil)
|
||||
testing.expect(t, os.write_entire_file(main_path, transmute([]byte)text))
|
||||
testing.expect_value(t, compiler_core.compile_package(directory, output), 0)
|
||||
state := run_executable(output)
|
||||
testing.expect_value(t, state.exit_code, 0)
|
||||
}
|
||||
|
||||
@(test)
|
||||
fallible_void_fallthrough_compiles_at_runtime_and_comptime :: proc(t: ^testing.T) {
|
||||
text := `Failure :: enum {
|
||||
|
||||
@@ -33,6 +33,8 @@ module.exports = grammar({
|
||||
[$.array_type, $.expression],
|
||||
[$.array_type, $.array_literal],
|
||||
[$.expression_statement, $.parenthesized_expression],
|
||||
[$.assignment_statement, $.expression_statement],
|
||||
[$.labeled_block, $.expression],
|
||||
[$.block, $.tuple_literal, $.anonymous_record_literal],
|
||||
[$.field_initializer, $.expression],
|
||||
[$.capture_list, $.expression],
|
||||
@@ -310,8 +312,8 @@ module.exports = grammar({
|
||||
field('value', $._value),
|
||||
),
|
||||
|
||||
break_statement: $ => seq('break', optional(seq(':', field('label', $.identifier)))),
|
||||
continue_statement: $ => seq('continue', optional(seq(':', field('label', $.identifier)))),
|
||||
break_statement: $ => prec.right(seq('break', optional(seq(':', field('label', $.identifier))))),
|
||||
continue_statement: $ => prec.right(seq('continue', optional(seq(':', field('label', $.identifier))))),
|
||||
|
||||
defer_statement: $ => choice(
|
||||
seq('defer', repeat($._newline), field('body', $.statement)),
|
||||
@@ -468,7 +470,7 @@ module.exports = grammar({
|
||||
|
||||
binary_expression: $ => choice(
|
||||
prec.left(PREC.RANGE, seq(field('left', $.expression), field('operator', choice('..', '..=')), repeat($._newline), field('right', $.expression))),
|
||||
prec.left(PREC.FALLBACK, seq(field('left', $.expression), field('operator', choice('orelse', 'catch')), repeat($._newline), field('right', $.expression))),
|
||||
prec.left(PREC.FALLBACK, seq(field('left', $.expression), field('operator', 'orelse'), repeat($._newline), field('right', $.expression))),
|
||||
prec.left(PREC.OR, seq(field('left', $.expression), 'or', repeat($._newline), field('right', $.expression))),
|
||||
prec.left(PREC.AND, seq(field('left', $.expression), 'and', repeat($._newline), field('right', $.expression))),
|
||||
prec.left(PREC.COMPARE, seq(field('left', $.expression), field('operator', choice('==', '!=', '<', '<=', '>', '>=')), repeat($._newline), field('right', $.expression))),
|
||||
@@ -481,11 +483,16 @@ module.exports = grammar({
|
||||
catch_expression: $ => prec.left(PREC.FALLBACK, seq(
|
||||
field('value', $.expression),
|
||||
'catch',
|
||||
'|',
|
||||
field('name', choice($.identifier, $.sink)),
|
||||
'|',
|
||||
optional(field('capture', $.error_capture)),
|
||||
repeat($._newline),
|
||||
field('body', $.block),
|
||||
field('fallback', choice(
|
||||
$.block,
|
||||
$.if_statement,
|
||||
$.while_statement,
|
||||
$.for_statement,
|
||||
$.match_statement,
|
||||
$.expression,
|
||||
)),
|
||||
)),
|
||||
|
||||
unary_expression: $ => prec(PREC.PREFIX, seq(
|
||||
|
||||
@@ -2072,72 +2072,80 @@
|
||||
]
|
||||
},
|
||||
"break_statement": {
|
||||
"type": "SEQ",
|
||||
"members": [
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "break"
|
||||
},
|
||||
{
|
||||
"type": "CHOICE",
|
||||
"members": [
|
||||
{
|
||||
"type": "SEQ",
|
||||
"members": [
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": ":"
|
||||
},
|
||||
{
|
||||
"type": "FIELD",
|
||||
"name": "label",
|
||||
"content": {
|
||||
"type": "SYMBOL",
|
||||
"name": "identifier"
|
||||
"type": "PREC_RIGHT",
|
||||
"value": 0,
|
||||
"content": {
|
||||
"type": "SEQ",
|
||||
"members": [
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "break"
|
||||
},
|
||||
{
|
||||
"type": "CHOICE",
|
||||
"members": [
|
||||
{
|
||||
"type": "SEQ",
|
||||
"members": [
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": ":"
|
||||
},
|
||||
{
|
||||
"type": "FIELD",
|
||||
"name": "label",
|
||||
"content": {
|
||||
"type": "SYMBOL",
|
||||
"name": "identifier"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "BLANK"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "BLANK"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"continue_statement": {
|
||||
"type": "SEQ",
|
||||
"members": [
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "continue"
|
||||
},
|
||||
{
|
||||
"type": "CHOICE",
|
||||
"members": [
|
||||
{
|
||||
"type": "SEQ",
|
||||
"members": [
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": ":"
|
||||
},
|
||||
{
|
||||
"type": "FIELD",
|
||||
"name": "label",
|
||||
"content": {
|
||||
"type": "SYMBOL",
|
||||
"name": "identifier"
|
||||
"type": "PREC_RIGHT",
|
||||
"value": 0,
|
||||
"content": {
|
||||
"type": "SEQ",
|
||||
"members": [
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "continue"
|
||||
},
|
||||
{
|
||||
"type": "CHOICE",
|
||||
"members": [
|
||||
{
|
||||
"type": "SEQ",
|
||||
"members": [
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": ":"
|
||||
},
|
||||
{
|
||||
"type": "FIELD",
|
||||
"name": "label",
|
||||
"content": {
|
||||
"type": "SYMBOL",
|
||||
"name": "identifier"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "BLANK"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "BLANK"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"defer_statement": {
|
||||
"type": "CHOICE",
|
||||
@@ -3299,17 +3307,8 @@
|
||||
"type": "FIELD",
|
||||
"name": "operator",
|
||||
"content": {
|
||||
"type": "CHOICE",
|
||||
"members": [
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "orelse"
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "catch"
|
||||
}
|
||||
]
|
||||
"type": "STRING",
|
||||
"value": "orelse"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -3692,29 +3691,20 @@
|
||||
"value": "catch"
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "|"
|
||||
},
|
||||
{
|
||||
"type": "FIELD",
|
||||
"name": "name",
|
||||
"content": {
|
||||
"type": "CHOICE",
|
||||
"members": [
|
||||
{
|
||||
"type": "CHOICE",
|
||||
"members": [
|
||||
{
|
||||
"type": "FIELD",
|
||||
"name": "capture",
|
||||
"content": {
|
||||
"type": "SYMBOL",
|
||||
"name": "identifier"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "sink"
|
||||
"name": "error_capture"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "STRING",
|
||||
"value": "|"
|
||||
},
|
||||
{
|
||||
"type": "BLANK"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "REPEAT",
|
||||
@@ -3725,10 +3715,35 @@
|
||||
},
|
||||
{
|
||||
"type": "FIELD",
|
||||
"name": "body",
|
||||
"name": "fallback",
|
||||
"content": {
|
||||
"type": "SYMBOL",
|
||||
"name": "block"
|
||||
"type": "CHOICE",
|
||||
"members": [
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "block"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "if_statement"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "while_statement"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "for_statement"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "match_statement"
|
||||
},
|
||||
{
|
||||
"type": "SYMBOL",
|
||||
"name": "expression"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -5481,6 +5496,14 @@
|
||||
"expression_statement",
|
||||
"parenthesized_expression"
|
||||
],
|
||||
[
|
||||
"assignment_statement",
|
||||
"expression_statement"
|
||||
],
|
||||
[
|
||||
"labeled_block",
|
||||
"expression"
|
||||
],
|
||||
[
|
||||
"block",
|
||||
"tuple_literal",
|
||||
|
||||
@@ -290,10 +290,6 @@
|
||||
"type": ">>",
|
||||
"named": false
|
||||
},
|
||||
{
|
||||
"type": "catch",
|
||||
"named": false
|
||||
},
|
||||
{
|
||||
"type": "orelse",
|
||||
"named": false
|
||||
@@ -436,26 +432,42 @@
|
||||
"type": "catch_expression",
|
||||
"named": true,
|
||||
"fields": {
|
||||
"body": {
|
||||
"capture": {
|
||||
"multiple": false,
|
||||
"required": false,
|
||||
"types": [
|
||||
{
|
||||
"type": "error_capture",
|
||||
"named": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"fallback": {
|
||||
"multiple": false,
|
||||
"required": true,
|
||||
"types": [
|
||||
{
|
||||
"type": "block",
|
||||
"named": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"name": {
|
||||
"multiple": false,
|
||||
"required": true,
|
||||
"types": [
|
||||
},
|
||||
{
|
||||
"type": "identifier",
|
||||
"type": "expression",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "sink",
|
||||
"type": "for_statement",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "if_statement",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "match_statement",
|
||||
"named": true
|
||||
},
|
||||
{
|
||||
"type": "while_statement",
|
||||
"named": true
|
||||
}
|
||||
]
|
||||
|
||||
+1047997
-324168
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,110 @@
|
||||
==================
|
||||
Catch value sources
|
||||
==================
|
||||
|
||||
recover func() void {
|
||||
a :: fail() catch |err| handle(err)
|
||||
b :: fail() catch |err| match err {
|
||||
.bad: 1
|
||||
else: 2
|
||||
}
|
||||
c :: fail() catch { yield 3 }
|
||||
d :: fail() catch if true { yield 4 } else { yield 5 }
|
||||
}
|
||||
|
||||
---
|
||||
|
||||
(source_file
|
||||
(function_declaration
|
||||
(identifier)
|
||||
(parameter_list)
|
||||
(type
|
||||
(builtin_type))
|
||||
(block
|
||||
(statement
|
||||
(constant_declaration
|
||||
(identifier)
|
||||
(expression
|
||||
(catch_expression
|
||||
(expression
|
||||
(call_expression
|
||||
(expression
|
||||
(identifier))
|
||||
(argument_list)))
|
||||
(error_capture
|
||||
(identifier))
|
||||
(expression
|
||||
(call_expression
|
||||
(expression
|
||||
(identifier))
|
||||
(argument_list
|
||||
(expression
|
||||
(identifier)))))))))
|
||||
(statement
|
||||
(constant_declaration
|
||||
(identifier)
|
||||
(expression
|
||||
(catch_expression
|
||||
(expression
|
||||
(call_expression
|
||||
(expression
|
||||
(identifier))
|
||||
(argument_list)))
|
||||
(error_capture
|
||||
(identifier))
|
||||
(match_statement
|
||||
(expression
|
||||
(identifier))
|
||||
(match_arm
|
||||
(expression
|
||||
(enum_literal
|
||||
(identifier)))
|
||||
(statement
|
||||
(expression_statement
|
||||
(expression
|
||||
(integer)))))
|
||||
(match_arm
|
||||
(statement
|
||||
(expression_statement
|
||||
(expression
|
||||
(integer))))))))))
|
||||
(statement
|
||||
(constant_declaration
|
||||
(identifier)
|
||||
(expression
|
||||
(catch_expression
|
||||
(expression
|
||||
(call_expression
|
||||
(expression
|
||||
(identifier))
|
||||
(argument_list)))
|
||||
(block
|
||||
(statement
|
||||
(yield_statement
|
||||
(expression
|
||||
(integer)))))))))
|
||||
(statement
|
||||
(constant_declaration
|
||||
(identifier)
|
||||
(expression
|
||||
(catch_expression
|
||||
(expression
|
||||
(call_expression
|
||||
(expression
|
||||
(identifier))
|
||||
(argument_list)))
|
||||
(if_statement
|
||||
(expression
|
||||
(boolean))
|
||||
(statement
|
||||
(block
|
||||
(statement
|
||||
(yield_statement
|
||||
(expression
|
||||
(integer))))))
|
||||
(statement
|
||||
(block
|
||||
(statement
|
||||
(yield_statement
|
||||
(expression
|
||||
(integer))))))))))))))
|
||||
Reference in New Issue
Block a user