Switch statement

This commit is contained in:
David Gonzalez Martin 2025-06-13 22:06:04 -06:00
parent bb57af7642
commit fa4ec4c156

View File

@ -2738,9 +2738,27 @@ StatementWhile = struct
block: &Block,
}
StatementSwitchDiscriminantId = enum
{
single,
range,
}
StatementSwitchDiscriminantContent = union
{
single: &Value,
range: [2]&Value,
}
StatementSwitchDiscriminant = struct
{
content: StatementSwitchDiscriminantContent,
id: StatementSwitchDiscriminantId,
}
StatementSwitchClause = struct
{
values: []&Value,
values: []StatementSwitchDiscriminant,
block: &Block,
}
@ -6014,7 +6032,148 @@ parse_statement = fn (module: &Module, scope: &Scope) &Statement
},
.switch =>
{
#trap();
skip_space(module);
expect_character(module, left_parenthesis);
skip_space(module);
>discriminant = parse_value(module, scope, zero);
skip_space(module);
expect_character(module, right_parenthesis);
skip_space(module);
expect_character(module, left_brace);
>clause_buffer: [64]StatementSwitchClause = undefined;
>clause_count: u64 = 0;
while (1)
{
skip_space(module);
>is_else: u1 = 0;
if (is_identifier_start(module.content[module.offset]))
{
>else_checkpoint = get_checkpoint(module);
>i = parse_identifier(module);
is_else = string_equal(i, "else");
if (!is_else)
{
set_checkpoint(module, else_checkpoint);
}
}
>clause_values: []StatementSwitchDiscriminant = zero;
if (is_else)
{
skip_space(module);
expect_character(module, '=');
expect_character(module, '>');
}
else
{
>case_buffer: [64]StatementSwitchDiscriminant = undefined;
>case_count: u64 = 0;
while (1)
{
>first_case_value = parse_value(module, scope, zero);
skip_space(module);
>checkpoint = get_checkpoint(module);
>token = tokenize(module);
>clause_discriminant: StatementSwitchDiscriminant = undefined;
switch (token.id)
{
.triple_dot =>
{
>last_case_value = parse_value(module, scope, zero);
clause_discriminant = {
.content = {
.range = [ first_case_value, last_case_value ],
},
.id = .range,
};
},
else =>
{
if (token.id != .comma)
{
set_checkpoint(module, checkpoint);
}
clause_discriminant = {
.content = {
.single = first_case_value,
},
.id = .single,
};
},
}
switch (clause_discriminant.id)
{
.single => { assert(clause_discriminant.content.single != zero); },
.range =>
{
assert(clause_discriminant.content.range[0] != zero);
assert(clause_discriminant.content.range[1] != zero);
},
}
case_buffer[case_count] = clause_discriminant;
case_count += 1;
skip_space(module);
if (consume_character_if_match(module, '='))
{
expect_character(module, '>');
break;
}
}
clause_values = arena_allocate_slice[StatementSwitchDiscriminant](module.arena, case_count);
memcpy(#pointer_cast(clause_values.pointer), #pointer_cast(&case_buffer), case_count * #byte_size(StatementSwitchDiscriminant));
}
skip_space(module);
>clause_block = parse_block(module, scope);
clause_buffer[clause_count] = {
.values = clause_values,
.block = clause_block,
};
clause_count += 1;
consume_character_if_match(module, ',');
skip_space(module);
if (consume_character_if_match(module, right_brace))
{
break;
}
}
>clauses = arena_allocate_slice[StatementSwitchClause](module.arena, clause_count);
memcpy(#pointer_cast(clauses.pointer), #pointer_cast(&clause_buffer), clause_count * #byte_size(StatementSwitchClause));
require_semicolon = 0;
statement.content = {
.switch = {
.discriminant = discriminant,
.clauses = clauses,
},
};
statement.id = .switch;
},
.break =>
{
@ -13013,6 +13172,10 @@ analyze_statement = fn (module: &Module, scope: &Scope, statement: &Statement) v
},
}
},
.switch =>
{
#trap();
},
else =>
{
#trap();
@ -14457,6 +14620,7 @@ names: [_][]u8 =
"string_to_enum",
"empty_if",
"else_if",
"else_if_complicated",
];
[export] main = fn [cc(c)] (argument_count: u32, argv: &&u8, envp: &&u8) s32