Skip to content

Commit

Permalink
Add const values to structs
Browse files Browse the repository at this point in the history
  • Loading branch information
Victorious3 committed Apr 21, 2024
1 parent 16daf68 commit b93933f
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 26 deletions.
52 changes: 42 additions & 10 deletions src/compiler.pr
Original file line number Diff line number Diff line change
Expand Up @@ -4081,6 +4081,7 @@ type Member = struct {
index: int
tpe: &typechecking::Type
is_embed: bool
value: &Value
}

// This list needs to be reversed to find the actual indices
Expand Down Expand Up @@ -4113,11 +4114,24 @@ def resolve_member(vec: &Vector(Member), tpe: &typechecking::Type, name: Str) ->
}
}
}
for var field in @tpe.const_fields {
if field.name == name {
let member = [
value = field.value
] !Member
vec.push(member)
return true
}
}

return false
}

def walk_MemberAccess_struct(node: &parser::Node, tpe: &typechecking::Type, member: &Member, value: Value, state: &State) -> Value {
let loc = make_location(node, state)
if member.value {
return @member.value
}

var member_type = member.tpe
if member.tpe.kind == typechecking::TypeKind::BOX {
Expand Down Expand Up @@ -9532,20 +9546,38 @@ def generate_vtable_function(function: &Function, tpe: &typechecking::Type, stat
state.ret(NO_VALUE)
} else {
// Getter
var deref = state.extract_value(pointer(type_entry.tpe.tpe), reference, [1])
var value = state.load(type_entry.tpe.tpe, deref)
let name = function.unmangled
var findex: size_t = 0
var ftpe: &typechecking::Type
for var field in @type_entry.tpe.tpe.fields {
if field.name == name {
findex = field.index
ftpe = field.tpe

var const_field: typechecking::StructMember
var is_const = false
let const_fields = type_entry.tpe.tpe.const_fields
if const_fields {
for var field in @const_fields {
if field.name == name {
is_const = true
const_field = field
break
}
}
}

value = state.extract_value(ftpe, value, [findex !int])
state.ret(value)
if is_const {
state.ret(@const_field.value)
} else {
var deref = state.extract_value(pointer(type_entry.tpe.tpe), reference, [1])
var value = state.load(type_entry.tpe.tpe, deref)
var findex: size_t = 0
var ftpe: &typechecking::Type
for var field in @type_entry.tpe.tpe.fields {
if field.name == name {
findex = field.index
ftpe = field.tpe
}
}

value = state.extract_value(ftpe, value, [findex !int])
state.ret(value)
}
}
}
}
Expand Down
23 changes: 21 additions & 2 deletions src/parser.pr
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,8 @@ export type NodeIdDeclStruct = struct {
is_bitfield: bool
is_embed: bool
bit_size: size_t
is_const: bool
value: &Node
}

export type NodeEnumT = struct {
Expand Down Expand Up @@ -827,6 +829,7 @@ export def offset(node: &Node, changes: &[server::TextDocumentChangeEvent]) {
case NodeKind::ID_DECL_STRUCT
offset(node.value.id_decl_struct.ident, changes)
offset(node.value.id_decl_struct.tpe, changes)
offset(node.value.id_decl_struct.value, changes)
case NodeKind::ID_DECL_ENUM
offset(node.value.id_decl_enum.ident, changes)
offset(node.value.id_decl_enum.value, changes)
Expand Down Expand Up @@ -961,6 +964,7 @@ export def clear(node: &Node) {
case NodeKind::ID_DECL_STRUCT
clear(node.value.id_decl_struct.ident)
clear(node.value.id_decl_struct.tpe)
clear(node.value.id_decl_struct.value)
case NodeKind::ID_DECL_ENUM
clear(node.value.id_decl_enum.ident)
clear(node.value.id_decl_enum.value)
Expand Down Expand Up @@ -1156,6 +1160,8 @@ export def find(node: &Node, line: int, column: int) -> &Node {
if n2 { return n2 }
n2 = find(node.value.id_decl_struct.tpe, line, column)
if n2 { return n2 }
n2 = find(node.value.id_decl_struct.value, line, column)
if n2 { return n2 }
case NodeKind::ID_DECL_ENUM
var n2 = find(node.value.id_decl_enum.ident, line, column)
if n2 { return n2 }
Expand Down Expand Up @@ -1380,6 +1386,7 @@ export def deep_copy_node(node: &Node, clear_svalue: bool = true) -> &Node {
case NodeKind::ID_DECL_STRUCT
copy.value.id_decl_struct.ident = deep_copy_node(node.value.id_decl_struct.ident, clear_svalue)
copy.value.id_decl_struct.tpe = deep_copy_node(node.value.id_decl_struct.tpe, clear_svalue)
copy.value.id_decl_struct.value = deep_copy_node(node.value.id_decl_struct.value, clear_svalue)
case NodeKind::ID_DECL_ENUM
copy.value.id_decl_enum.ident = deep_copy_node(node.value.id_decl_enum.ident, clear_svalue)
copy.value.id_decl_enum.value = deep_copy_node(node.value.id_decl_enum.value, clear_svalue)
Expand Down Expand Up @@ -1957,13 +1964,23 @@ def parse_id_decl_struct(parse_state: &ParseState) -> &Node {
token = peek(parse_state)

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

if token.tpe == lexer::TokenType::COLON {
pop(parse_state)
skip_newline(parse_state)
tpe = expect_type(parse_state)
} else if token.tpe == lexer::TokenType::K_CONST {
pop(parse_state)
is_const = true
ident = expect_identifier(parse_state)
expect(parse_state, lexer::TokenType::COLON, "Expected ':'")
tpe = expect_type(parse_state)
expect(parse_state, lexer::TokenType::OP_ASSIGN, "Expected '='")
value = expect_expression(parse_state)
} else {
if token.tpe == lexer::TokenType::OP_BAND {
is_embed = true
Expand Down Expand Up @@ -1992,9 +2009,11 @@ def parse_id_decl_struct(parse_state: &ParseState) -> &Node {
tpe = tpe,
is_bitfield = is_bitfield,
is_embed = is_embed,
bit_size = bit_size
bit_size = bit_size,
is_const = is_const,
value = value
] !NodeIdDeclStruct
node._hash = combine_hashes(node.kind !uint64, is_bitfield !uint64, bit_size, hash(ident), hash(tpe))
node._hash = combine_hashes(node.kind !uint64, is_bitfield !uint64, bit_size, is_embed !uint64, hash(ident), hash(tpe), hash(value))
}

parse_t_term(parse_state)
Expand Down
2 changes: 1 addition & 1 deletion src/serialize.pr
Original file line number Diff line number Diff line change
Expand Up @@ -533,7 +533,7 @@ def deserialize_type(deserialize: &Deserialize, fp: File, tpe: &typechecking::Ty
field_types.push(type_member)
tpe.field_types = field_types
} else {
typechecking::make_struct_type(fields, tpe)
typechecking::make_struct_type(fields, null, tpe)
}
tpe.size = size
tpe.align = align
Expand Down
55 changes: 42 additions & 13 deletions src/typechecking.pr
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,10 @@ export type StructMember = struct {
is_bitfield: bool
bit_size: size_t
bit_offset: size_t

is_embed: bool
is_const: bool
value: &compiler::Value
}

export type StructuralTypeMember = struct {
Expand Down Expand Up @@ -142,6 +145,8 @@ export type Type = struct {
packed: bool
// Fields for struct, array of StructMember
fields: &[StructMember]
// Constants
const_fields: &[StructMember]
// Vector of TypeMember
field_types: &Vector(TypeMember)
// Function and Tuple
Expand Down Expand Up @@ -1285,6 +1290,11 @@ def has_function(entry: &TypeEntry, intf: &Type, mb: StructuralTypeMember, modul
for var field in @tpe.fields {
if field.name == mb.name and equals(mb.return_t(0), field.tpe) { return true }
}
if tpe.const_fields {
for var field in @tpe.const_fields {
if field.name == mb.name and equals(mb.return_t(0), field.tpe) { return true }
}
}
}
}

Expand Down Expand Up @@ -2242,7 +2252,7 @@ export def make_stub_type(ident: &parser::Node, state: &State, prefix: bool = tr
return tpe
}

export def make_union_type(fields: &[StructMember], current_type: &Type = null) -> &Type {
export def make_union_type(fields: &[StructMember], const_fields: &[StructMember], current_type: &Type = null) -> &Type {
let tpe = make_type_raw(TypeKind::UNION) if not current_type else current_type
let field_types = vector::make(TypeMember)

Expand Down Expand Up @@ -2271,6 +2281,7 @@ export def make_union_type(fields: &[StructMember], current_type: &Type = null)
tpe.size = size
tpe.align = align
tpe.fields = fields
tpe.const_fields = const_fields if const_fields else allocate_ref(StructMember, 0)
tpe.field_types = field_types

return tpe
Expand All @@ -2291,7 +2302,7 @@ export def make_tuple_type(types: &Vector(&Type)) -> &Type {
return tpe
}

export def make_struct_type(fields: &[StructMember], current_type: &Type = null) -> &Type {
export def make_struct_type(fields: &[StructMember], const_fields: &[StructMember] = null, current_type: &Type = null) -> &Type {
let struct_tpe = make_type_raw(TypeKind::STRUCT) if not current_type else current_type
let field_types = vector::make(TypeMember)

Expand Down Expand Up @@ -2388,6 +2399,7 @@ export def make_struct_type(fields: &[StructMember], current_type: &Type = null)
struct_tpe.size = offset
struct_tpe.align = align
struct_tpe.fields = fields
struct_tpe.const_fields = const_fields if const_fields else allocate_ref(StructMember, 0)
struct_tpe.field_types = field_types

return struct_tpe
Expand Down Expand Up @@ -2646,7 +2658,9 @@ export def do_type_lookup(node: &parser::Node, state: &State, current_type: &Typ
} else if node.kind == parser::NodeKind::STRUCT_T or node.kind == parser::NodeKind::UNION_T {

let length = vector::length(node.value.body)
let fields = allocate_ref(StructMember, length)
let fields = vector::make(StructMember)
let const_fields = vector::make(StructMember)

for var i in 0..length {
let field = node.value.body(i)
if not field { continue }
Expand All @@ -2658,6 +2672,8 @@ export def do_type_lookup(node: &parser::Node, state: &State, current_type: &Typ
var is_bitfield = false
var is_embed = field.value.id_decl_struct.is_embed
var bit_size = 0 !size_t
var is_const = field.value.id_decl_struct.is_const
var value: &compiler::Value

var field_type: &Type = null
if not is_embed and current_type and current_type.kind != TypeKind::STUB { field_type = current_type.fields(i).tpe }
Expand All @@ -2675,26 +2691,35 @@ export def do_type_lookup(node: &parser::Node, state: &State, current_type: &Typ
is_bitfield = true
bit_size = field.value.id_decl_struct.bit_size
}
if is_const {
// Load value for const
value = consteval::expr(field.value.id_decl_struct.value, state)
}
}
} else if (@field).kind == parser::NodeKind::STRUCT_T or
(@field).kind == parser::NodeKind::UNION_T {
field_tpe = type_lookup(field, state, field_type, false, cache)
}

fields(i) = [
let member = [
node = field,
line = line,
name = name,
tpe = field_tpe,
is_bitfield = is_bitfield,
is_embed = is_embed,
bit_size = bit_size
bit_size = bit_size,
is_const = is_const,
value = value
] !StructMember

if is_const { const_fields.push(member) }
else { fields.push(member) }
}

var tpe = (make_struct_type(fields, current_type)
var tpe = (make_struct_type(fields.to_array(), const_fields.to_array(), current_type)
if node.kind == parser::NodeKind::STRUCT_T
else make_union_type(fields, current_type))
else make_union_type(fields.to_array(), const_fields.to_array(), current_type))

tpe.line = node.loc.line
tpe.type_name = make_unique_name("<anonymous>", state)
Expand Down Expand Up @@ -3081,7 +3106,7 @@ export def do_type_lookup(node: &parser::Node, state: &State, current_type: &Typ
tpe.size = (ceil(offset / biggest_type.align !double) * biggest_type.align) !int
tpe.align = util::lcm(align !int, biggest_type.align !int)

tpe._tpe = make_union_type(fields, tpe._tpe)
tpe._tpe = make_union_type(fields, null, tpe._tpe)
tpe.variants = set::make(variants)
tpe.line = node.loc.line

Expand Down Expand Up @@ -5608,9 +5633,8 @@ export def lookup_struct_member(member: StructMember, resolved: &SSet = null) {
}
}

def resolve_member(fields: &[StructMember], name: String) -> &Type {
for var i in 0..fields.size {
let member = fields(i)
def resolve_member(tpe: &Type, name: String) -> &Type {
for var member in @tpe.fields {
if member.name {
if member.name == name {
lookup_struct_member(member)
Expand All @@ -5621,10 +5645,15 @@ def resolve_member(fields: &[StructMember], name: String) -> &Type {
if member.is_embed and is_ref(member.tpe) {
tpe = member.tpe.tpe
}
let member = resolve_member(tpe.fields, name)
let member = resolve_member(tpe, name)
if member { return member }
}
}
for var member in @tpe.const_fields {
if member.name == name {
return member.tpe
}
}
return null
}

Expand Down Expand Up @@ -5684,7 +5713,7 @@ def walk_MemberAccess_aggregate(node: &parser::Node, ucs: bool, state: &State) -
if (@tpe).kind == TypeKind::STRUCT or (@tpe).kind == TypeKind::UNION {
let name = last_ident_to_str(right)

var rtpe = resolve_member((@tpe).fields, name)
var rtpe = resolve_member(tpe, name)
if not rtpe {
if ucs {
if walk_MemberAccess_ucs(node, state) { return true }
Expand Down

0 comments on commit b93933f

Please sign in to comment.