Implement pointers
This commit is contained in:
parent
088c8d8d5d
commit
3381aa0625
@ -157,6 +157,7 @@ const LocalSymbol = struct {
|
||||
attributes: Attributes = .{},
|
||||
local_declaration: LocalDeclaration,
|
||||
type: *Type,
|
||||
appointee_type: ?*Type = null,
|
||||
instruction: Instruction,
|
||||
alignment: u32,
|
||||
|
||||
@ -622,6 +623,7 @@ const Parser = struct{
|
||||
return value;
|
||||
},
|
||||
'[' => {
|
||||
// This is an array expression
|
||||
parser.i += 1;
|
||||
|
||||
const ty = maybe_type orelse exit(1);
|
||||
@ -905,17 +907,20 @@ const Parser = struct{
|
||||
},
|
||||
};
|
||||
},
|
||||
' ', ',', ';', ')' => {
|
||||
const declaration_value = switch (lookup_result.declaration.*.id) {
|
||||
.local => block: {
|
||||
'&' => {
|
||||
parser.i += 1;
|
||||
|
||||
const local_declaration = lookup_result.declaration.*.get_payload(.local);
|
||||
const local_symbol = local_declaration.to_symbol();
|
||||
return &local_symbol.instruction.value;
|
||||
},
|
||||
'@' => {
|
||||
parser.i += 1;
|
||||
|
||||
if (maybe_type) |ty| {
|
||||
switch (typecheck(ty, local_symbol.type)) {
|
||||
.success => {},
|
||||
}
|
||||
}
|
||||
const local_declaration = lookup_result.declaration.*.get_payload(.local);
|
||||
const local_symbol = local_declaration.to_symbol();
|
||||
assert(local_symbol.type.sema.id == .pointer);
|
||||
assert(local_symbol.appointee_type != null);
|
||||
|
||||
const load = thread.loads.append(.{
|
||||
.instruction = .{
|
||||
@ -934,7 +939,73 @@ const Parser = struct{
|
||||
.is_volatile = false,
|
||||
});
|
||||
_ = analyzer.current_basic_block.instructions.append(&load.instruction);
|
||||
break :block &load.instruction.value;
|
||||
|
||||
return switch (side) {
|
||||
.left => &load.instruction.value,
|
||||
.right => block: {
|
||||
const pointer_load_type = local_symbol.appointee_type.?;
|
||||
if (maybe_type) |ty| {
|
||||
switch (typecheck(ty, pointer_load_type)) {
|
||||
.success => {},
|
||||
}
|
||||
}
|
||||
|
||||
const pointer_load = thread.loads.append(.{
|
||||
.instruction = .{
|
||||
.value = .{
|
||||
.sema = .{
|
||||
.thread = thread.get_index(),
|
||||
.resolved = true,
|
||||
.id = .instruction,
|
||||
},
|
||||
},
|
||||
.id = .load,
|
||||
},
|
||||
.value = &load.instruction.value,
|
||||
.type = pointer_load_type,
|
||||
.alignment = pointer_load_type.alignment,
|
||||
.is_volatile = false,
|
||||
});
|
||||
_ = analyzer.current_basic_block.instructions.append(&pointer_load.instruction);
|
||||
break :block &pointer_load.instruction.value;
|
||||
},
|
||||
};
|
||||
},
|
||||
' ', ',', ';', ')' => {
|
||||
const declaration_value = switch (lookup_result.declaration.*.id) {
|
||||
.local => block: {
|
||||
const local_declaration = lookup_result.declaration.*.get_payload(.local);
|
||||
const local_symbol = local_declaration.to_symbol();
|
||||
|
||||
if (maybe_type) |ty| {
|
||||
switch (typecheck(ty, local_symbol.type)) {
|
||||
.success => {},
|
||||
}
|
||||
}
|
||||
|
||||
break :block switch (side) {
|
||||
.right => b: {
|
||||
const load = thread.loads.append(.{
|
||||
.instruction = .{
|
||||
.value = .{
|
||||
.sema = .{
|
||||
.thread = thread.get_index(),
|
||||
.resolved = true,
|
||||
.id = .instruction,
|
||||
},
|
||||
},
|
||||
.id = .load,
|
||||
},
|
||||
.value = &local_symbol.instruction.value,
|
||||
.type = local_symbol.type,
|
||||
.alignment = local_symbol.type.alignment,
|
||||
.is_volatile = false,
|
||||
});
|
||||
_ = analyzer.current_basic_block.instructions.append(&load.instruction);
|
||||
break :b &load.instruction.value;
|
||||
},
|
||||
.left => &local_symbol.instruction.value,
|
||||
};
|
||||
},
|
||||
.argument => block: {
|
||||
const argument_declaration = lookup_result.declaration.*.get_payload(.argument);
|
||||
@ -944,6 +1015,8 @@ const Parser = struct{
|
||||
.success => {},
|
||||
}
|
||||
}
|
||||
break :block switch (side) {
|
||||
.right => b: {
|
||||
const load = thread.loads.append(.{
|
||||
.instruction = .{
|
||||
.value = .{
|
||||
@ -961,7 +1034,10 @@ const Parser = struct{
|
||||
.is_volatile = false,
|
||||
});
|
||||
_ = analyzer.current_basic_block.instructions.append(&load.instruction);
|
||||
break :block &load.instruction.value;
|
||||
break :b &load.instruction.value;
|
||||
},
|
||||
.left => &argument_symbol.instruction.value,
|
||||
};
|
||||
},
|
||||
.global => block: {
|
||||
const global_declaration = lookup_result.declaration.*.get_payload(.global);
|
||||
@ -981,6 +1057,8 @@ const Parser = struct{
|
||||
}
|
||||
}
|
||||
|
||||
break :block switch (side) {
|
||||
.right => b: {
|
||||
const load = thread.loads.append(.{
|
||||
.instruction = .{
|
||||
.value = .{
|
||||
@ -998,12 +1076,18 @@ const Parser = struct{
|
||||
.is_volatile = false,
|
||||
});
|
||||
_ = analyzer.current_basic_block.instructions.append(&load.instruction);
|
||||
break :block &load.instruction.value;
|
||||
break :b &load.instruction.value;
|
||||
},
|
||||
.left => &global_symbol.value,
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
const declaration_type = declaration_value.get_type();
|
||||
|
||||
if (unary != .none) assert(side == .right);
|
||||
if (side == .left) assert(side == .left);
|
||||
|
||||
return switch (unary) {
|
||||
.none => declaration_value,
|
||||
.one_complement => block: {
|
||||
@ -1119,6 +1203,10 @@ const Parser = struct{
|
||||
var it_ty: ?*Type = ty;
|
||||
|
||||
while (true) {
|
||||
// if (src[parser.i] == ';') {
|
||||
// break;
|
||||
// }
|
||||
|
||||
if (iterations == 1 and it_ty == null) {
|
||||
it_ty = previous_value.get_type();
|
||||
}
|
||||
@ -1724,6 +1812,9 @@ const Value = struct {
|
||||
const lz = instruction.get_payload(.leading_zeroes);
|
||||
return lz.value.get_type();
|
||||
},
|
||||
.local_symbol => {
|
||||
return &instance.threads[value.sema.thread].pointer;
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
};
|
||||
},
|
||||
@ -1731,6 +1822,16 @@ const Value = struct {
|
||||
const constant_int = value.get_payload(.constant_int);
|
||||
return constant_int.type;
|
||||
},
|
||||
.global_symbol => {
|
||||
const global_symbol = value.get_payload(.global_symbol);
|
||||
return switch (global_symbol.id) {
|
||||
.global_variable => b: {
|
||||
const global_variable = global_symbol.get_payload(.global_variable);
|
||||
break :b global_variable.type;
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
};
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
};
|
||||
}
|
||||
@ -1753,6 +1854,7 @@ const Type = struct {
|
||||
void,
|
||||
integer,
|
||||
array,
|
||||
pointer,
|
||||
};
|
||||
|
||||
const Integer = struct {
|
||||
@ -1781,6 +1883,7 @@ const Type = struct {
|
||||
.void = void,
|
||||
.integer = Integer,
|
||||
.array = Array,
|
||||
.pointer = void,
|
||||
});
|
||||
|
||||
fn get_payload(ty: *Type, comptime id: Id) *id_to_type_map.get(id) {
|
||||
@ -2277,6 +2380,15 @@ const Thread = struct{
|
||||
.size = 0,
|
||||
.alignment = 0,
|
||||
},
|
||||
pointer: Type = .{
|
||||
.sema = .{
|
||||
.thread = undefined,
|
||||
.id = .pointer,
|
||||
.resolved = true,
|
||||
},
|
||||
.size = 8,
|
||||
.alignment = 8,
|
||||
},
|
||||
handle: std.Thread = undefined,
|
||||
|
||||
fn add_thread_work(thread: *Thread, job: Job) void {
|
||||
@ -3833,8 +3945,13 @@ fn llvm_get_type(thread: *Thread, ty: *Type) *LLVM.Type {
|
||||
const array_type = LLVM.Type.Array.get(element_type, array_ty.descriptor.element_count);
|
||||
break :b array_type.toType();
|
||||
},
|
||||
.pointer => b: {
|
||||
const pointer_type = thread.llvm.context.getPointerType(0);
|
||||
break :b pointer_type.toType();
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
};
|
||||
|
||||
return llvm_type;
|
||||
}
|
||||
}
|
||||
@ -4053,6 +4170,7 @@ pub fn analyze_local_block(thread: *Thread, analyzer: *Analyzer, parser: *Parser
|
||||
initial_value: *Value,
|
||||
type: *Type,
|
||||
};
|
||||
|
||||
const result: LocalResult = switch (src[parser.i]) {
|
||||
':' => block: {
|
||||
parser.i += 1;
|
||||
@ -4115,6 +4233,22 @@ pub fn analyze_local_block(thread: *Thread, analyzer: *Analyzer, parser: *Parser
|
||||
.alignment = result.type.alignment,
|
||||
});
|
||||
|
||||
if (local_symbol.type.sema.id == .pointer) {
|
||||
switch (result.initial_value.sema.id) {
|
||||
.instruction => {
|
||||
const instruction = result.initial_value.get_payload(.instruction);
|
||||
switch (instruction.id) {
|
||||
.local_symbol => {
|
||||
const right_local_symbol = instruction.get_payload(.local_symbol);
|
||||
local_symbol.appointee_type = right_local_symbol.type;
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
}
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
}
|
||||
}
|
||||
|
||||
_ = analyzer.current_function.stack_slots.append(local_symbol);
|
||||
|
||||
const store = thread.stores.append(.{
|
||||
@ -4290,21 +4424,9 @@ pub fn analyze_local_block(thread: *Thread, analyzer: *Analyzer, parser: *Parser
|
||||
}
|
||||
|
||||
if (statement_start_ch_index == parser.i) {
|
||||
if (is_identifier_char_start(statement_start_ch)) {
|
||||
const raw_identifier = parser.parse_raw_identifier(src);
|
||||
const keyword_index = parse_keyword(raw_identifier);
|
||||
const is_keyword = keyword_index != ~@as(u32, 0);
|
||||
if (is_keyword) {
|
||||
const keyword: Keyword = @enumFromInt(keyword_index);
|
||||
switch (keyword) {
|
||||
else => |t| @panic(@tagName(t)),
|
||||
}
|
||||
} else {
|
||||
const identifier = intern_identifier(&thread.identifiers, raw_identifier);
|
||||
const left = parser.parse_single_expression(analyzer, thread, file, null, .left);
|
||||
parser.skip_space(src);
|
||||
|
||||
const declaration_lookup = analyzer.current_scope.get_declaration(identifier) orelse unreachable;
|
||||
|
||||
const operation_index = parser.i;
|
||||
const operation_ch = src[operation_index];
|
||||
var is_binary_operation = false;
|
||||
@ -4324,34 +4446,74 @@ pub fn analyze_local_block(thread: *Thread, analyzer: *Analyzer, parser: *Parser
|
||||
|
||||
parser.skip_space(src);
|
||||
|
||||
const declaration_value = get_declaration_value(analyzer, thread, declaration_lookup.declaration.*, null, .right);
|
||||
const declaration_type = switch (declaration_lookup.declaration.*.id) {
|
||||
.argument => block: {
|
||||
const argument_declaration = declaration_lookup.declaration.*.get_payload(.argument);
|
||||
const argument_symbol = argument_declaration.to_symbol();
|
||||
break :block argument_symbol.type;
|
||||
},
|
||||
.local => block: {
|
||||
const local_declaration = declaration_lookup.declaration.*.get_payload(.local);
|
||||
const local_symbol = local_declaration.to_symbol();
|
||||
break :block local_symbol.type;
|
||||
},
|
||||
.global => block: {
|
||||
const global_declaration = declaration_lookup.declaration.*.get_payload(.global);
|
||||
const global_symbol = global_declaration.to_symbol();
|
||||
switch (global_symbol.id) {
|
||||
.global_variable => {
|
||||
const global_variable = global_symbol.get_payload(.global_variable);
|
||||
break :block global_variable.type;
|
||||
const expected_right_type = switch (left.sema.id) {
|
||||
.instruction => b: {
|
||||
const instruction = left.get_payload(.instruction);
|
||||
switch (instruction.id) {
|
||||
.load => {
|
||||
const load = instruction.get_payload(.load);
|
||||
switch (load.value.sema.id) {
|
||||
.instruction => {
|
||||
const load_instruction = load.value.get_payload(.instruction);
|
||||
switch (load_instruction.id) {
|
||||
.local_symbol => {
|
||||
const local_symbol = load_instruction.get_payload(.local_symbol);
|
||||
if (local_symbol.type.sema.id == .pointer) {
|
||||
break :b local_symbol.appointee_type.?;
|
||||
} else {
|
||||
break :b local_symbol.type;
|
||||
}
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
}
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
}
|
||||
},
|
||||
.local_symbol => {
|
||||
const local_symbol = instruction.get_payload(.local_symbol);
|
||||
assert(local_symbol.appointee_type == null);
|
||||
break :b local_symbol.type;
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
}
|
||||
},
|
||||
.global_symbol => b: {
|
||||
const global_symbol = left.get_payload(.global_symbol);
|
||||
break :b switch (global_symbol.id) {
|
||||
.global_variable => gv: {
|
||||
const global_variable = global_symbol.get_payload(.global_variable);
|
||||
break :gv global_variable.type;
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
};
|
||||
const right = parser.parse_expression(analyzer, thread, file, declaration_type, .right);
|
||||
},
|
||||
else => |t| @panic(@tagName(t)),
|
||||
};
|
||||
|
||||
const source = switch (is_binary_operation) {
|
||||
false => right,
|
||||
false => parser.parse_expression(analyzer, thread, file, expected_right_type, .right),
|
||||
true => block: {
|
||||
const left_load = thread.loads.append(.{
|
||||
.instruction = .{
|
||||
.id = .load,
|
||||
.value = .{
|
||||
.sema = .{
|
||||
.thread = thread.get_index(),
|
||||
.resolved = true,
|
||||
.id = .instruction,
|
||||
},
|
||||
},
|
||||
},
|
||||
.value = left,
|
||||
.type = expected_right_type,
|
||||
.alignment = expected_right_type.alignment,
|
||||
.is_volatile = false,
|
||||
});
|
||||
_ = analyzer.current_basic_block.instructions.append(&left_load.instruction);
|
||||
|
||||
const right = parser.parse_expression(analyzer, thread, file, expected_right_type, .right);
|
||||
|
||||
const binary_operation_id: IntegerBinaryOperation.Id = switch (operation_ch) {
|
||||
'+' => .add,
|
||||
else => unreachable,
|
||||
@ -4368,20 +4530,17 @@ pub fn analyze_local_block(thread: *Thread, analyzer: *Analyzer, parser: *Parser
|
||||
},
|
||||
},
|
||||
},
|
||||
.left = declaration_value,
|
||||
.left = &left_load.instruction.value,
|
||||
.right = right,
|
||||
.type = declaration_type,
|
||||
.type = expected_right_type,
|
||||
});
|
||||
_ = analyzer.current_basic_block.instructions.append(&binary_operation.instruction);
|
||||
break :block &binary_operation.instruction.value;
|
||||
},
|
||||
};
|
||||
|
||||
parser.skip_space(src);
|
||||
|
||||
parser.expect_character(src, ';');
|
||||
|
||||
const declaration_pointer = get_declaration_value(analyzer, thread, declaration_lookup.declaration.*, null, .left);
|
||||
const store = thread.stores.append(.{
|
||||
.instruction = .{
|
||||
.id = .store,
|
||||
@ -4393,9 +4552,9 @@ pub fn analyze_local_block(thread: *Thread, analyzer: *Analyzer, parser: *Parser
|
||||
},
|
||||
},
|
||||
},
|
||||
.destination = declaration_pointer,
|
||||
.destination = left,
|
||||
.source = source,
|
||||
.alignment = declaration_type.alignment,
|
||||
.alignment = expected_right_type.alignment,
|
||||
.is_volatile = false,
|
||||
});
|
||||
_ = analyzer.current_basic_block.instructions.append(&store.instruction);
|
||||
@ -4403,10 +4562,6 @@ pub fn analyze_local_block(thread: *Thread, analyzer: *Analyzer, parser: *Parser
|
||||
else => @panic((src.ptr + parser.i)[0..1]),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
exit_with_error("Unrecognized statement initial char");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parser.expect_character(src, brace_close);
|
||||
|
6
retest/standalone/pointer/main.nat
Normal file
6
retest/standalone/pointer/main.nat
Normal file
@ -0,0 +1,6 @@
|
||||
fn[cc(.c)] main[export]() s32 {
|
||||
>a: s32 = 0;
|
||||
>pointer = a&;
|
||||
pointer@ = 4;
|
||||
return pointer@ - a;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user