typedef struct CaseToBlock {
AstTyped *original_value;
AstBinaryOp *comparison;
- AstBlock *block;
+ AstSwitchCase *casestmt;
} CaseToBlock;
struct AstSwitchCase {
// NOTE: All expressions that end up in this block
bh_arr(AstTyped *) values;
- AstBlock *block;
+ union {
+ AstBlock *block;
+ AstTyped *expr;
+ };
AstLocal *capture;
+ Scope *scope; // Scope for the capture
b32 is_default: 1; // Could this be inferred by the values array being null?
b32 capture_is_by_pointer: 1;
+ b32 body_is_expr : 1;
};
struct AstSwitch {
- AstNode_base;
+ AstTyped_base;
Scope *scope;
AstNode* initialization;
// been handled.
u8 *union_variants_handled;
+ b32 is_expr;
+
union {
struct {
// NOTE: This is a mapping from the compile time known case value
}
}
+ if (node->kind == Ast_Kind_Switch) {
+ AstSwitch *switchnode = (AstSwitch *) node;
+ if (!switchnode->is_expr) return TYPE_MATCH_FAILED;
+
+ if (switchnode->cases == NULL) return TYPE_MATCH_YIELD;
+
+ bh_arr_each(AstSwitchCase *, pcasestmt, switchnode->cases) {
+ AstSwitchCase *casestmt = *pcasestmt;
+ if (!casestmt->body_is_expr) continue;
+
+ switch (unify_node_and_type_(&casestmt->expr, type, permanent)) {
+ case TYPE_MATCH_SUCCESS: break;
+ case TYPE_MATCH_FAILED: return TYPE_MATCH_FAILED;
+ case TYPE_MATCH_YIELD: return TYPE_MATCH_YIELD;
+ }
+ }
+
+ if (switchnode->default_case) {
+ switch (unify_node_and_type_((AstTyped **) &switchnode->default_case, type, permanent)) {
+ case TYPE_MATCH_SUCCESS: break;
+ case TYPE_MATCH_FAILED: return TYPE_MATCH_FAILED;
+ case TYPE_MATCH_YIELD: return TYPE_MATCH_YIELD;
+ }
+ }
+
+ if (permanent) switchnode->type = type;
+ return TYPE_MATCH_SUCCESS;
+ }
// If the destination type is an optional, and the node's type is a value of
// the same underlying type, then we can construct an optional with a value
return Check_Success;
}
-static b32 add_case_to_switch_statement(AstSwitch* switchnode, u64 case_value, AstBlock* block, OnyxFilePos pos) {
+static b32 add_case_to_switch_statement(AstSwitch* switchnode, u64 case_value, AstSwitchCase* casestmt, OnyxFilePos pos) {
assert(switchnode->switch_kind == Switch_Kind_Integer || switchnode->switch_kind == Switch_Kind_Union);
switchnode->min_case = bh_min(switchnode->min_case, case_value);
return 1;
}
- bh_imap_put(&switchnode->case_map, case_value, (u64) block);
+ bh_imap_put(&switchnode->case_map, case_value, (u64) casestmt);
return 0;
}
AstSwitchCase *sc = switchnode->cases[i];
if (sc->capture && bh_arr_length(sc->values) != 1) {
- ERROR(sc->token->pos, "Expected exactly one value in switch-case when using a capture, i.e. `case X => Y { ... }`.");
+ ERROR(sc->token->pos, "Expected exactly one value in switch-case when using a capture, i.e. `case value: X { ... }`.");
}
if (sc->capture && switchnode->switch_kind != Switch_Kind_Union) {
// NOTE: This is inclusive!!!!
fori (case_value, lower, upper + 1) {
- if (add_case_to_switch_statement(switchnode, case_value, sc->block, rl->token->pos))
+ if (add_case_to_switch_statement(switchnode, case_value, sc, rl->token->pos))
return Check_Error;
}
if (!is_valid)
ERROR_((*value)->token->pos, "Case statement expected compile time known integer. Got '%s'.", onyx_ast_node_kind_string((*value)->kind));
- if (add_case_to_switch_statement(switchnode, integer_value, sc->block, sc->block->token->pos))
+ if (add_case_to_switch_statement(switchnode, integer_value, sc, sc->block->token->pos))
return Check_Error;
break;
if (found) break;
CaseToBlock ctb;
- ctb.block = sc->block;
+ ctb.casestmt = sc;
ctb.original_value = *value;
ctb.comparison = make_binary_op(context.ast_alloc, Binary_Op_Equal, switchnode->expr, *value);
ctb.comparison->token = (*value)->token;
sc->flags |= Ast_Flag_Has_Been_Checked;
check_switch_case_block:
- CHECK(block, sc->block);
+ if (switchnode->is_expr) {
+ if (!sc->body_is_expr) {
+ onyx_report_error(sc->token->pos, Error_Critical, "Inside a switch expression, all cases must return a value.");
+ ERROR(sc->token->pos, "Change the case statement to look like 'case X => expr'.");
+ }
+ } else {
+ if (sc->body_is_expr) {
+ ERROR(sc->token->pos, "This kind of case statement is only allowed in switch expressions, not switch statements.");
+ }
+ }
+
+ if (sc->body_is_expr) {
+ CHECK(expression, &sc->expr);
+ if (switchnode->type == NULL) {
+ switchnode->type = resolve_expression_type(sc->expr);
+ } else {
+ TYPE_CHECK(&sc->expr, switchnode->type) {
+ ERROR_(sc->token->pos, "Expected case expression to be of type '%s', got '%s'.",
+ type_get_name(switchnode->type),
+ type_get_name(sc->expr->type));
+ }
+ }
+
+ } else {
+ CHECK(block, sc->block);
+ }
switchnode->yield_return_index += 1;
}
if (switchnode->default_case) {
- CHECK(block, switchnode->default_case);
+ if (switchnode->is_expr) {
+ AstTyped **default_case = (AstTyped **) &switchnode->default_case;
+ CHECK(expression, default_case);
+
+ if (switchnode->type) {
+ TYPE_CHECK(default_case, switchnode->type) {
+ ERROR_((*default_case)->token->pos, "Expected case expression to be of type '%s', got '%s'.",
+ type_get_name(switchnode->type),
+ type_get_name((*default_case)->type));
+ }
+ }
+
+ } else {
+ CHECK(block, switchnode->default_case);
+ }
} else if (switchnode->switch_kind == Switch_Kind_Union) {
// If there is no default case, and this is a union switch,
break;
}
+ case Ast_Kind_Switch: {
+ AstSwitch* switch_node = (AstSwitch *) expr;
+ assert(switch_node->is_expr);
+
+ CHECK(switch, switch_node);
+ break;
+ }
+
+ case Ast_Kind_Switch_Case: break;
case Ast_Kind_File_Contents: break;
case Ast_Kind_Overloaded_Function: break;
case Ast_Kind_Enum_Value: break;
case Ast_Kind_Package: break;
case Ast_Kind_Error: break;
case Ast_Kind_Unary_Field_Access: break;
- case Ast_Kind_Switch_Case: break;
case Ast_Kind_Foreign_Block: break;
case Ast_Kind_Zero_Value: break;
case Ast_Kind_Interface: break;
static AstIfWhile* parse_while_stmt(OnyxParser* parser);
static AstFor* parse_for_stmt(OnyxParser* parser);
static AstSwitchCase* parse_case_stmt(OnyxParser* parser);
-static AstSwitch* parse_switch_stmt(OnyxParser* parser);
+static AstSwitch* parse_switch_stmt(OnyxParser* parser, b32 switch_is_expr);
static i32 parse_possible_symbol_declaration(OnyxParser* parser, AstNode** ret);
static AstReturn* parse_return_stmt(OnyxParser* parser);
static AstBlock* parse_block(OnyxParser* parser, b32 make_a_new_scope, char* block_name);
break;
}
+ case Token_Type_Keyword_Switch: {
+ retval = (AstTyped *) parse_switch_stmt(parser, 1);
+ break;
+ }
+
case '[': {
// HACK CLEANUP
// :LinearTokenDependent
sc_node->is_default = 1;
} else {
+ if ( next_tokens_are(parser, 3, '&', Token_Type_Symbol, ':')
+ || next_tokens_are(parser, 3, '^', Token_Type_Symbol, ':')
+ || next_tokens_are(parser, 2, Token_Type_Symbol, ':')
+ ) {
+ b32 is_pointer = 0;
+ if (consume_token_if_next(parser, '&') || consume_token_if_next(parser, '^'))
+ is_pointer = 1;
+
+ OnyxToken *capture_symbol = expect_token(parser, Token_Type_Symbol);
+ AstLocal *capture = make_local(parser->allocator, capture_symbol, NULL);
+
+ sc_node->capture = capture;
+ sc_node->capture_is_by_pointer = is_pointer;
+
+ expect_token(parser, ':');
+ }
+
bh_arr_new(global_heap_allocator, sc_node->values, 1);
parser->parse_quick_functions = 0;
}
if (consume_token_if_next(parser, Token_Type_Fat_Right_Arrow)) {
- // Captured value for union switching
- b32 is_pointer = 0;
- if (consume_token_if_next(parser, '&') || consume_token_if_next(parser, '^'))
- is_pointer = 1;
-
- OnyxToken *capture_symbol = expect_token(parser, Token_Type_Symbol);
- AstLocal *capture = make_local(parser->allocator, capture_symbol, NULL);
-
- sc_node->capture = capture;
- sc_node->capture_is_by_pointer = is_pointer;
+ sc_node->expr = parse_expression(parser, 0);
+ sc_node->body_is_expr = 1;
+ } else {
+ sc_node->block = parse_block(parser, 1, NULL);
}
- sc_node->block = parse_block(parser, 1, NULL);
-
return sc_node;
}
-static AstSwitch* parse_switch_stmt(OnyxParser* parser) {
+static AstSwitch* parse_switch_stmt(OnyxParser* parser, b32 switch_is_expr) {
AstSwitch* switch_node = make_node(AstSwitch, Ast_Kind_Switch);
switch_node->token = expect_token(parser, Token_Type_Keyword_Switch);
+ switch_node->is_expr = switch_is_expr;
AstTyped* expr;
AstNode* initialization_or_expr=NULL;
case Token_Type_Keyword_Switch:
needs_semicolon = 0;
- retval = (AstNode *) parse_switch_stmt(parser);
+ retval = (AstNode *) parse_switch_stmt(parser, 0);
break;
case Token_Type_Keyword_Case:
break;
}
+ case Ast_Kind_Switch: {
+ SYMRES(switch, (AstSwitch *) *expr);
+ break;
+ }
+
default: break;
}
}
if (casenode->capture) {
- casenode->block->scope = scope_create(context.ast_alloc, current_scope, casenode->block->token->pos);
- symbol_introduce(casenode->block->scope, casenode->capture->token, (AstNode *) casenode->capture);
+ if (casenode->scope == NULL) {
+ casenode->scope = scope_create(context.ast_alloc, current_scope, casenode->token->pos);
+ symbol_introduce(casenode->scope, casenode->capture->token, (AstNode *) casenode->capture);
+ }
+
+ scope_enter(casenode->scope);
+ }
+
+ if (casenode->body_is_expr) {
+ SYMRES(expression, &casenode->expr);
+ } else {
+ SYMRES(block, casenode->block);
+ }
+
+ if (casenode->capture) {
+ scope_leave();
}
- SYMRES(block, casenode->block);
return Symres_Success;
}
SYMRES(case, *pcase);
}
- if (switchnode->default_case) SYMRES(block, switchnode->default_case);
+ if (switchnode->default_case) {
+ if (switchnode->is_expr) {
+ SYMRES(expression, (AstTyped **) &switchnode->default_case);
+ } else {
+ SYMRES(block, switchnode->default_case);
+ }
+ }
}
if (switchnode->switch_kind == Switch_Kind_Use_Equals && switchnode->case_exprs) {
bh_imap block_map;
bh_imap_init(&block_map, global_heap_allocator, bh_arr_length(switch_node->cases));
+ u64 expr_result_local = 0;
+ if (switch_node->is_expr) {
+ expr_result_local = local_allocate(mod->local_alloc, (AstTyped *) switch_node);
+ bh_imap_put(&mod->local_map, (u64) switch_node, expr_result_local);
+ }
+
if (switch_node->initialization != NULL) {
forll (AstNode, stmt, switch_node->initialization, next) {
emit_statement(mod, &code, stmt);
u64 block_num = 0;
bh_arr_each(AstSwitchCase *, sc, switch_node->cases) {
- if (bh_imap_has(&block_map, (u64) (*sc)->block)) continue;
+ if (bh_imap_has(&block_map, (u64) *sc)) continue;
emit_enter_structured_block(mod, &code, SBT_Fallthrough_Block, (*sc)->block->token);
- bh_imap_put(&block_map, (u64) (*sc)->block, block_num);
+ bh_imap_put(&block_map, (u64) *sc, block_num);
block_num++;
}
fori (i, 0, bt->count) bt->cases[i] = bt->default_case;
bh_arr_each(bh__imap_entry, sc, switch_node->case_map.entries) {
+ assert(bh_imap_has(&block_map, (u64) sc->value));
bt->cases[sc->key - switch_node->min_case] = bh_imap_get(&block_map, (u64) sc->value);
}
bh_arr_each(CaseToBlock, ctb, switch_node->case_exprs) {
emit_expression(mod, &code, (AstTyped *) ctb->comparison);
- u64 bn = bh_imap_get(&block_map, (u64) ctb->block);
+ u64 bn = bh_imap_get(&block_map, (u64) ctb->casestmt);
WID(switch_node->expr->token, WI_IF_START, 0x40);
WID(switch_node->expr->token, WI_JUMP, bn + 1);
WI(switch_node->expr->token, WI_IF_END);
AstSwitchCase *sc = *psc;
if (bh_imap_get(&block_map, (u64) sc->block) == 0xdeadbeef) continue;
- u64 bn = bh_imap_get(&block_map, (u64) sc->block);
+ u64 bn = bh_imap_get(&block_map, (u64) sc);
if (sc->capture) {
assert(union_capture_idx != 0);
// Maybe the Symbol Frame idea should be controlled as a block_flag?
debug_enter_symbol_frame(mod);
- emit_block(mod, &code, sc->block, 0);
+ if (sc->body_is_expr) {
+ emit_expression(mod, &code, sc->expr);
+ emit_generic_store_instruction(mod, &code, (AstTyped *) switch_node, switch_node->token);
+
+ } else {
+ emit_block(mod, &code, sc->block, 0);
+ }
+
debug_leave_symbol_frame(mod);
if (bh_arr_last(code).type != WI_JUMP)
emit_leave_structured_block(mod, &code);
- bh_imap_put(&block_map, (u64) sc->block, 0xdeadbeef);
+ bh_imap_put(&block_map, (u64) sc, 0xdeadbeef);
}
if (switch_node->default_case != NULL) {
- emit_block(mod, &code, switch_node->default_case, 0);
+ if (switch_node->is_expr) {
+ emit_expression(mod, &code, (AstTyped *) switch_node->default_case);
+ emit_generic_store_instruction(mod, &code, (AstTyped *) switch_node, switch_node->token);
+
+ } else {
+ emit_block(mod, &code, switch_node->default_case, 0);
+ }
}
if (union_capture_idx != 0) local_raw_free(mod->local_alloc, WASM_TYPE_PTR);
emit_leave_structured_block(mod, &code);
+ if (switch_node->is_expr) {
+ if ((expr_result_local & LOCAL_IS_WASM) == 0) {
+ u64 offset = 0;
+ emit_local_location(mod, &code, (AstLocal *) switch_node, &offset);
+ emit_load_instruction(mod, &code, switch_node->type, offset);
+
+ } else {
+ WIL(switch_node->token, WI_LOCAL_GET, expr_result_local);
+ }
+
+ local_free(mod->local_alloc, (AstTyped *) switch_node);
+ }
+
bh_imap_free(&block_map);
*pcode = code;
}
case Ast_Kind_Do_Block:
case Ast_Kind_If_Expression:
case Ast_Kind_Call_Site:
- case Ast_Kind_Zero_Value: {
+ case Ast_Kind_Zero_Value:
+ case Ast_Kind_Switch: {
emit_local_location(mod, &code, (AstLocal *) expr, offset_return);
break;
}
break;
}
+ case Ast_Kind_Switch: {
+ AstSwitch* switchnode = (AstSwitch *) expr;
+ assert(switchnode->is_expr);
+
+ emit_switch(mod, &code, switchnode);
+ break;
+ }
+
default:
- bh_printf("Unhandled case: %d\n", expr->kind);
+ bh_printf("Unhandled case: %s\n", onyx_ast_node_kind_string(expr->kind));
DEBUG_HERE;
assert(0);
}
Extracts the value from the Optional, or uses a default if
no value is present.
"""
- value_or :: (o: ?$T, default: T) -> T {
- switch o {
- case .Some => v do return v;
- case #default do return default;
- }
+ value_or :: (o: ?$T, default: T) => switch o {
+ case v: .Some => v;
+ case #default => default;
}
#doc "Clears the value in the Optional, zeroing the memory of the value."
#doc "Monadic chaining operation."
and_then :: (o: ?$T, transform: (T) -> ?$R) -> ?R {
- switch o {
- case .Some => v do return transform(v);
- case #default do return .{ None = .{} };
- }
+ return switch o {
+ case v: .Some => transform(v);
+ case #default => .{ None = .{} };
+ };
}
#doc "Changes the value inside the optional, if present."
transform :: (o: ?$T, transform: (T) -> $R) -> ?R {
switch o {
- case .Some => v do return .{ Some = transform(v) };
+ case v: .Some do return .{ Some = transform(v) };
case #default do return .{ None = .{} };
}
}
provide a function to generate a value.
"""
or_else :: (o: ?$T, generate: () -> ?T) -> ?T {
- switch o {
- case .Some => v do return o;
- case #default do return generate();
- }
+ return switch o {
+ case .Some => o;
+ case #default => generate();
+ };
}
#doc """
"""
unwrap :: (o: ?$T) -> T {
switch o {
- case .Some => v do return v;
+ case v: .Some do return v;
case #default {
assert(false, "Unwrapping empty Optional.");
}
"""
unwrap_ptr :: (o: & ?$T) -> &T {
switch o {
- case .Some => &v do return v;
+ case &v: .Some do return v;
case #default {
assert(false, "Unwrapping empty Optional.");
}
or_return :: #match {
macro (o: ?$T) -> T {
switch value := o; value {
- case .Some => v do return v;
+ case v: .Some do return v;
case #default {
return return .{};
}
},
macro (o: ?$T, return_value: $R) -> T {
switch value := o; value {
- case .Some => v do return v;
+ case v: .Some do return v;
case #default {
return return return_value;
}
catch :: macro (o: ?$T, body: Code) -> T {
switch value := o; value {
- case .Some => v do return v;
+ case v: .Some do return v;
case .None {
#unquote body;
}
with :: macro (o: ?$T, body: Code) {
switch o {
case .None ---;
- case .Some => it {
+ case it: .Some {
#unquote body(it);
}
}
}
- hash :: (o: ?$T/core.hash.Hashable) -> u32 {
- switch o {
- case .Some => v do return core.hash.hash(v);
- case #default do return 0;
- }
+ hash :: (o: ?$T/core.hash.Hashable) => switch o {
+ case v: .Some => core.hash.hash(v);
+ case #default => 0;
}
}
#operator == (o1, o2: ?$T) -> bool {
if cast(Optional(T).tag_enum, o1) != cast(Optional(T).tag_enum, o2) do return false;
- switch o1 {
- case .None do return true;
- case .Some => v1 {
- v2 := o2->unwrap();
- return v1 == v2;
- }
- }
+
+ return switch o1 {
+ case .None => true;
+ case v1: .Some => v1 == o2->unwrap();
+ };
}
#operator ?? macro (opt: ?$T, default: T) -> T {
- switch value := opt; value {
- case .Some => v do return v;
- case #default do return default;
- }
+ return switch value := opt; value {
+ case v: .Some => v;
+ case #default => default;
+ };
}
#operator ?? macro (opt: ?$T, catch: Code) -> T {
switch value := opt; value {
- case .Some => v do return v;
+ case v: .Some do return v;
case #default ---
}
#operator ? macro (opt: ?$T) -> T {
switch value := opt; value {
- case .Some => v do return v;
+ case v: .Some do return v;
case #default do return return .{};
}
}
#inject Result {
#doc "Returns true if the result contains an Ok value."
is_ok :: (r: #Self) -> bool {
- switch r {
- case .Ok do return true;
- case #default do return false;
- }
+ return switch r {
+ case .Ok => true;
+ case #default => false;
+ };
}
#doc "Returns true if the result contains an Err value."
is_err :: (r: #Self) -> bool {
- switch r {
- case .Err do return true;
- case #default do return false;
- }
+ return switch r {
+ case .Err => true;
+ case #default => false;
+ };
}
#doc "Returns an Optional of the Ok type."
ok :: (r: #Self) -> Optional(r.Ok_Type) {
- switch r {
- case .Ok => v do return v;
- case #default do return .{};
- }
+ return switch r {
+ case v: .Ok => Optional.make(v);
+ case #default => .{};
+ };
}
#doc "Returns an Optional of the Err type."
err :: (r: #Self) -> Optional(r.Err_Type) {
- switch r {
- case .Err => v do return v;
- case #default do return .{};
- }
+ return switch r {
+ case v: .Err => Optional.make(v);
+ case #default => .{};
+ };
}
#doc """
"""
unwrap :: (r: #Self) -> r.Ok_Type {
switch r {
- case .Ok => v do return v;
- case .Err => err {
+ case v: .Ok do return v;
+ case err: .Err {
msg := tprintf("Unwrapping Result with error '{}'.", err);
assert(false, msg);
return .{};
result contains an Err, the empty .{} value is returned.
"""
unwrap_or_default :: (r: #Self) -> r.Ok_Type {
- switch r {
- case .Ok => v do return v;
- case #default do return .{};
- }
+ return switch r {
+ case v: .Ok => v;
+ case #default => .{};
+ };
}
#doc """
"""
expect :: (r: #Self, msg: str) -> r.Ok_Type {
switch r {
- case .Ok => v do return v;
+ case v: .Ok do return v;
case #default {
assert(false, msg);
}
Err(e) => Err(e)
"""
transform :: (r: Result($T, $E), f: (T) -> $R) -> Result(R, E) {
- switch r {
- case .Ok => v do return .{ Ok = f(v) };
- case .Err => v do return .{ Err = v };
- }
+ return switch r {
+ case v: .Ok => .{ Ok = f(v) };
+ case v: .Err => .{ Err = v };
+ };
}
#doc "Monadic chaining operation."
and_then :: (r: #Self, f: (r.Ok_Type) -> Result($R, r.Err_Type)) -> Result(R, r.Err_Type) {
- switch r {
- case .Ok => v do return f(v);
- case .Err => v do return .{ Err = v };
- }
+ return switch r {
+ case v: .Ok => f(v);
+ case v: .Err => .{ Err = v };
+ };
}
#doc "If the Result contains Err, generate is called to make a value"
or_else :: (r: #Self, generate: () -> typeof r) => {
- switch r {
- case .Ok => v do return v;
- case #default do return generate();
- }
+ return switch r {
+ case v: .Ok => v;
+ case #default => generate();
+ };
}
#doc """
"""
forward_err :: macro (r: Result($T, $E)) -> T {
switch res := r; res {
- case .Ok => v do return v;
- case .Err => v do return return .{ Err = v };
+ case v: .Ok do return v;
+ case v: .Err do return return .{ Err = v };
}
}
"""
or_return :: macro (r: Result($T, $E), v: $V) -> T {
switch res := r; res {
- case .Ok => v do return v;
+ case v: .Ok do return v;
case .Err do return return v;
}
}
"""
catch :: macro (r: Result($T, $E), on_err: Code) -> T {
switch res := r; res {
- case .Ok => v do return v;
- case .Err => err {
+ case v: .Ok do return v;
+ case err: .Err {
#unquote on_err(err);
}
}
#operator ? macro (r: Result($T, $E)) -> T {
switch res := r; res {
- case .Ok => v do return v;
- case .Err => v do return return .{ Err = v };
+ case v: .Ok do return v;
+ case v: .Err do return return .{ Err = v };
}
}
#operator ?? macro (r: Result($T, $E), v: T) -> T {
- switch res := r; res {
- case .Ok => v do return v;
- case .Err do return v;
- }
+ return switch res := r; res {
+ case val: .Ok => val;
+ case .Err => v;
+ };
}
return new_str;
digit_to_value :: (it: u8) -> u32 {
- switch it {
- case #char "0" .. #char "9" do return ~~(it - #char "0");
- case #char "a" .. #char "f" do return ~~(it - #char "a" + 10);
- case #char "A" .. #char "F" do return ~~(it - #char "A" + 10);
- }
-
- return 0;
+ return ~~ switch it {
+ case #char "0" .. #char "9" => it - #char "0";
+ case #char "a" .. #char "f" => it - #char "a" + 10;
+ case #char "A" .. #char "F" => it - #char "A" + 10;
+ case #default => 0;
+ };
}
}
\ No newline at end of file
return 0, 0;
digit_to_hex :: (c: u8) -> i32 {
- switch c {
- case #char "0" do return 0;
- case #char "1" do return 1;
- case #char "2" do return 2;
- case #char "3" do return 3;
- case #char "4" do return 4;
- case #char "5" do return 5;
- case #char "6" do return 6;
- case #char "7" do return 7;
- case #char "8" do return 8;
- case #char "9" do return 9;
- case #char "A", #char "a" do return 10;
- case #char "B", #char "b" do return 11;
- case #char "C", #char "c" do return 12;
- case #char "D", #char "d" do return 13;
- case #char "E", #char "e" do return 14;
- case #char "F", #char "f" do return 15;
- }
-
- return 0;
+ return switch c {
+ case '0' => 0;
+ case '1' => 1;
+ case '2' => 2;
+ case '3' => 3;
+ case '4' => 4;
+ case '5' => 5;
+ case '6' => 6;
+ case '7' => 7;
+ case '8' => 8;
+ case '9' => 9;
+ case 'A', 'a' => 10;
+ case 'B', 'b' => 11;
+ case 'C', 'c' => 12;
+ case 'D', 'd' => 13;
+ case 'E', 'e' => 14;
+ case 'F', 'f' => 15;
+ };
}
}
map_to_ascii :: (x: u8) -> u8 {
- switch x {
- case 0 do return #char "0";
- case 1 do return #char "1";
- case 2 do return #char "2";
- case 3 do return #char "3";
- case 4 do return #char "4";
- case 5 do return #char "5";
- case 6 do return #char "6";
- case 7 do return #char "7";
- case 8 do return #char "8";
- case 9 do return #char "9";
- case 10 do return #char "A";
- case 11 do return #char "B";
- case 12 do return #char "C";
- case 13 do return #char "D";
- case 14 do return #char "E";
- case 15 do return #char "F";
- case #default do return #char "X";
- }
+ return switch x {
+ case 0 => #char "0";
+ case 1 => #char "1";
+ case 2 => #char "2";
+ case 3 => #char "3";
+ case 4 => #char "4";
+ case 5 => #char "5";
+ case 6 => #char "6";
+ case 7 => #char "7";
+ case 8 => #char "8";
+ case 9 => #char "9";
+ case 10 => #char "A";
+ case 11 => #char "B";
+ case 12 => #char "C";
+ case 13 => #char "D";
+ case 14 => #char "E";
+ case 15 => #char "F";
+ case #default => #char "X";
+ };
}
}
}
socket_connect :: (s: &Socket, host: str, port: u16 = 0) -> SocketError {
- switch s.family {
- case .Inet do return __net_connect_ipv4(s.handle, host, port);
- case .Unix do return __net_connect_unix(s.handle, host);
- case #default do return .BadSettings;
- }
+ return switch s.family {
+ case .Inet => __net_connect_ipv4(s.handle, host, port);
+ case .Unix => __net_connect_unix(s.handle, host);
+ case #default => .BadSettings;
+ };
}
socket_bind :: (s: &Socket, bind_address: &Socket_Address) -> bool {
param_info := get_type_info(t);
switch param_info.kind {
- case .Basic do switch t {
- case bool do return "i32";
- case i8 do return "i32";
- case u8 do return "i32";
- case i16 do return "i32";
- case u16 do return "i32";
- case i32 do return "i32";
- case u32 do return "i32";
- case i64 do return "i64";
- case u64 do return "i64";
-
- case f32 do return "f32";
- case f64 do return "f64";
-
- case rawptr do return "ptr";
+ case .Basic do return switch t {
+ case bool => "i32";
+ case i8 => "i32";
+ case u8 => "i32";
+ case i16 => "i32";
+ case u16 => "i32";
+ case i32 => "i32";
+ case u32 => "i32";
+ case i64 => "i64";
+ case u64 => "i64";
+
+ case f32 => "f32";
+ case f64 => "f64";
+
+ case rawptr => "ptr";
- case i8x16, i16x8, i32x4, i64x2, f32x4, f64x2, v128 do return "v128";
+ case i8x16, i16x8, i32x4, i64x2, f32x4, f64x2, v128 => "v128";
- case type_expr do return "i32";
- }
+ case type_expr => "i32";
+ };
case .Pointer do return "ptr";
case .Multi_Pointer do return "ptr";
param_info := get_type_info(t);
switch param_info.kind {
- case .Basic do switch t {
- case bool do return "WASM_I32";
- case i8 do return "WASM_I32";
- case u8 do return "WASM_I32";
- case i16 do return "WASM_I32";
- case u16 do return "WASM_I32";
- case i32 do return "WASM_I32";
- case u32 do return "WASM_I32";
- case i64 do return "WASM_I64";
- case u64 do return "WASM_I64";
-
- case f32 do return "WASM_F32";
- case f64 do return "WASM_F64";
-
- case rawptr do return "WASM_I32"; // This will have to depend on the pointer size...
+ case .Basic do return switch t {
+ case bool => "WASM_I32";
+ case i8 => "WASM_I32";
+ case u8 => "WASM_I32";
+ case i16 => "WASM_I32";
+ case u16 => "WASM_I32";
+ case i32 => "WASM_I32";
+ case u32 => "WASM_I32";
+ case i64 => "WASM_I64";
+ case u64 => "WASM_I64";
+
+ case f32 => "WASM_F32";
+ case f64 => "WASM_F64";
+
+ case rawptr => "WASM_I32"; // This will have to depend on the pointer size...
- case i8x16, i16x8, i32x4, i64x2, f32x4, f64x2, v128 do return "WASM_V128";
+ case i8x16, i16x8, i32x4, i64x2, f32x4, f64x2, v128 => "WASM_V128";
- case type_expr do return "WASM_I32";
- }
+ case type_expr => "WASM_I32";
+ };
case .Pointer do return "WASM_I32"; // This will also have to depend on the pointer size...
case .Multi_Pointer do return "WASM_I32"; // This will also have to depend on the pointer size...
case .F32 do io.write_str(writer, "f32");
case .F64 do io.write_str(writer, "f64");
- case .Rawptr do return io.write_str(writer, "rawptr");
+ case .Rawptr do io.write_str(writer, "rawptr");
- case .I8X16 do return io.write_str(writer, "i8x16");
- case .I16X8 do return io.write_str(writer, "i16x8");
- case .I32X4 do return io.write_str(writer, "i32x4");
- case .I64X2 do return io.write_str(writer, "i64x2");
- case .F32X4 do return io.write_str(writer, "f32x4");
- case .F64X2 do return io.write_str(writer, "f64x2");
- case .V128 do return io.write_str(writer, "v128");
+ case .I8X16 do io.write_str(writer, "i8x16");
+ case .I16X8 do io.write_str(writer, "i16x8");
+ case .I32X4 do io.write_str(writer, "i32x4");
+ case .I64X2 do io.write_str(writer, "i64x2");
+ case .F32X4 do io.write_str(writer, "f32x4");
+ case .F64X2 do io.write_str(writer, "f64x2");
+ case .V128 do io.write_str(writer, "v128");
case .Type_Index do io.write_str(writer, "type_expr");
case .Unsized_Int do io.write_str(writer, "<unsized int>");
info := get_type_info(t);
if info == null do return 0;
- switch info.kind {
- case .Basic {
+ return switch info.kind {
+ case .Basic => do {
basic := cast(&Type_Info_Basic) info;
- switch basic.basic_kind {
- case .Void do return 0;
- case .Bool, .U8, .I8 do return 1;
- case .U16, .I16 do return 2;
- case .U32, .I32, .F32, .Type_Index do return 4;
- case .U64, .I64, .F64 do return 8;
- case .I8X16, .I16X8, .I32X4, .I64X2, .F32X4, .F64X2, .V128 do return 16;
- case .Rawptr do return sizeof rawptr;
-
- case .Unsized_Int do return 0;
- case .Unsized_Float do return 0;
- }
+ return switch basic.basic_kind {
+ case .Void => 0;
+ case .Bool, .U8, .I8 => 1;
+ case .U16, .I16 => 2;
+ case .U32, .I32, .F32, .Type_Index => 4;
+ case .U64, .I64, .F64 => 8;
+ case .I8X16, .I16X8, .I32X4, .I64X2, .F32X4, .F64X2, .V128 => 16;
+ case .Rawptr => sizeof rawptr;
+
+ case .Unsized_Int => 0;
+ case .Unsized_Float => 0;
+ };
}
- case .Pointer do return sizeof rawptr;
+ case .Pointer => sizeof rawptr
- case .Array {
+ case .Array => do {
arr := cast(&Type_Info_Array) info;
return size_of(arr.of) * arr.count;
}
- case .Slice do return sizeof str;
- case .Dynamic_Array do return sizeof [..] void;
- case .Variadic_Argument do return sizeof str;
- case .Enum {
+ case .Slice => sizeof str;
+ case .Dynamic_Array => sizeof [..] void;
+ case .Variadic_Argument => sizeof str;
+ case .Enum => do {
e := cast(&Type_Info_Enum) info;
return e.size;
}
- case .Struct {
+ case .Struct => do {
s := cast(&Type_Info_Struct) info;
return s.size;
}
- case .Polymorphic_Struct do return 0;
+ case .Polymorphic_Struct => 0;
- case .Compound do return 0;
+ case .Compound => 0;
- case .Function do return 4;
+ case .Function => 4;
- case .Distinct {
+ case .Distinct => do {
d := cast(&Type_Info_Distinct) info;
return size_of(d.base_type);
}
- }
- return 0;
+ case #default => 0;
+ };
}
offset_of :: (T: type_expr, member_name: str) -> u32 {
}
index_square_with_orientation :: (data: [&] $T, ori: TO, size: i32, x: i32, y: i32) -> &T {
- switch ori {
- case TO.N do return &data[x + y * size];
- case TO.R90 do return &data[y + (size - 1 - x) * size];
- case TO.R180 do return &data[(size - 1 - x) + (size - 1 - y) * size];
- case TO.R270 do return &data[(size - 1 - y) + x * size];
- case TO.F do return &data[x + (size - 1 - y) * size];
- case TO.FR90 do return &data[y + x * size];
- case TO.FR180 do return &data[(size - 1 - x) + y * size];
- case TO.FR270 do return &data[(size - 1 - y) + (size - 1 - x) * size];
- }
-
- return null;
+ return switch ori {
+ case TO.N => &data[x + y * size];
+ case TO.R90 => &data[y + (size - 1 - x) * size];
+ case TO.R180 => &data[(size - 1 - x) + (size - 1 - y) * size];
+ case TO.R270 => &data[(size - 1 - y) + x * size];
+ case TO.F => &data[x + (size - 1 - y) * size];
+ case TO.FR90 => &data[y + x * size];
+ case TO.FR180 => &data[(size - 1 - x) + y * size];
+ case TO.FR270 => &data[(size - 1 - y) + (size - 1 - x) * size];
+ case #default => null
+ };
}
sea_monster_width := 20;
--- /dev/null
+Val3
+Val1
+123
+12.3400
+A string
--- /dev/null
+use core {*}
+
+Foo :: enum {
+ Val1;
+ Val2;
+ Val3;
+}
+
+assignment_test :: () {
+ v: Foo = switch 3 {
+ case 1 => .Val1;
+ case 2 => .Val2;
+ case 3 => .Val3;
+ };
+
+ printf("{}\n", v);
+}
+
+quick_map_test :: () {
+ println(quick_map(3));
+
+ quick_map :: (n: i32) -> Foo {
+ return switch n {
+ case 4 => .Val1;
+ case 5 => .Val2;
+ case 6 => .Val3;
+ case #default => .Val1;
+ };
+ }
+}
+
+quick_union_map :: () {
+
+ quick_map(SomeUnion.{ x = 123 }) |> println();
+ quick_map(SomeUnion.{ y = 12.34 }) |> println();
+ quick_map(SomeUnion.{ z = "A string" }) |> println();
+
+ SomeUnion :: union {
+ x: i32;
+ y: f32;
+ z: str;
+ }
+
+ quick_map :: (v: $T) => switch v {
+ case val: .z => val;
+ case val: .y => conv.format("{}", val);
+ case val: .x => conv.format("{}", val);
+ }
+}
+
+main :: () {
+ assignment_test();
+ quick_map_test();
+ quick_union_map();
+}
\ No newline at end of file
extract_variant :: macro (u: $U, $variant: U.tag_enum) => {
switch u {
- case variant => v {
+ case v: variant {
return Optional.make(v);
}
}
value := Extraction.{ string = "This works" };
switch value {
- case .int => int_value {
+ case int_value: .int {
printf("This is an integer: {}\n", int_value);
}
- case .float => float_value {
+ case float_value: .float {
printf("This is a float: {}\n", float_value);
}
- case .string => string_value {
+ case string_value: .string {
printf("This is a string: {}\n", string_value);
}
}
do_the_thing :: (value: &Methoded) {
switch *value {
- case .int => int_value {
+ case int_value: .int {
printf("This is an integer: {}\n", int_value);
}
- case .float => float_value {
+ case float_value: .float {
printf("This is a float: {}\n", float_value);
}
- case .string => string_value {
+ case string_value: .string {
printf("This is a string: {}\n", string_value);
}
}
switch walker {
case .End do break break;
- case .Next => &next {
+ case &next: .Next {
printf("{}\n", next.data);
walker = next.next;
}