parse switch
This commit is contained in:
parent
03484afd75
commit
8a6eb3b714
@ -574,15 +574,9 @@ pub const Statement = struct {
|
||||
@"return": ?*Value,
|
||||
assignment: Assignment,
|
||||
expression: *Value,
|
||||
@"if": struct {
|
||||
condition: *Value,
|
||||
if_block: *LexicalBlock,
|
||||
else_block: ?*LexicalBlock,
|
||||
},
|
||||
@"while": struct {
|
||||
condition: *Value,
|
||||
block: *LexicalBlock,
|
||||
},
|
||||
@"if": If,
|
||||
@"while": While,
|
||||
@"switch": Switch,
|
||||
},
|
||||
line: u32,
|
||||
column: u32,
|
||||
@ -606,6 +600,27 @@ pub const Statement = struct {
|
||||
@"^=",
|
||||
};
|
||||
};
|
||||
|
||||
const If = struct {
|
||||
condition: *Value,
|
||||
if_block: *LexicalBlock,
|
||||
else_block: ?*LexicalBlock,
|
||||
};
|
||||
|
||||
const While = struct {
|
||||
condition: *Value,
|
||||
block: *LexicalBlock,
|
||||
};
|
||||
|
||||
const Switch = struct {
|
||||
discriminant: *Value,
|
||||
clauses: []const Clause,
|
||||
|
||||
const Clause = struct {
|
||||
values: []const *Value,
|
||||
block: *LexicalBlock,
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
const Unary = struct {
|
||||
@ -1561,6 +1576,7 @@ pub const Module = struct {
|
||||
@"if",
|
||||
// TODO: make `unreachable` a statement start keyword?
|
||||
@"while",
|
||||
@"switch",
|
||||
};
|
||||
|
||||
const rules = blk: {
|
||||
@ -2245,77 +2261,146 @@ pub const Module = struct {
|
||||
'A'...'Z', 'a'...'z' => blk: {
|
||||
const statement_start_identifier = module.parse_identifier();
|
||||
|
||||
if (lib.string.to_enum(StatementStartKeyword, statement_start_identifier)) |statement_start_keyword| {
|
||||
switch (statement_start_keyword) {
|
||||
._ => @trap(),
|
||||
.@"return" => break :blk .{
|
||||
.@"return" = module.parse_value(function, .{}),
|
||||
},
|
||||
.@"if" => {
|
||||
if (lib.string.to_enum(StatementStartKeyword, statement_start_identifier)) |statement_start_keyword| switch (statement_start_keyword) {
|
||||
._ => @trap(),
|
||||
.@"return" => break :blk .{
|
||||
.@"return" = module.parse_value(function, .{}),
|
||||
},
|
||||
.@"if" => {
|
||||
module.skip_space();
|
||||
|
||||
module.expect_character(left_parenthesis);
|
||||
module.skip_space();
|
||||
|
||||
const condition = module.parse_value(function, .{});
|
||||
|
||||
module.skip_space();
|
||||
module.expect_character(right_parenthesis);
|
||||
|
||||
module.skip_space();
|
||||
|
||||
const if_block = module.parse_block(function);
|
||||
|
||||
module.skip_space();
|
||||
|
||||
var is_else = false;
|
||||
if (is_identifier_start_ch(module.content[module.offset])) {
|
||||
const identifier = module.parse_identifier();
|
||||
is_else = lib.string.equal(identifier, "else");
|
||||
if (!is_else) {
|
||||
module.offset -= identifier.len;
|
||||
} else {
|
||||
module.skip_space();
|
||||
}
|
||||
}
|
||||
|
||||
const else_block = if (is_else) module.parse_block(function) else null;
|
||||
|
||||
require_semicolon = false;
|
||||
|
||||
break :blk .{
|
||||
.@"if" = .{
|
||||
.condition = condition,
|
||||
.if_block = if_block,
|
||||
.else_block = else_block,
|
||||
},
|
||||
};
|
||||
},
|
||||
.@"while" => {
|
||||
module.skip_space();
|
||||
|
||||
module.expect_character(left_parenthesis);
|
||||
module.skip_space();
|
||||
|
||||
const condition = module.parse_value(function, .{});
|
||||
|
||||
module.skip_space();
|
||||
module.expect_character(right_parenthesis);
|
||||
|
||||
module.skip_space();
|
||||
|
||||
const while_block = module.parse_block(function);
|
||||
|
||||
require_semicolon = false;
|
||||
|
||||
break :blk .{
|
||||
.@"while" = .{
|
||||
.condition = condition,
|
||||
.block = while_block,
|
||||
},
|
||||
};
|
||||
},
|
||||
.@"switch" => {
|
||||
module.skip_space();
|
||||
module.expect_character(left_parenthesis);
|
||||
module.skip_space();
|
||||
|
||||
const discriminant = module.parse_value(function, .{});
|
||||
|
||||
module.skip_space();
|
||||
module.expect_character(right_parenthesis);
|
||||
|
||||
module.skip_space();
|
||||
module.expect_character(left_brace);
|
||||
|
||||
var clause_buffer: [64]Statement.Switch.Clause = undefined;
|
||||
var clause_count: u64 = 0;
|
||||
|
||||
while (true) {
|
||||
module.skip_space();
|
||||
|
||||
module.expect_character(left_parenthesis);
|
||||
module.skip_space();
|
||||
var case_buffer: [64]*Value = undefined;
|
||||
var case_count: u64 = 0;
|
||||
|
||||
const condition = module.parse_value(function, .{});
|
||||
while (true) {
|
||||
const case_value = module.parse_value(function, .{});
|
||||
case_buffer[case_count] = case_value;
|
||||
case_count += 1;
|
||||
|
||||
module.skip_space();
|
||||
module.expect_character(right_parenthesis);
|
||||
_ = module.consume_character_if_match(',');
|
||||
|
||||
module.skip_space();
|
||||
module.skip_space();
|
||||
|
||||
const if_block = module.parse_block(function);
|
||||
|
||||
module.skip_space();
|
||||
|
||||
var is_else = false;
|
||||
if (is_identifier_start_ch(module.content[module.offset])) {
|
||||
const identifier = module.parse_identifier();
|
||||
is_else = lib.string.equal(identifier, "else");
|
||||
if (!is_else) {
|
||||
module.offset -= identifier.len;
|
||||
} else {
|
||||
module.skip_space();
|
||||
if (module.consume_character_if_match('=')) {
|
||||
module.expect_character('>');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const else_block = if (is_else) module.parse_block(function) else null;
|
||||
module.skip_space();
|
||||
|
||||
require_semicolon = false;
|
||||
const clause_block = module.parse_block(function);
|
||||
|
||||
break :blk .{
|
||||
.@"if" = .{
|
||||
.condition = condition,
|
||||
.if_block = if_block,
|
||||
.else_block = else_block,
|
||||
},
|
||||
const clause_values = module.arena.allocate(*Value, case_count);
|
||||
@memcpy(clause_values, case_buffer[0..case_count]);
|
||||
|
||||
clause_buffer[clause_count] = .{
|
||||
.values = clause_values,
|
||||
.block = clause_block,
|
||||
};
|
||||
},
|
||||
.@"while" => {
|
||||
module.skip_space();
|
||||
clause_count += 1;
|
||||
|
||||
module.expect_character(left_parenthesis);
|
||||
module.skip_space();
|
||||
|
||||
const condition = module.parse_value(function, .{});
|
||||
_ = module.consume_character_if_match(',');
|
||||
|
||||
module.skip_space();
|
||||
module.expect_character(right_parenthesis);
|
||||
|
||||
if (module.consume_character_if_match(right_brace)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
module.skip_space();
|
||||
const clauses = module.arena.allocate(Statement.Switch.Clause, clause_count);
|
||||
@memcpy(clauses, clause_buffer[0..clause_count]);
|
||||
|
||||
const while_block = module.parse_block(function);
|
||||
require_semicolon = false;
|
||||
|
||||
require_semicolon = false;
|
||||
|
||||
break :blk .{
|
||||
.@"while" = .{
|
||||
.condition = condition,
|
||||
.block = while_block,
|
||||
},
|
||||
};
|
||||
},
|
||||
}
|
||||
break :blk .{
|
||||
.@"switch" = .{
|
||||
.discriminant = discriminant,
|
||||
.clauses = clauses,
|
||||
},
|
||||
};
|
||||
},
|
||||
} else {
|
||||
module.offset -= statement_start_identifier.len;
|
||||
|
||||
@ -3356,14 +3441,12 @@ pub const Module = struct {
|
||||
const field_index = field_count;
|
||||
const field_name = module.parse_identifier();
|
||||
module.skip_space();
|
||||
|
||||
const field_value = if (module.consume_character_if_match('=')) blk: {
|
||||
const has_explicit_value = module.consume_character_if_match('=');
|
||||
const field_value = if (has_explicit_value) blk: {
|
||||
module.skip_space();
|
||||
const field_value = module.parse_integer_value(false);
|
||||
break :blk field_value;
|
||||
} else {
|
||||
@trap();
|
||||
};
|
||||
} else field_index;
|
||||
|
||||
field_buffer[field_index] = .{
|
||||
.name = field_name,
|
||||
@ -6448,6 +6531,7 @@ pub const Module = struct {
|
||||
|
||||
module.llvm.builder.position_at_end(loop_end_block);
|
||||
},
|
||||
.@"switch" => @trap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
26
tests/switch.bbb
Normal file
26
tests/switch.bbb
Normal file
@ -0,0 +1,26 @@
|
||||
E = enum
|
||||
{
|
||||
a,
|
||||
b,
|
||||
c,
|
||||
}
|
||||
|
||||
[export] main = fn [cc(c)] () s32
|
||||
{
|
||||
>some_enum: E = .a;
|
||||
switch (some_enum)
|
||||
{
|
||||
.a =>
|
||||
{
|
||||
return 0;
|
||||
},
|
||||
.b =>
|
||||
{
|
||||
return 1;
|
||||
},
|
||||
.c =>
|
||||
{
|
||||
return 1;
|
||||
},
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user