For each
All checks were successful
CI / ci (ReleaseFast, ubuntu-latest) (pull_request) Successful in 2m19s
CI / ci (ReleaseSmall, ubuntu-latest) (pull_request) Successful in 2m17s
CI / ci (ReleaseSafe, ubuntu-latest) (pull_request) Successful in 2m23s
CI / ci (Debug, ubuntu-latest) (pull_request) Successful in 3m33s
CI / ci (ReleaseFast, ubuntu-latest) (push) Successful in 2m19s
CI / ci (ReleaseSmall, ubuntu-latest) (push) Successful in 2m16s
CI / ci (ReleaseSafe, ubuntu-latest) (push) Successful in 2m22s
CI / ci (Debug, ubuntu-latest) (push) Successful in 3m32s
All checks were successful
CI / ci (ReleaseFast, ubuntu-latest) (pull_request) Successful in 2m19s
CI / ci (ReleaseSmall, ubuntu-latest) (pull_request) Successful in 2m17s
CI / ci (ReleaseSafe, ubuntu-latest) (pull_request) Successful in 2m23s
CI / ci (Debug, ubuntu-latest) (pull_request) Successful in 3m33s
CI / ci (ReleaseFast, ubuntu-latest) (push) Successful in 2m19s
CI / ci (ReleaseSmall, ubuntu-latest) (push) Successful in 2m16s
CI / ci (ReleaseSafe, ubuntu-latest) (push) Successful in 2m22s
CI / ci (Debug, ubuntu-latest) (push) Successful in 3m32s
This commit is contained in:
parent
8bef7f8bd0
commit
c09715b2d0
@ -616,12 +616,21 @@ pub const Statement = struct {
|
|||||||
expression: *Value,
|
expression: *Value,
|
||||||
@"if": If,
|
@"if": If,
|
||||||
@"while": While,
|
@"while": While,
|
||||||
|
for_each: ForEach,
|
||||||
@"switch": Switch,
|
@"switch": Switch,
|
||||||
block: *LexicalBlock,
|
block: *LexicalBlock,
|
||||||
},
|
},
|
||||||
line: u32,
|
line: u32,
|
||||||
column: u32,
|
column: u32,
|
||||||
|
|
||||||
|
const ForEach = struct {
|
||||||
|
locals: []const *Local,
|
||||||
|
left_values: []const Value.Kind,
|
||||||
|
right_values: []const *Value,
|
||||||
|
predicate: *Statement,
|
||||||
|
scope: Scope,
|
||||||
|
};
|
||||||
|
|
||||||
const Assignment = struct {
|
const Assignment = struct {
|
||||||
left: *Value,
|
left: *Value,
|
||||||
right: *Value,
|
right: *Value,
|
||||||
@ -980,6 +989,7 @@ pub const Scope = struct {
|
|||||||
global,
|
global,
|
||||||
function,
|
function,
|
||||||
local,
|
local,
|
||||||
|
for_each,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1044,7 +1054,6 @@ pub const Module = struct {
|
|||||||
lexical_blocks: lib.VirtualBuffer(LexicalBlock),
|
lexical_blocks: lib.VirtualBuffer(LexicalBlock),
|
||||||
statements: lib.VirtualBuffer(Statement),
|
statements: lib.VirtualBuffer(Statement),
|
||||||
current_function: ?*Global = null,
|
current_function: ?*Global = null,
|
||||||
current_scope: *Scope,
|
|
||||||
name: []const u8,
|
name: []const u8,
|
||||||
path: []const u8,
|
path: []const u8,
|
||||||
executable: [:0]const u8,
|
executable: [:0]const u8,
|
||||||
@ -1639,6 +1648,7 @@ pub const Module = struct {
|
|||||||
@"return",
|
@"return",
|
||||||
@"if",
|
@"if",
|
||||||
// TODO: make `unreachable` a statement start keyword?
|
// TODO: make `unreachable` a statement start keyword?
|
||||||
|
@"for",
|
||||||
@"while",
|
@"while",
|
||||||
@"switch",
|
@"switch",
|
||||||
};
|
};
|
||||||
@ -2234,30 +2244,30 @@ pub const Module = struct {
|
|||||||
after: ?*const Rule.Function,
|
after: ?*const Rule.Function,
|
||||||
precedence: Precedence,
|
precedence: Precedence,
|
||||||
|
|
||||||
const Function = fn (noalias module: *Module, function: ?*Global, value_builder: Value.Builder) *Value;
|
const Function = fn (noalias module: *Module, function: ?*Global, scope: *Scope, value_builder: Value.Builder) *Value;
|
||||||
};
|
};
|
||||||
|
|
||||||
fn parse_value(module: *Module, function: ?*Global, value_builder: Value.Builder) *Value {
|
fn parse_value(module: *Module, function: ?*Global, scope: *Scope, value_builder: Value.Builder) *Value {
|
||||||
assert(value_builder.precedence == .none);
|
assert(value_builder.precedence == .none);
|
||||||
assert(value_builder.left == null);
|
assert(value_builder.left == null);
|
||||||
const value = module.parse_precedence(function, value_builder.with_precedence(.assignment));
|
const value = module.parse_precedence(function, scope, value_builder.with_precedence(.assignment));
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_precedence(module: *Module, function: ?*Global, value_builder: Value.Builder) *Value {
|
fn parse_precedence(module: *Module, function: ?*Global, scope: *Scope, value_builder: Value.Builder) *Value {
|
||||||
assert(value_builder.token == .none);
|
assert(value_builder.token == .none);
|
||||||
const token = module.tokenize();
|
const token = module.tokenize();
|
||||||
const rule = &rules[@intFromEnum(token)];
|
const rule = &rules[@intFromEnum(token)];
|
||||||
if (rule.before) |before| {
|
if (rule.before) |before| {
|
||||||
const left = before(module, function, value_builder.with_precedence(.none).with_token(token));
|
const left = before(module, function, scope, value_builder.with_precedence(.none).with_token(token));
|
||||||
const result = module.parse_precedence_left(function, value_builder.with_left(left));
|
const result = module.parse_precedence_left(function, scope, value_builder.with_left(left));
|
||||||
return result;
|
return result;
|
||||||
} else {
|
} else {
|
||||||
module.report_error();
|
module.report_error();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_precedence_left(module: *Module, function: ?*Global, value_builder: Value.Builder) *Value {
|
fn parse_precedence_left(module: *Module, function: ?*Global, scope: *Scope, value_builder: Value.Builder) *Value {
|
||||||
var result = value_builder.left;
|
var result = value_builder.left;
|
||||||
_ = &result;
|
_ = &result;
|
||||||
const precedence = value_builder.precedence;
|
const precedence = value_builder.precedence;
|
||||||
@ -2279,14 +2289,14 @@ pub const Module = struct {
|
|||||||
|
|
||||||
const after_rule = token_rule.after orelse module.report_error();
|
const after_rule = token_rule.after orelse module.report_error();
|
||||||
const old = result;
|
const old = result;
|
||||||
const new = after_rule(module, function, value_builder.with_token(token).with_precedence(.none).with_left(old));
|
const new = after_rule(module, function, scope, value_builder.with_token(token).with_precedence(.none).with_left(old));
|
||||||
result = new;
|
result = new;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result.?;
|
return result.?;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_statement(module: *Module, function: *Global, block: *LexicalBlock) *Statement {
|
fn parse_statement(module: *Module, function: *Global, scope: *Scope) *Statement {
|
||||||
const statement_line = module.get_line();
|
const statement_line = module.get_line();
|
||||||
const statement_column = module.get_column();
|
const statement_column = module.get_column();
|
||||||
|
|
||||||
@ -2307,7 +2317,7 @@ pub const Module = struct {
|
|||||||
break :b t;
|
break :b t;
|
||||||
} else null;
|
} else null;
|
||||||
module.expect_character('=');
|
module.expect_character('=');
|
||||||
const local_value = module.parse_value(function, .{});
|
const local_value = module.parse_value(function, scope, .{});
|
||||||
const local = module.locals.add();
|
const local = module.locals.add();
|
||||||
local.* = .{
|
local.* = .{
|
||||||
.variable = .{
|
.variable = .{
|
||||||
@ -2316,18 +2326,23 @@ pub const Module = struct {
|
|||||||
.name = local_name,
|
.name = local_name,
|
||||||
.line = statement_line,
|
.line = statement_line,
|
||||||
.column = statement_column,
|
.column = statement_column,
|
||||||
.scope = module.current_scope,
|
.scope = scope,
|
||||||
},
|
},
|
||||||
.argument_index = null,
|
.argument_index = null,
|
||||||
};
|
};
|
||||||
assert(module.current_scope == &block.scope);
|
switch (scope.kind) {
|
||||||
_ = block.locals.append(local);
|
.local => {
|
||||||
|
const block: *LexicalBlock = @fieldParentPtr("scope", scope);
|
||||||
|
_ = block.locals.append(local);
|
||||||
|
},
|
||||||
|
else => @trap(),
|
||||||
|
}
|
||||||
break :blk .{
|
break :blk .{
|
||||||
.local = local,
|
.local = local,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
'#' => .{
|
'#' => .{
|
||||||
.expression = module.parse_value(function, .{}),
|
.expression = module.parse_value(function, scope, .{}),
|
||||||
},
|
},
|
||||||
'A'...'Z', 'a'...'z' => blk: {
|
'A'...'Z', 'a'...'z' => blk: {
|
||||||
const statement_start_identifier = module.parse_identifier();
|
const statement_start_identifier = module.parse_identifier();
|
||||||
@ -2335,7 +2350,7 @@ pub const Module = struct {
|
|||||||
if (lib.string.to_enum(StatementStartKeyword, statement_start_identifier)) |statement_start_keyword| switch (statement_start_keyword) {
|
if (lib.string.to_enum(StatementStartKeyword, statement_start_identifier)) |statement_start_keyword| switch (statement_start_keyword) {
|
||||||
._ => @trap(),
|
._ => @trap(),
|
||||||
.@"return" => break :blk .{
|
.@"return" => break :blk .{
|
||||||
.@"return" = module.parse_value(function, .{}),
|
.@"return" = module.parse_value(function, scope, .{}),
|
||||||
},
|
},
|
||||||
.@"if" => {
|
.@"if" => {
|
||||||
module.skip_space();
|
module.skip_space();
|
||||||
@ -2343,14 +2358,14 @@ pub const Module = struct {
|
|||||||
module.expect_character(left_parenthesis);
|
module.expect_character(left_parenthesis);
|
||||||
module.skip_space();
|
module.skip_space();
|
||||||
|
|
||||||
const condition = module.parse_value(function, .{});
|
const condition = module.parse_value(function, scope, .{});
|
||||||
|
|
||||||
module.skip_space();
|
module.skip_space();
|
||||||
module.expect_character(right_parenthesis);
|
module.expect_character(right_parenthesis);
|
||||||
|
|
||||||
module.skip_space();
|
module.skip_space();
|
||||||
|
|
||||||
const if_statement = module.parse_statement(function, block);
|
const if_statement = module.parse_statement(function, scope);
|
||||||
|
|
||||||
module.skip_space();
|
module.skip_space();
|
||||||
|
|
||||||
@ -2366,7 +2381,7 @@ pub const Module = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const else_block = switch (is_else) {
|
const else_block = switch (is_else) {
|
||||||
true => module.parse_statement(function, block),
|
true => module.parse_statement(function, scope),
|
||||||
false => null,
|
false => null,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -2386,14 +2401,14 @@ pub const Module = struct {
|
|||||||
module.expect_character(left_parenthesis);
|
module.expect_character(left_parenthesis);
|
||||||
module.skip_space();
|
module.skip_space();
|
||||||
|
|
||||||
const condition = module.parse_value(function, .{});
|
const condition = module.parse_value(function, scope, .{});
|
||||||
|
|
||||||
module.skip_space();
|
module.skip_space();
|
||||||
module.expect_character(right_parenthesis);
|
module.expect_character(right_parenthesis);
|
||||||
|
|
||||||
module.skip_space();
|
module.skip_space();
|
||||||
|
|
||||||
const while_block = module.parse_block(function);
|
const while_block = module.parse_block(function, scope);
|
||||||
|
|
||||||
require_semicolon = false;
|
require_semicolon = false;
|
||||||
|
|
||||||
@ -2404,12 +2419,132 @@ pub const Module = struct {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
.@"for" => {
|
||||||
|
module.skip_space();
|
||||||
|
|
||||||
|
module.expect_character(left_parenthesis);
|
||||||
|
module.skip_space();
|
||||||
|
|
||||||
|
statement.* = .{
|
||||||
|
.line = statement_line,
|
||||||
|
.column = statement_column,
|
||||||
|
.bb = .{
|
||||||
|
.for_each = .{
|
||||||
|
.locals = &.{},
|
||||||
|
.left_values = &.{},
|
||||||
|
.right_values = &.{},
|
||||||
|
.predicate = undefined,
|
||||||
|
.scope = .{
|
||||||
|
.line = statement_line,
|
||||||
|
.column = statement_column,
|
||||||
|
.kind = .for_each,
|
||||||
|
.parent = scope,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
var local_buffer: [64]*Local = undefined;
|
||||||
|
var left_value_buffer: [64]Value.Kind = undefined;
|
||||||
|
var left_value_count: u64 = 0;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
module.skip_space();
|
||||||
|
|
||||||
|
const is_left = switch (module.content[module.offset]) {
|
||||||
|
'&' => true,
|
||||||
|
else => false,
|
||||||
|
};
|
||||||
|
module.offset += @intFromBool(is_left);
|
||||||
|
|
||||||
|
const for_local_line = module.get_line();
|
||||||
|
const for_local_column = module.get_column();
|
||||||
|
|
||||||
|
if (is_identifier_start_ch(module.content[module.offset])) {
|
||||||
|
const identifier = module.parse_identifier();
|
||||||
|
const local = module.locals.add();
|
||||||
|
local.* = .{
|
||||||
|
.variable = .{
|
||||||
|
.type = null,
|
||||||
|
.initial_value = undefined,
|
||||||
|
.scope = &statement.bb.for_each.scope,
|
||||||
|
.name = identifier,
|
||||||
|
.line = for_local_line,
|
||||||
|
.column = for_local_column,
|
||||||
|
},
|
||||||
|
.argument_index = null,
|
||||||
|
};
|
||||||
|
local_buffer[left_value_count] = local;
|
||||||
|
left_value_buffer[left_value_count] = switch (is_left) {
|
||||||
|
true => .left,
|
||||||
|
false => .right,
|
||||||
|
};
|
||||||
|
left_value_count += 1;
|
||||||
|
} else {
|
||||||
|
@trap();
|
||||||
|
}
|
||||||
|
|
||||||
|
module.skip_space();
|
||||||
|
|
||||||
|
if (!module.consume_character_if_match(',')) {
|
||||||
|
module.expect_character(':');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.skip_space();
|
||||||
|
|
||||||
|
var right_value_buffer: [64]*Value = undefined;
|
||||||
|
var right_value_count: u64 = 0;
|
||||||
|
while (true) {
|
||||||
|
module.skip_space();
|
||||||
|
|
||||||
|
const identifier = module.parse_value(function, scope, .{
|
||||||
|
.kind = .left,
|
||||||
|
});
|
||||||
|
right_value_buffer[right_value_count] = identifier;
|
||||||
|
right_value_count += 1;
|
||||||
|
|
||||||
|
module.skip_space();
|
||||||
|
|
||||||
|
if (!module.consume_character_if_match(',')) {
|
||||||
|
module.expect_character(right_parenthesis);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.skip_space();
|
||||||
|
|
||||||
|
if (left_value_count != right_value_count) {
|
||||||
|
module.report_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
const locals = module.arena.allocate(*Local, left_value_count);
|
||||||
|
@memcpy(locals, local_buffer[0..left_value_count]);
|
||||||
|
const left_values = module.arena.allocate(Value.Kind, left_value_count);
|
||||||
|
@memcpy(left_values, left_value_buffer[0..left_value_count]);
|
||||||
|
const right_values = module.arena.allocate(*Value, right_value_count);
|
||||||
|
@memcpy(right_values, right_value_buffer[0..right_value_count]);
|
||||||
|
|
||||||
|
statement.bb.for_each.locals = locals;
|
||||||
|
statement.bb.for_each.left_values = left_values;
|
||||||
|
statement.bb.for_each.right_values = right_values;
|
||||||
|
|
||||||
|
const predicate = module.parse_statement(function, &statement.bb.for_each.scope);
|
||||||
|
statement.bb.for_each.predicate = predicate;
|
||||||
|
|
||||||
|
module.skip_space();
|
||||||
|
|
||||||
|
require_semicolon = false;
|
||||||
|
|
||||||
|
break :blk statement.bb;
|
||||||
|
},
|
||||||
.@"switch" => {
|
.@"switch" => {
|
||||||
module.skip_space();
|
module.skip_space();
|
||||||
module.expect_character(left_parenthesis);
|
module.expect_character(left_parenthesis);
|
||||||
module.skip_space();
|
module.skip_space();
|
||||||
|
|
||||||
const discriminant = module.parse_value(function, .{});
|
const discriminant = module.parse_value(function, scope, .{});
|
||||||
|
|
||||||
module.skip_space();
|
module.skip_space();
|
||||||
module.expect_character(right_parenthesis);
|
module.expect_character(right_parenthesis);
|
||||||
@ -2447,7 +2582,7 @@ pub const Module = struct {
|
|||||||
var case_count: u64 = 0;
|
var case_count: u64 = 0;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
const case_value = module.parse_value(function, .{});
|
const case_value = module.parse_value(function, scope, .{});
|
||||||
case_buffer[case_count] = case_value;
|
case_buffer[case_count] = case_value;
|
||||||
case_count += 1;
|
case_count += 1;
|
||||||
|
|
||||||
@ -2468,7 +2603,7 @@ pub const Module = struct {
|
|||||||
|
|
||||||
module.skip_space();
|
module.skip_space();
|
||||||
|
|
||||||
const clause_block = module.parse_block(function);
|
const clause_block = module.parse_block(function, scope);
|
||||||
|
|
||||||
clause_buffer[clause_count] = .{
|
clause_buffer[clause_count] = .{
|
||||||
.values = clause_values,
|
.values = clause_values,
|
||||||
@ -2500,7 +2635,7 @@ pub const Module = struct {
|
|||||||
} else {
|
} else {
|
||||||
module.offset -= statement_start_identifier.len;
|
module.offset -= statement_start_identifier.len;
|
||||||
|
|
||||||
const left = module.parse_value(function, .{
|
const left = module.parse_value(function, scope, .{
|
||||||
.kind = .left,
|
.kind = .left,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -2583,7 +2718,7 @@ pub const Module = struct {
|
|||||||
|
|
||||||
module.skip_space();
|
module.skip_space();
|
||||||
|
|
||||||
const right = module.parse_value(function, .{});
|
const right = module.parse_value(function, scope, .{});
|
||||||
|
|
||||||
break :blk .{
|
break :blk .{
|
||||||
.assignment = .{
|
.assignment = .{
|
||||||
@ -2598,7 +2733,7 @@ pub const Module = struct {
|
|||||||
left_brace => blk: {
|
left_brace => blk: {
|
||||||
require_semicolon = false;
|
require_semicolon = false;
|
||||||
break :blk .{
|
break :blk .{
|
||||||
.block = module.parse_block(function),
|
.block = module.parse_block(function, scope),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
else => @trap(),
|
else => @trap(),
|
||||||
@ -2614,8 +2749,7 @@ pub const Module = struct {
|
|||||||
return statement;
|
return statement;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_block(module: *Module, function: *Global) *LexicalBlock {
|
fn parse_block(module: *Module, function: *Global, parent_scope: *Scope) *LexicalBlock {
|
||||||
const parent_scope = module.current_scope;
|
|
||||||
const block = module.lexical_blocks.append(.{
|
const block = module.lexical_blocks.append(.{
|
||||||
.statements = .initialize(),
|
.statements = .initialize(),
|
||||||
.locals = .initialize(),
|
.locals = .initialize(),
|
||||||
@ -2626,8 +2760,7 @@ pub const Module = struct {
|
|||||||
.column = module.get_column(),
|
.column = module.get_column(),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
module.current_scope = &block.scope;
|
const scope = &block.scope;
|
||||||
defer module.current_scope = parent_scope;
|
|
||||||
|
|
||||||
module.expect_character(left_brace);
|
module.expect_character(left_brace);
|
||||||
|
|
||||||
@ -2642,14 +2775,15 @@ pub const Module = struct {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const statement = module.parse_statement(function, block);
|
const statement = module.parse_statement(function, scope);
|
||||||
_ = block.statements.append(statement);
|
_ = block.statements.append(statement);
|
||||||
}
|
}
|
||||||
|
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rule_before_dot(noalias module: *Module, function: ?*Global, value_builder: Value.Builder) *Value {
|
fn rule_before_dot(noalias module: *Module, function: ?*Global, scope: *Scope, value_builder: Value.Builder) *Value {
|
||||||
|
_ = scope;
|
||||||
_ = function;
|
_ = function;
|
||||||
_ = value_builder;
|
_ = value_builder;
|
||||||
module.skip_space();
|
module.skip_space();
|
||||||
@ -2664,7 +2798,8 @@ pub const Module = struct {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rule_after_dot(noalias module: *Module, function: ?*Global, value_builder: Value.Builder) *Value {
|
fn rule_after_dot(noalias module: *Module, function: ?*Global, scope: *Scope, value_builder: Value.Builder) *Value {
|
||||||
|
_ = scope;
|
||||||
_ = function;
|
_ = function;
|
||||||
module.skip_space();
|
module.skip_space();
|
||||||
const left = value_builder.left orelse module.report_error();
|
const left = value_builder.left orelse module.report_error();
|
||||||
@ -2683,7 +2818,8 @@ pub const Module = struct {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rule_before_string_literal(noalias module: *Module, function: ?*Global, value_builder: Value.Builder) *Value {
|
fn rule_before_string_literal(noalias module: *Module, function: ?*Global, parent_scope: *Scope, value_builder: Value.Builder) *Value {
|
||||||
|
_ = parent_scope;
|
||||||
_ = function;
|
_ = function;
|
||||||
const value = module.values.add();
|
const value = module.values.add();
|
||||||
value.* = .{
|
value.* = .{
|
||||||
@ -2694,16 +2830,17 @@ pub const Module = struct {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rule_before_identifier(noalias module: *Module, function: ?*Global, value_builder: Value.Builder) *Value {
|
fn rule_before_identifier(noalias module: *Module, function: ?*Global, current_scope: *Scope, value_builder: Value.Builder) *Value {
|
||||||
_ = function;
|
_ = function;
|
||||||
const identifier = value_builder.token.identifier;
|
const identifier = value_builder.token.identifier;
|
||||||
assert(!lib.string.equal(identifier, ""));
|
assert(!lib.string.equal(identifier, ""));
|
||||||
assert(!lib.string.equal(identifier, "_"));
|
assert(!lib.string.equal(identifier, "_"));
|
||||||
|
|
||||||
var scope_it: ?*Scope = module.current_scope;
|
var scope_it: ?*Scope = current_scope;
|
||||||
const variable = blk: while (scope_it) |scope| : (scope_it = scope.parent) {
|
const variable = blk: while (scope_it) |scope| : (scope_it = scope.parent) {
|
||||||
switch (scope.kind) {
|
switch (scope.kind) {
|
||||||
.global => {
|
.global => {
|
||||||
|
assert(scope.parent == null);
|
||||||
const m: *Module = @fieldParentPtr("scope", scope);
|
const m: *Module = @fieldParentPtr("scope", scope);
|
||||||
assert(m == module);
|
assert(m == module);
|
||||||
for (module.globals.get_slice()) |*global| {
|
for (module.globals.get_slice()) |*global| {
|
||||||
@ -2712,25 +2849,33 @@ pub const Module = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(scope.parent == null);
|
|
||||||
},
|
},
|
||||||
.function => {
|
.function => {
|
||||||
|
assert(scope.parent != null);
|
||||||
const f: *Function = @fieldParentPtr("scope", scope);
|
const f: *Function = @fieldParentPtr("scope", scope);
|
||||||
for (f.arguments) |argument| {
|
for (f.arguments) |argument| {
|
||||||
if (lib.string.equal(argument.variable.name, identifier)) {
|
if (lib.string.equal(argument.variable.name, identifier)) {
|
||||||
break :blk &argument.variable;
|
break :blk &argument.variable;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert(scope.parent != null);
|
|
||||||
},
|
},
|
||||||
.local => {
|
.local => {
|
||||||
|
assert(scope.parent != null);
|
||||||
const block: *LexicalBlock = @fieldParentPtr("scope", scope);
|
const block: *LexicalBlock = @fieldParentPtr("scope", scope);
|
||||||
for (block.locals.get_slice()) |local| {
|
for (block.locals.get_slice()) |local| {
|
||||||
if (lib.string.equal(local.variable.name, identifier)) {
|
if (lib.string.equal(local.variable.name, identifier)) {
|
||||||
break :blk &local.variable;
|
break :blk &local.variable;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
.for_each => {
|
||||||
assert(scope.parent != null);
|
assert(scope.parent != null);
|
||||||
|
const for_each: *Statement.ForEach = @fieldParentPtr("scope", scope);
|
||||||
|
for (for_each.locals) |local| {
|
||||||
|
if (lib.string.equal(local.variable.name, identifier)) {
|
||||||
|
break :blk &local.variable;
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -2752,7 +2897,8 @@ pub const Module = struct {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rule_before_value_keyword(noalias module: *Module, function: ?*Global, value_builder: Value.Builder) *Value {
|
fn rule_before_value_keyword(noalias module: *Module, function: ?*Global, scope: *Scope, value_builder: Value.Builder) *Value {
|
||||||
|
_ = scope;
|
||||||
_ = function;
|
_ = function;
|
||||||
const value = module.values.add();
|
const value = module.values.add();
|
||||||
const new_value: Value = switch (value_builder.token.value_keyword) {
|
const new_value: Value = switch (value_builder.token.value_keyword) {
|
||||||
@ -2770,7 +2916,7 @@ pub const Module = struct {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rule_before_value_intrinsic(noalias module: *Module, function: ?*Global, value_builder: Value.Builder) *Value {
|
fn rule_before_value_intrinsic(noalias module: *Module, function: ?*Global, scope: *Scope, value_builder: Value.Builder) *Value {
|
||||||
const intrinsic = value_builder.token.value_intrinsic;
|
const intrinsic = value_builder.token.value_intrinsic;
|
||||||
const value = module.values.add();
|
const value = module.values.add();
|
||||||
|
|
||||||
@ -2793,7 +2939,7 @@ pub const Module = struct {
|
|||||||
module.skip_space();
|
module.skip_space();
|
||||||
module.expect_character(left_parenthesis);
|
module.expect_character(left_parenthesis);
|
||||||
module.skip_space();
|
module.skip_space();
|
||||||
const arg_value = module.parse_value(function, .{});
|
const arg_value = module.parse_value(function, scope, .{});
|
||||||
module.expect_character(right_parenthesis);
|
module.expect_character(right_parenthesis);
|
||||||
break :blk .{
|
break :blk .{
|
||||||
.bb = .{
|
.bb = .{
|
||||||
@ -2821,7 +2967,7 @@ pub const Module = struct {
|
|||||||
module.skip_space();
|
module.skip_space();
|
||||||
module.expect_character(left_parenthesis);
|
module.expect_character(left_parenthesis);
|
||||||
module.skip_space();
|
module.skip_space();
|
||||||
const arg_value = module.parse_value(function, .{});
|
const arg_value = module.parse_value(function, scope, .{});
|
||||||
module.expect_character(right_parenthesis);
|
module.expect_character(right_parenthesis);
|
||||||
break :blk .{
|
break :blk .{
|
||||||
.bb = .{
|
.bb = .{
|
||||||
@ -2835,7 +2981,7 @@ pub const Module = struct {
|
|||||||
module.skip_space();
|
module.skip_space();
|
||||||
module.expect_character(left_parenthesis);
|
module.expect_character(left_parenthesis);
|
||||||
module.skip_space();
|
module.skip_space();
|
||||||
const arg_value = module.parse_value(function, .{});
|
const arg_value = module.parse_value(function, scope, .{});
|
||||||
module.expect_character(right_parenthesis);
|
module.expect_character(right_parenthesis);
|
||||||
break :blk .{
|
break :blk .{
|
||||||
.bb = .{
|
.bb = .{
|
||||||
@ -2849,7 +2995,7 @@ pub const Module = struct {
|
|||||||
module.skip_space();
|
module.skip_space();
|
||||||
module.expect_character(left_parenthesis);
|
module.expect_character(left_parenthesis);
|
||||||
module.skip_space();
|
module.skip_space();
|
||||||
const v = module.parse_value(function, .{});
|
const v = module.parse_value(function, scope, .{});
|
||||||
module.expect_character(right_parenthesis);
|
module.expect_character(right_parenthesis);
|
||||||
break :blk .{
|
break :blk .{
|
||||||
.bb = .{
|
.bb = .{
|
||||||
@ -2863,13 +3009,13 @@ pub const Module = struct {
|
|||||||
module.skip_space();
|
module.skip_space();
|
||||||
module.expect_character(left_parenthesis);
|
module.expect_character(left_parenthesis);
|
||||||
module.skip_space();
|
module.skip_space();
|
||||||
const condition = module.parse_value(function, .{});
|
const condition = module.parse_value(function, scope, .{});
|
||||||
module.expect_character(',');
|
module.expect_character(',');
|
||||||
module.skip_space();
|
module.skip_space();
|
||||||
const true_value = module.parse_value(function, .{});
|
const true_value = module.parse_value(function, scope, .{});
|
||||||
module.expect_character(',');
|
module.expect_character(',');
|
||||||
module.skip_space();
|
module.skip_space();
|
||||||
const false_value = module.parse_value(function, .{});
|
const false_value = module.parse_value(function, scope, .{});
|
||||||
module.skip_space();
|
module.skip_space();
|
||||||
module.expect_character(right_parenthesis);
|
module.expect_character(right_parenthesis);
|
||||||
break :blk .{
|
break :blk .{
|
||||||
@ -2891,7 +3037,7 @@ pub const Module = struct {
|
|||||||
const enum_type = module.parse_type(function);
|
const enum_type = module.parse_type(function);
|
||||||
module.expect_character(',');
|
module.expect_character(',');
|
||||||
module.skip_space();
|
module.skip_space();
|
||||||
const string_value = module.parse_value(function, .{});
|
const string_value = module.parse_value(function, scope, .{});
|
||||||
module.skip_space();
|
module.skip_space();
|
||||||
module.expect_character(right_parenthesis);
|
module.expect_character(right_parenthesis);
|
||||||
|
|
||||||
@ -2921,7 +3067,7 @@ pub const Module = struct {
|
|||||||
module.skip_space();
|
module.skip_space();
|
||||||
module.expect_character(left_parenthesis);
|
module.expect_character(left_parenthesis);
|
||||||
module.skip_space();
|
module.skip_space();
|
||||||
const v = module.parse_value(function, .{});
|
const v = module.parse_value(function, scope, .{});
|
||||||
module.expect_character(right_parenthesis);
|
module.expect_character(right_parenthesis);
|
||||||
break :blk .{
|
break :blk .{
|
||||||
.bb = .{
|
.bb = .{
|
||||||
@ -2946,7 +3092,7 @@ pub const Module = struct {
|
|||||||
module.skip_space();
|
module.skip_space();
|
||||||
module.expect_character(left_parenthesis);
|
module.expect_character(left_parenthesis);
|
||||||
module.skip_space();
|
module.skip_space();
|
||||||
const va_list = module.parse_value(function, .{});
|
const va_list = module.parse_value(function, scope, .{});
|
||||||
module.expect_character(right_parenthesis);
|
module.expect_character(right_parenthesis);
|
||||||
break :blk .{
|
break :blk .{
|
||||||
.bb = .{
|
.bb = .{
|
||||||
@ -2960,7 +3106,7 @@ pub const Module = struct {
|
|||||||
module.skip_space();
|
module.skip_space();
|
||||||
module.expect_character(left_parenthesis);
|
module.expect_character(left_parenthesis);
|
||||||
module.skip_space();
|
module.skip_space();
|
||||||
const va_list = module.parse_value(function, .{});
|
const va_list = module.parse_value(function, scope, .{});
|
||||||
module.skip_space();
|
module.skip_space();
|
||||||
module.expect_character(',');
|
module.expect_character(',');
|
||||||
module.skip_space();
|
module.skip_space();
|
||||||
@ -2983,7 +3129,8 @@ pub const Module = struct {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rule_before_integer(noalias module: *Module, function: ?*Global, value_builder: Value.Builder) *Value {
|
fn rule_before_integer(noalias module: *Module, function: ?*Global, scope: *Scope, value_builder: Value.Builder) *Value {
|
||||||
|
_ = scope;
|
||||||
_ = function;
|
_ = function;
|
||||||
const v = value_builder.token.integer.value;
|
const v = value_builder.token.integer.value;
|
||||||
const value = module.values.add();
|
const value = module.values.add();
|
||||||
@ -2998,13 +3145,13 @@ pub const Module = struct {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rule_after_binary(noalias module: *Module, function: ?*Global, value_builder: Value.Builder) *Value {
|
fn rule_after_binary(noalias module: *Module, function: ?*Global, scope: *Scope, value_builder: Value.Builder) *Value {
|
||||||
const binary_operator_token = value_builder.token;
|
const binary_operator_token = value_builder.token;
|
||||||
const binary_operator_token_precedence = rules[@intFromEnum(binary_operator_token)].precedence;
|
const binary_operator_token_precedence = rules[@intFromEnum(binary_operator_token)].precedence;
|
||||||
const left = value_builder.left orelse module.report_error();
|
const left = value_builder.left orelse module.report_error();
|
||||||
assert(binary_operator_token_precedence != .assignment); // TODO: this may be wrong. Assignment operator is not allowed in expressions
|
assert(binary_operator_token_precedence != .assignment); // TODO: this may be wrong. Assignment operator is not allowed in expressions
|
||||||
const right_precedence = if (binary_operator_token_precedence == .assignment) .assignment else binary_operator_token_precedence.increment();
|
const right_precedence = if (binary_operator_token_precedence == .assignment) .assignment else binary_operator_token_precedence.increment();
|
||||||
const right = module.parse_precedence(function, value_builder.with_precedence(right_precedence).with_token(.none).with_left(null));
|
const right = module.parse_precedence(function, scope, value_builder.with_precedence(right_precedence).with_token(.none).with_left(null));
|
||||||
|
|
||||||
const binary_operation_kind: Binary.Id = switch (binary_operator_token) {
|
const binary_operation_kind: Binary.Id = switch (binary_operator_token) {
|
||||||
.none => unreachable,
|
.none => unreachable,
|
||||||
@ -3045,7 +3192,7 @@ pub const Module = struct {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rule_before_unary(noalias module: *Module, function: ?*Global, value_builder: Value.Builder) *Value {
|
fn rule_before_unary(noalias module: *Module, function: ?*Global, scope: *Scope, value_builder: Value.Builder) *Value {
|
||||||
assert(value_builder.left == null);
|
assert(value_builder.left == null);
|
||||||
const unary_token = value_builder.token;
|
const unary_token = value_builder.token;
|
||||||
const unary_id: Unary.Id = switch (unary_token) {
|
const unary_id: Unary.Id = switch (unary_token) {
|
||||||
@ -3058,7 +3205,7 @@ pub const Module = struct {
|
|||||||
else => @trap(),
|
else => @trap(),
|
||||||
};
|
};
|
||||||
|
|
||||||
const right = module.parse_precedence(function, value_builder.with_precedence(.prefix).with_token(.none).with_kind(if (unary_id == .@"&") .left else value_builder.kind));
|
const right = module.parse_precedence(function, scope, value_builder.with_precedence(.prefix).with_token(.none).with_kind(if (unary_id == .@"&") .left else value_builder.kind));
|
||||||
|
|
||||||
const value = module.values.add();
|
const value = module.values.add();
|
||||||
value.* = .{
|
value.* = .{
|
||||||
@ -3072,7 +3219,8 @@ pub const Module = struct {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rule_after_dereference(noalias module: *Module, function: ?*Global, value_builder: Value.Builder) *Value {
|
fn rule_after_dereference(noalias module: *Module, function: ?*Global, scope: *Scope, value_builder: Value.Builder) *Value {
|
||||||
|
_ = scope;
|
||||||
_ = function;
|
_ = function;
|
||||||
const value = module.values.add();
|
const value = module.values.add();
|
||||||
value.* = .{
|
value.* = .{
|
||||||
@ -3083,7 +3231,7 @@ pub const Module = struct {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rule_before_brace(noalias module: *Module, function: ?*Global, value_builder: Value.Builder) *Value {
|
fn rule_before_brace(noalias module: *Module, function: ?*Global, scope: *Scope, value_builder: Value.Builder) *Value {
|
||||||
assert(value_builder.left == null);
|
assert(value_builder.left == null);
|
||||||
|
|
||||||
var name_buffer: [64][]const u8 = undefined;
|
var name_buffer: [64][]const u8 = undefined;
|
||||||
@ -3108,7 +3256,7 @@ pub const Module = struct {
|
|||||||
|
|
||||||
module.skip_space();
|
module.skip_space();
|
||||||
|
|
||||||
const value = module.parse_value(function, .{});
|
const value = module.parse_value(function, scope, .{});
|
||||||
value_buffer[field_count] = value;
|
value_buffer[field_count] = value;
|
||||||
module.skip_space();
|
module.skip_space();
|
||||||
|
|
||||||
@ -3162,7 +3310,7 @@ pub const Module = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Array initialization
|
// Array initialization
|
||||||
fn rule_before_bracket(noalias module: *Module, function: ?*Global, value_builder: Value.Builder) *Value {
|
fn rule_before_bracket(noalias module: *Module, function: ?*Global, scope: *Scope, value_builder: Value.Builder) *Value {
|
||||||
assert(value_builder.left == null);
|
assert(value_builder.left == null);
|
||||||
|
|
||||||
var value_buffer: [64]*Value = undefined;
|
var value_buffer: [64]*Value = undefined;
|
||||||
@ -3175,7 +3323,7 @@ pub const Module = struct {
|
|||||||
if (module.consume_character_if_match(right_bracket)) {
|
if (module.consume_character_if_match(right_bracket)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
const v = module.parse_value(function, .{});
|
const v = module.parse_value(function, scope, .{});
|
||||||
value_buffer[element_count] = v;
|
value_buffer[element_count] = v;
|
||||||
|
|
||||||
_ = module.consume_character_if_match(',');
|
_ = module.consume_character_if_match(',');
|
||||||
@ -3198,9 +3346,9 @@ pub const Module = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Array-like subscript
|
// Array-like subscript
|
||||||
fn rule_after_bracket(noalias module: *Module, function: ?*Global, value_builder: Value.Builder) *Value {
|
fn rule_after_bracket(noalias module: *Module, function: ?*Global, scope: *Scope, value_builder: Value.Builder) *Value {
|
||||||
const left = value_builder.left orelse module.report_error();
|
const left = value_builder.left orelse module.report_error();
|
||||||
const index = module.parse_value(function, .{});
|
const index = module.parse_value(function, scope, .{});
|
||||||
const value = module.values.add();
|
const value = module.values.add();
|
||||||
if (module.consume_character_if_match(right_bracket)) {
|
if (module.consume_character_if_match(right_bracket)) {
|
||||||
value.* = .{
|
value.* = .{
|
||||||
@ -3218,7 +3366,7 @@ pub const Module = struct {
|
|||||||
const end = switch (module.consume_character_if_match(right_bracket)) {
|
const end = switch (module.consume_character_if_match(right_bracket)) {
|
||||||
true => null,
|
true => null,
|
||||||
false => b: {
|
false => b: {
|
||||||
const end = module.parse_value(function, .{});
|
const end = module.parse_value(function, scope, .{});
|
||||||
module.expect_character(right_bracket);
|
module.expect_character(right_bracket);
|
||||||
break :b end;
|
break :b end;
|
||||||
},
|
},
|
||||||
@ -3236,15 +3384,15 @@ pub const Module = struct {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rule_before_parenthesis(noalias module: *Module, function: ?*Global, value_builder: Value.Builder) *Value {
|
fn rule_before_parenthesis(noalias module: *Module, function: ?*Global, scope: *Scope, value_builder: Value.Builder) *Value {
|
||||||
_ = value_builder;
|
_ = value_builder;
|
||||||
module.skip_space();
|
module.skip_space();
|
||||||
const v = module.parse_value(function, .{});
|
const v = module.parse_value(function, scope, .{});
|
||||||
module.expect_character(right_parenthesis);
|
module.expect_character(right_parenthesis);
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rule_after_call(noalias module: *Module, function: ?*Global, value_builder: Value.Builder) *Value {
|
fn rule_after_call(noalias module: *Module, function: ?*Global, scope: *Scope, value_builder: Value.Builder) *Value {
|
||||||
const may_be_callable = value_builder.left orelse module.report_error();
|
const may_be_callable = value_builder.left orelse module.report_error();
|
||||||
assert(value_builder.token == .@"(");
|
assert(value_builder.token == .@"(");
|
||||||
var semantic_argument_count: u32 = 0;
|
var semantic_argument_count: u32 = 0;
|
||||||
@ -3259,7 +3407,7 @@ pub const Module = struct {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const argument = module.parse_value(function, .{});
|
const argument = module.parse_value(function, scope, .{});
|
||||||
const argument_index = semantic_argument_count;
|
const argument_index = semantic_argument_count;
|
||||||
semantic_argument_buffer[argument_index] = argument;
|
semantic_argument_buffer[argument_index] = argument;
|
||||||
|
|
||||||
@ -3570,11 +3718,7 @@ pub const Module = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const global_scope = module.current_scope;
|
storage.bb.function.main_block = module.parse_block(global, &storage.bb.function.scope);
|
||||||
module.current_scope = &storage.bb.function.scope;
|
|
||||||
defer module.current_scope = global_scope;
|
|
||||||
|
|
||||||
storage.bb.function.main_block = module.parse_block(global);
|
|
||||||
} else {
|
} else {
|
||||||
storage.bb = .external_function;
|
storage.bb = .external_function;
|
||||||
}
|
}
|
||||||
@ -3834,7 +3978,7 @@ pub const Module = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!global_keyword) {
|
if (!global_keyword) {
|
||||||
const v = module.parse_value(null, .{});
|
const v = module.parse_value(null, &module.scope, .{});
|
||||||
module.skip_space();
|
module.skip_space();
|
||||||
module.expect_character(';');
|
module.expect_character(';');
|
||||||
|
|
||||||
@ -5159,7 +5303,7 @@ pub const Module = struct {
|
|||||||
module.emit_value(function, value, type_kind);
|
module.emit_value(function, value, type_kind);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn analyze_field_access_type(module: *Module, function: ?*Global, value: *Value) *Type {
|
pub fn analyze_field_access_type(module: *Module, function: ?*Global, value: *Value, expected_type: ?*Type) *Type {
|
||||||
switch (value.bb) {
|
switch (value.bb) {
|
||||||
.field_access => |field_access| {
|
.field_access => |field_access| {
|
||||||
module.analyze_value_type(function, field_access.aggregate, .{});
|
module.analyze_value_type(function, field_access.aggregate, .{});
|
||||||
@ -5204,6 +5348,17 @@ pub const Module = struct {
|
|||||||
.right => field_type,
|
.right => field_type,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
.array => {
|
||||||
|
if (expected_type) |t| {
|
||||||
|
if (t.bb != .integer) {
|
||||||
|
module.report_error();
|
||||||
|
}
|
||||||
|
// TODO: see if the count fits into the integer type
|
||||||
|
return t;
|
||||||
|
} else {
|
||||||
|
@trap();
|
||||||
|
}
|
||||||
|
},
|
||||||
.pointer => module.report_error(),
|
.pointer => module.report_error(),
|
||||||
else => @trap(),
|
else => @trap(),
|
||||||
}
|
}
|
||||||
@ -5549,7 +5704,7 @@ pub const Module = struct {
|
|||||||
else => @trap(),
|
else => @trap(),
|
||||||
},
|
},
|
||||||
.field_access => {
|
.field_access => {
|
||||||
const field_type = module.analyze_field_access_type(function, value);
|
const field_type = module.analyze_field_access_type(function, value, expected_type);
|
||||||
if (field_type != expected_type) {
|
if (field_type != expected_type) {
|
||||||
module.report_error();
|
module.report_error();
|
||||||
}
|
}
|
||||||
@ -6001,7 +6156,7 @@ pub const Module = struct {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.field_access => module.analyze_field_access_type(function, value),
|
.field_access => module.analyze_field_access_type(function, value, null),
|
||||||
.string_literal => module.get_slice_type(.{ .type = module.integer_type(8, false) }),
|
.string_literal => module.get_slice_type(.{ .type = module.integer_type(8, false) }),
|
||||||
.slice_expression => |slice_expression| blk: {
|
.slice_expression => |slice_expression| blk: {
|
||||||
module.analyze_value_type(function, slice_expression.array_like, .{});
|
module.analyze_value_type(function, slice_expression.array_like, .{});
|
||||||
@ -6608,6 +6763,7 @@ pub const Module = struct {
|
|||||||
const trunc = module.llvm.builder.create_truncate(shift, field.type.llvm.abi.?);
|
const trunc = module.llvm.builder.create_truncate(shift, field.type.llvm.abi.?);
|
||||||
break :blk trunc;
|
break :blk trunc;
|
||||||
},
|
},
|
||||||
|
.array => |array| break :blk value_type.get_llvm(type_kind).to_integer().get_constant(array.element_count, 0).to_value(),
|
||||||
else => @trap(),
|
else => @trap(),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -6739,13 +6895,13 @@ pub const Module = struct {
|
|||||||
value.llvm = llvm_value;
|
value.llvm = llvm_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn analyze_statement(module: *Module, function: *Global, block: *LexicalBlock, statement: *Statement, last_line: *u32, last_column: *u32, last_statement_debug_location: **llvm.DI.Location) void {
|
pub fn analyze_statement(module: *Module, function: *Global, scope: *Scope, statement: *Statement, last_line: *u32, last_column: *u32, last_statement_debug_location: **llvm.DI.Location) void {
|
||||||
const llvm_function = function.variable.storage.?.llvm.?.to_function();
|
const llvm_function = function.variable.storage.?.llvm.?.to_function();
|
||||||
const current_function = &function.variable.storage.?.bb.function;
|
const current_function = &function.variable.storage.?.bb.function;
|
||||||
if (module.has_debug_info) {
|
if (module.has_debug_info) {
|
||||||
if (statement.line != last_line.* or statement.column != last_column.*) {
|
if (statement.line != last_line.* or statement.column != last_column.*) {
|
||||||
const inlined_at: ?*llvm.DI.Metadata = null; // TODO
|
const inlined_at: ?*llvm.DI.Metadata = null; // TODO
|
||||||
last_statement_debug_location.* = llvm.DI.create_debug_location(module.llvm.context, statement.line, statement.column, block.scope.llvm.?, inlined_at);
|
last_statement_debug_location.* = llvm.DI.create_debug_location(module.llvm.context, statement.line, statement.column, scope.llvm.?, inlined_at);
|
||||||
module.llvm.builder.set_current_debug_location(last_statement_debug_location.*);
|
module.llvm.builder.set_current_debug_location(last_statement_debug_location.*);
|
||||||
last_line.* = statement.line;
|
last_line.* = statement.line;
|
||||||
last_column.* = statement.column;
|
last_column.* = statement.column;
|
||||||
@ -6980,14 +7136,14 @@ pub const Module = struct {
|
|||||||
|
|
||||||
current_function.exit_block = exit_block;
|
current_function.exit_block = exit_block;
|
||||||
|
|
||||||
module.analyze_statement(function, block, if_statement.if_statement, last_line, last_line, last_statement_debug_location);
|
module.analyze_statement(function, scope, if_statement.if_statement, last_line, last_line, last_statement_debug_location);
|
||||||
if (module.llvm.builder.get_insert_block() != null) {
|
if (module.llvm.builder.get_insert_block() != null) {
|
||||||
_ = module.llvm.builder.create_branch(exit_block);
|
_ = module.llvm.builder.create_branch(exit_block);
|
||||||
}
|
}
|
||||||
|
|
||||||
module.llvm.builder.position_at_end(not_taken_block);
|
module.llvm.builder.position_at_end(not_taken_block);
|
||||||
if (if_statement.else_statement) |else_statement| {
|
if (if_statement.else_statement) |else_statement| {
|
||||||
module.analyze_statement(function, block, else_statement, last_line, last_line, last_statement_debug_location);
|
module.analyze_statement(function, scope, else_statement, last_line, last_line, last_statement_debug_location);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (module.llvm.builder.get_insert_block() != null) {
|
if (module.llvm.builder.get_insert_block() != null) {
|
||||||
@ -7102,6 +7258,119 @@ pub const Module = struct {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
.block => |child_block| module.analyze_block(function, child_block),
|
.block => |child_block| module.analyze_block(function, child_block),
|
||||||
|
.for_each => |*for_loop| {
|
||||||
|
if (module.has_debug_info) {
|
||||||
|
const lexical_block = module.llvm.di_builder.create_lexical_block(for_loop.scope.parent.?.llvm.?, module.llvm.file, for_loop.scope.line, for_loop.scope.column);
|
||||||
|
for_loop.scope.llvm = lexical_block.to_scope();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (for_loop.locals, for_loop.left_values, for_loop.right_values) |local, kind, right| {
|
||||||
|
assert(right.kind == .left);
|
||||||
|
module.analyze_value_type(function, right, .{});
|
||||||
|
const pointer_type = right.type.?;
|
||||||
|
if (pointer_type.bb != .pointer) {
|
||||||
|
module.report_error();
|
||||||
|
}
|
||||||
|
const aggregate_type = pointer_type.bb.pointer.type;
|
||||||
|
const child_type = switch (aggregate_type.bb) {
|
||||||
|
.array => |array| array.element_type,
|
||||||
|
else => @trap(),
|
||||||
|
};
|
||||||
|
assert(local.variable.type == null);
|
||||||
|
const local_type = switch (kind) {
|
||||||
|
.left => module.get_pointer_type(.{ .type = child_type }),
|
||||||
|
.right => child_type,
|
||||||
|
};
|
||||||
|
local.variable.type = local_type;
|
||||||
|
module.emit_local_storage(local, last_statement_debug_location.*);
|
||||||
|
module.emit_value(function, right, .memory);
|
||||||
|
}
|
||||||
|
|
||||||
|
const length = for (for_loop.right_values) |right| {
|
||||||
|
const pointer_type = right.type.?;
|
||||||
|
if (pointer_type.bb != .pointer) {
|
||||||
|
module.report_error();
|
||||||
|
}
|
||||||
|
const aggregate_type = pointer_type.bb.pointer.type;
|
||||||
|
const length = switch (aggregate_type.bb) {
|
||||||
|
.array => |array| array.element_count,
|
||||||
|
else => @trap(),
|
||||||
|
};
|
||||||
|
break length;
|
||||||
|
} else unreachable;
|
||||||
|
|
||||||
|
const index_type = module.integer_type(64, false);
|
||||||
|
index_type.resolve(module);
|
||||||
|
const index_zero = index_type.llvm.abi.?.get_zero().to_value();
|
||||||
|
const index_alloca = module.create_alloca(.{ .type = index_type, .name = "foreach.index" });
|
||||||
|
_ = module.create_store(.{ .type = index_type, .source_value = index_zero, .destination_value = index_alloca });
|
||||||
|
|
||||||
|
const loop_entry_block = module.llvm.context.create_basic_block("foreach.entry", llvm_function);
|
||||||
|
const loop_body_block = module.llvm.context.create_basic_block("foreach.body", llvm_function);
|
||||||
|
const loop_continue_block = module.llvm.context.create_basic_block("foreach.continue", llvm_function);
|
||||||
|
const loop_exit_block = module.llvm.context.create_basic_block("foreach.exit", llvm_function);
|
||||||
|
_ = module.llvm.builder.create_branch(loop_entry_block);
|
||||||
|
module.llvm.builder.position_at_end(loop_entry_block);
|
||||||
|
|
||||||
|
const header_index_load = module.create_load(.{ .type = index_type, .value = index_alloca });
|
||||||
|
const index_compare = module.llvm.builder.create_integer_compare(.ult, header_index_load, index_type.llvm.abi.?.to_integer().get_constant(length, 0).to_value());
|
||||||
|
_ = module.llvm.builder.create_conditional_branch(index_compare, loop_body_block, loop_exit_block);
|
||||||
|
|
||||||
|
module.llvm.builder.position_at_end(loop_body_block);
|
||||||
|
const body_index_load = module.create_load(.{ .type = index_type, .value = index_alloca });
|
||||||
|
|
||||||
|
for (for_loop.locals, for_loop.left_values, for_loop.right_values) |local, kind, right| {
|
||||||
|
const element_pointer_value = switch (right.type.?.bb.pointer.type.bb) {
|
||||||
|
.array => module.llvm.builder.create_gep(.{
|
||||||
|
.type = right.type.?.bb.pointer.type.llvm.memory.?,
|
||||||
|
.aggregate = right.llvm.?,
|
||||||
|
.indices = &.{index_zero, body_index_load},
|
||||||
|
}),
|
||||||
|
else => @trap(),
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (kind) {
|
||||||
|
.left => {
|
||||||
|
_ = module.create_store(.{
|
||||||
|
.type = local.variable.type.?,
|
||||||
|
.source_value = element_pointer_value,
|
||||||
|
.destination_value = local.variable.storage.?.llvm.?,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
.right => switch (local.variable.type.?.get_evaluation_kind()) {
|
||||||
|
.scalar => {
|
||||||
|
const load = module.create_load(.{
|
||||||
|
.type = local.variable.type.?,
|
||||||
|
.value = element_pointer_value,
|
||||||
|
});
|
||||||
|
_ = module.create_store(.{
|
||||||
|
.type = local.variable.type.?,
|
||||||
|
.source_value = load,
|
||||||
|
.destination_value = local.variable.storage.?.llvm.?,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
.aggregate => {
|
||||||
|
@trap();
|
||||||
|
},
|
||||||
|
.complex => @trap(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.analyze_statement(function, &for_loop.scope, for_loop.predicate, last_line, last_column, last_statement_debug_location);
|
||||||
|
|
||||||
|
if (module.llvm.builder.get_insert_block() != null) {
|
||||||
|
_ = module.llvm.builder.create_branch(loop_continue_block);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.llvm.builder.position_at_end(loop_continue_block);
|
||||||
|
const continue_index_load = module.create_load(.{ .type = index_type, .value = index_alloca });
|
||||||
|
const add = module.llvm.builder.create_add(continue_index_load, index_type.llvm.abi.?.to_integer().get_constant(1, 0).to_value());
|
||||||
|
_ = module.create_store(.{ .type = index_type, .source_value = add, .destination_value = index_alloca });
|
||||||
|
_ = module.llvm.builder.create_branch(loop_entry_block);
|
||||||
|
|
||||||
|
module.llvm.builder.position_at_end(loop_exit_block);
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7116,7 +7385,7 @@ pub const Module = struct {
|
|||||||
var last_statement_debug_location: *llvm.DI.Location = undefined;
|
var last_statement_debug_location: *llvm.DI.Location = undefined;
|
||||||
|
|
||||||
for (block.statements.get_slice()) |statement| {
|
for (block.statements.get_slice()) |statement| {
|
||||||
module.analyze_statement(function, block, statement, &last_line, &last_column, &last_statement_debug_location);
|
module.analyze_statement(function, &block.scope, statement, &last_line, &last_column, &last_statement_debug_location);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -8789,7 +9058,6 @@ pub fn compile(arena: *Arena, options: Options) void {
|
|||||||
.void_type = void_type,
|
.void_type = void_type,
|
||||||
.noreturn_type = noreturn_type,
|
.noreturn_type = noreturn_type,
|
||||||
.void_value = void_value,
|
.void_value = void_value,
|
||||||
.current_scope = undefined,
|
|
||||||
.scope = .{
|
.scope = .{
|
||||||
.kind = .global,
|
.kind = .global,
|
||||||
.column = 0,
|
.column = 0,
|
||||||
@ -8805,8 +9073,6 @@ pub fn compile(arena: *Arena, options: Options) void {
|
|||||||
.silent = options.silent,
|
.silent = options.silent,
|
||||||
};
|
};
|
||||||
|
|
||||||
module.current_scope = &module.scope;
|
|
||||||
|
|
||||||
module.parse();
|
module.parse();
|
||||||
module.emit();
|
module.emit();
|
||||||
}
|
}
|
||||||
|
@ -316,4 +316,5 @@ const names = &[_][]const u8{
|
|||||||
"else_if_complicated",
|
"else_if_complicated",
|
||||||
"shortcircuiting_if",
|
"shortcircuiting_if",
|
||||||
"field_access_left_assign",
|
"field_access_left_assign",
|
||||||
|
"for_each",
|
||||||
};
|
};
|
||||||
|
32
tests/for_each.bbb
Normal file
32
tests/for_each.bbb
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
require = fn (ok: u1) void
|
||||||
|
{
|
||||||
|
if (!ok) #trap();
|
||||||
|
}
|
||||||
|
|
||||||
|
[export] main = fn [cc(c)] () s32
|
||||||
|
{
|
||||||
|
>array: [_]u32 = [5, 3, 2];
|
||||||
|
>counter: u32 = 0;
|
||||||
|
for (e : array)
|
||||||
|
{
|
||||||
|
counter += e;
|
||||||
|
}
|
||||||
|
|
||||||
|
require(counter == 10);
|
||||||
|
|
||||||
|
for (&e : array)
|
||||||
|
{
|
||||||
|
e.& += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
>new_counter: u32 = 0;
|
||||||
|
|
||||||
|
for (e : array)
|
||||||
|
{
|
||||||
|
new_counter += e;
|
||||||
|
}
|
||||||
|
|
||||||
|
require(new_counter == counter + array.length);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user