Skip to content

Commit

Permalink
Add embeds
Browse files Browse the repository at this point in the history
  • Loading branch information
Victorious3 committed Apr 20, 2024
1 parent 2daae03 commit a1a3dc5
Show file tree
Hide file tree
Showing 7 changed files with 446 additions and 72 deletions.
199 changes: 152 additions & 47 deletions src/compiler.pr
Original file line number Diff line number Diff line change
Expand Up @@ -1522,7 +1522,7 @@ def convert_ref_to_ptr(tpe: &typechecking::Type, value: Value, loc: &Value, stat
return bitcast_ret
}

def convert_value_to_ref(tpe: &typechecking::Type, value: Value, loc: &Value, state: &State) -> Value {
def convert_value_to_ref(tpe: &typechecking::Type, value: Value, loc: &Value, state: &State, initial_ref_count: size_t = 0) -> Value {
if tpe.tpe and value.tpe.kind != tpe.tpe.kind {
value = convert_to(loc, value, tpe.tpe, state)
}
Expand Down Expand Up @@ -1564,7 +1564,7 @@ def convert_value_to_ref(tpe: &typechecking::Type, value: Value, loc: &Value, st
let store1 = make_insn_dbg(InsnKind::STORE, loc)
store1.value.store = [
loc = refcount,
value = [ kind = ValueKind::INT, tpe = builtins::int64_, i = 0 ] !Value
value = [ kind = ValueKind::INT, tpe = builtins::int64_, i = initial_ref_count ] !Value
] !InsnStore
push_insn(store1, state)
}
Expand Down Expand Up @@ -2077,6 +2077,19 @@ def convert_to(kind: InsnKind, loc: &Value, value: Value, tpe: &typechecking::Ty
return ret
}

def get_embed_field(left: &typechecking::Type, right: &typechecking::Type, state: &State) -> &typechecking::StructMember {
if is_interface(left) and is_struct(right) {
if typechecking::implements(right, left, state.module, check_embed = false) { return null }
for var field in @right.fields {
if field.is_embed and typechecking::implements(field.tpe, left, state.module, check_embed = false) {
return field
}
}
}

return null
}

// value gets loaded by this function
def convert_to(loc: &Value, value: Value, tpe: &typechecking::Type, state: &State) -> Value {
if not value.tpe or not tpe { return NO_VALUE }
Expand Down Expand Up @@ -2114,6 +2127,42 @@ def convert_to(loc: &Value, value: Value, tpe: &typechecking::Type, state: &Stat
return value
}
}
let left = tpe.tpe if is_ref(tpe) else tpe
let right = value.tpe.tpe if is_ref(value.tpe) else value.tpe
let embed_field = get_embed_field(left, right, state)

// Try to convert to embedded struct / reference
if is_struct(right) and (is_struct(left) or embed_field) {
var is_embed = false
var field: StructMember
if embed_field {
is_embed = true
field = @embed_field
} else {
for var f in @right.fields {
if f.is_embed and (equals(f.tpe, tpe) or equals(f.tpe, tpe.tpe)) {
is_embed = true
field = f
break
}
}
}
if is_embed {
var unwrap = load_value(value, loc, state)
// Unwrap reference on the value side
if is_ref(value.tpe) {
let ref = state.extract_value(pointer(right), unwrap, [1], loc)
unwrap = state.load(right, ref, loc)
}
// Extract element
var elem = state.extract_value(field.tpe, unwrap, [field.index !int], loc)
// Wrap in reference if needed
if is_ref(tpe) and not is_ref(field.tpe) {
elem = convert_value_to_ref(tpe, elem, loc, state, 1)
}
return elem
}
}
if tpe.kind == value.tpe.kind and value.tpe.is_anon and typechecking::is_struct(value.tpe) {
return convert_anon_to_struct(tpe, value, loc, state)
}
Expand Down Expand Up @@ -2322,7 +2371,18 @@ def walk_StructLitUnion(node: &parser::Node, state: &State) -> Value {
return load_ret
}

// TODO add loc to this
def locals_to_insert_value(value: &Value, state: &State) {
import_cstd_function("malloc", state)

var aref = is_ref(value.tpe)
let reftpe = value.tpe
var new_value = value
if aref {
new_value = @value
new_value.tpe = value.tpe.tpe
}

let values = value.values
for var i in 0..values.size {
let val = values(i)
Expand All @@ -2332,22 +2392,87 @@ def locals_to_insert_value(value: &Value, state: &State) {
tpe = val.tpe
] !Value

let ret = make_local_value(value.tpe, null, state)
let ret = make_local_value(new_value.tpe, null, state)

let index = allocate_ref(int, 1)
index(0) = i
let insert = make_insn(InsnKind::INSERTVALUE)
(@insert).value.insert_value = [
ret = ret,
value = @value,
value = @new_value,
element = val,
index = index
] !InsnInsertValue

push_insn(insert, state)
@value = ret
@new_value = ret
}
}
if aref {
@value = convert_value_to_ref(reftpe, @new_value, null, state, 1)
}
}

def struct_lit_create_value(tpe: &typechecking::Type, kwargs: &Vector(&parser::Node), loc: &Value, state: &State) -> &[Value] {
if not tpe { return null }
if is_ref(tpe) { tpe = tpe.tpe }

var types = vector::make(type &typechecking::Type)
if tpe.kind == typechecking::TypeKind::TUPLE {
types = tpe.return_t
} else {
for var field in @tpe.fields {
types.push(field.tpe)
}
}

let values = allocate_ref(Value, types.length)
for var i in 0..values.size {
values(i) = [
kind = ValueKind::ZEROINITIALIZER,
tpe = types(i)
] !Value
}

if is_struct(tpe) {
for var k in 0..tpe.fields.size {
let field = tpe.fields(k)
if field.is_embed {
let new_values = struct_lit_create_value(field.tpe, kwargs, loc, state)
let new_value = [
kind = ValueKind::STRUCT,
values = new_values,
tpe = field.tpe
] !&Value

locals_to_insert_value(new_value, state)

values(k) = @new_value
}
}
}

for var i in 0..vector::length(kwargs) {
let kwarg = kwargs(i)
let name = typechecking::last_ident_to_str((@kwarg).value.named_arg.name)
let value = walk_expression((@kwarg).value.named_arg.value, state)

for var j in 0..tpe.fields.size {
let field = tpe.fields(j)
if field.name == name {
values(j) = convert_to(kwarg, value, field.tpe, state)
if typechecking::is_ref(field.tpe) {
increase_ref_count_of_value(values(j), loc, state)
} else if typechecking::has_copy_constructor(field.tpe) {
let ret = state.alloca(values(j).tpe, loc, no_yield_capture = true)
insert_copy_constructor(ret, values(j), loc, state)
values(j) = state.load(values(j).tpe, ret, loc)
}
break
}
}
}
return values
}

def walk_StructLit(node: &parser::Node, state: &State) -> Value {
Expand All @@ -2367,23 +2492,8 @@ def walk_StructLit(node: &parser::Node, state: &State) -> Value {
} else if tpe.kind == typechecking::TypeKind::UNION {
value = walk_StructLitUnion(node, state)
} else {
var types = vector::make(type &typechecking::Type)
if tpe.kind == typechecking::TypeKind::TUPLE {
types = tpe.return_t
} else {
for var field in @tpe.fields {
types.push(field.tpe)
}
}

let values = allocate_ref(Value, types.length)
for var i in 0..values.size {
values(i) = [
kind = ValueKind::ZEROINITIALIZER,
tpe = types(i)
] !Value
}
for var i in 0..vector::length(args) {
// args no longer valid
/*for var i in 0..vector::length(args) {
let arg = args(i)
let arg_tpe = types(i)
let value = walk_expression(arg, state)
Expand All @@ -2395,27 +2505,10 @@ def walk_StructLit(node: &parser::Node, state: &State) -> Value {
insert_copy_constructor(ret, values(i), loc, state)
values(i) = state.load(values(i).tpe, ret, loc)
}
}
for var i in 0..vector::length(kwargs) {
let kwarg = kwargs(i)
let name = typechecking::last_ident_to_str((@kwarg).value.named_arg.name)
let value = walk_expression((@kwarg).value.named_arg.value, state)

for var j in 0..tpe.fields.size {
let field = tpe.fields(j)
if field.name == name {
values(j) = convert_to(kwarg, value, field.tpe, state)
if typechecking::is_ref(field.tpe) {
increase_ref_count_of_value(values(j), loc, state)
} else if typechecking::has_copy_constructor(field.tpe) {
let ret = state.alloca(values(j).tpe, loc, no_yield_capture = true)
insert_copy_constructor(ret, values(j), loc, state)
values(j) = state.load(values(j).tpe, ret, loc)
}
break
}
}
}
}*/

let values = struct_lit_create_value(tpe, kwargs, loc, state)

value = [
kind = ValueKind::STRUCT,
values = values,
Expand Down Expand Up @@ -3987,6 +4080,7 @@ def walk_MemberAccess_gep(node: &parser::Node, tpe: &typechecking::Type,
type Member = struct {
index: int
tpe: &typechecking::Type
is_embed: bool
}

// This list needs to be reversed to find the actual indices
Expand All @@ -4005,11 +4099,14 @@ def resolve_member(vec: &Vector(Member), tpe: &typechecking::Type, name: Str) ->
return true
}
} else {
let found = resolve_member(vec, field.tpe, name)
var tpe = field.tpe
if field.is_embed and is_ref(tpe) { tpe = tpe.tpe }
let found = resolve_member(vec, tpe, name)
if found {
let member = [
index = field.index !int,
tpe = field.tpe
tpe = field.tpe,
is_embed = field.is_embed
] !Member
vec.push(member)
return true
Expand All @@ -4028,7 +4125,6 @@ def walk_MemberAccess_struct(node: &parser::Node, tpe: &typechecking::Type, memb
}

if tpe.kind == typechecking::TypeKind::UNION {

let index = allocate_ref(Value, 2)
index(0) = make_int_value(0)
index(1) = make_int_value(0)
Expand Down Expand Up @@ -4057,8 +4153,17 @@ def walk_MemberAccess_struct(node: &parser::Node, tpe: &typechecking::Type, memb
let index = allocate_ref(Value, 2)
index(0) = make_int_value(0)
index(1) = make_int_value((@member).index)
return walk_MemberAccess_gep(node, tpe, member_type, value, index, state)
let res = walk_MemberAccess_gep(node, tpe, member_type, value, index, state)

if member.is_embed and is_ref(member.tpe) {
let ref = state.load(member.tpe, @res.addr, loc)
let ptr = state.extract_value(pointer(member.tpe.tpe), ref, [1], loc)
return make_address_value(pointer(member.tpe.tpe), ptr, state)
}

return res
}

}

def walk_MemberAccess(node: &parser::Node, state: &State) -> Value {
Expand Down
6 changes: 6 additions & 0 deletions src/debug.pr
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,12 @@ def id_decl_to_json(node: &parser::Node, types: bool) -> &Json {
def id_decl_struct_to_json(node: &parser::Node, types: bool) -> &Json {
let res = json::make_object()
res("kind") = "IdDeclStruct"
if node.value.id_decl_struct.is_embed {
res("is_embed") = true
}
if node.value.id_decl_struct.is_bitfield {
res("bit_size") = node.value.id_decl_struct.bit_size
}
res("ident") = node_to_json(node.value.id_decl_struct.ident, types)
res("tpe") = node_to_json(node.value.id_decl_struct.tpe, types)
return res
Expand Down
25 changes: 19 additions & 6 deletions src/parser.pr
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,7 @@ export type NodeIdDeclStruct = struct {
ident: &Node
tpe: &Node
is_bitfield: bool
is_embed: bool
bit_size: size_t
}

Expand Down Expand Up @@ -1955,6 +1956,7 @@ def parse_id_decl_struct(parse_state: &ParseState) -> &Node {
skip_newline(parse_state)
token = peek(parse_state)

var is_embed = false
var ident: &Node = null
var tpe: &Node = null

Expand All @@ -1963,14 +1965,24 @@ def parse_id_decl_struct(parse_state: &ParseState) -> &Node {
skip_newline(parse_state)
tpe = expect_type(parse_state)
} else {
ident = expect_identifier(parse_state)
skip_newline(parse_state)
expect(parse_state, lexer::TokenType::COLON, "Expected ':'")
skip_newline(parse_state)
tpe = expect_type(parse_state)
if token.tpe == lexer::TokenType::OP_BAND {
is_embed = true
tpe = expect_type(parse_state)
} else {
ident = expect_identifier(parse_state)
token = peek(parse_state)
if token.tpe == lexer::TokenType::COLON {
pop(parse_state)
tpe = expect_type(parse_state)
} else {
tpe = ident
ident = null
is_embed = true
}
}
}

if not ident and not is_bitfield {
if not ident and not is_bitfield and not is_embed {
errors::errort(token, parse_state, "Expected identifier")
}

Expand All @@ -1979,6 +1991,7 @@ def parse_id_decl_struct(parse_state: &ParseState) -> &Node {
ident = ident,
tpe = tpe,
is_bitfield = is_bitfield,
is_embed = is_embed,
bit_size = bit_size
] !NodeIdDeclStruct
node._hash = combine_hashes(node.kind !uint64, is_bitfield !uint64, bit_size, hash(ident), hash(tpe))
Expand Down
Loading

0 comments on commit a1a3dc5

Please sign in to comment.