aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBradley Lewis <22850972+BradLewis@users.noreply.github.com>2025-08-12 07:49:26 -0400
committerGitHub <noreply@github.com>2025-08-12 07:49:26 -0400
commit35a6216537c8aaa44c68df6c37b3f54cf37c2d29 (patch)
tree87e2529b7eb50d97a45a996179ee7d083f66ac04 /src
parentb07233c04cef18b283ea88f0abc8d4fac51f7e84 (diff)
parent6bdd9d0e01cc19d0a322520aca79b16532bb866f (diff)
Merge pull request #860 from BradLewis/fix/foreign-blocks
Fix issue with foreign block attributes
Diffstat (limited to 'src')
-rw-r--r--src/server/ast.odin100
-rw-r--r--src/server/documentation.odin33
2 files changed, 110 insertions, 23 deletions
diff --git a/src/server/ast.odin b/src/server/ast.odin
index dc5c0a9..28591f0 100644
--- a/src/server/ast.odin
+++ b/src/server/ast.odin
@@ -295,12 +295,62 @@ is_expr_basic_lit :: proc(expr: ^ast.Expr) -> bool {
return ok
}
+unwrap_attr_elem :: proc(elem: ^ast.Expr) -> (^ast.Ident, ^ast.Expr, bool) {
+ #partial switch v in elem.derived {
+ case ^ast.Field_Value:
+ if ident, ok := v.field.derived.(^ast.Ident); ok {
+ return ident, v.value, true
+ }
+ case ^ast.Ident:
+ return v, nil, true
+ }
+
+ return nil, nil, false
+}
+
+merge_attributes :: proc(attrs: []^ast.Attribute, foreign_attrs: []^ast.Attribute) -> []^ast.Attribute {
+ if len(foreign_attrs) == 0 {
+ return attrs
+ }
+
+ new_attrs := make([dynamic]^ast.Attribute, context.temp_allocator)
+ attr_names := make(map[string]bool, context.temp_allocator)
+ for attr in attrs {
+ append(&new_attrs, attr)
+ for elem in attr.elems {
+ if ident, _, ok := unwrap_attr_elem(elem); ok {
+ attr_names[ident.name] = true
+ }
+ }
+ }
+
+ for attr in foreign_attrs {
+ for elem in attr.elems {
+ if ident, _, ok := unwrap_attr_elem(elem); ok {
+ name_to_check := ident.name
+ if ident.name == "link_prefix" || ident.name == "link_suffix" {
+ name_to_check = "link_name"
+ }
+ if _, ok := attr_names[name_to_check]; !ok {
+ new_attr := new_type(ast.Attribute, attr.pos, attr.end, context.temp_allocator)
+ elems := make([dynamic]^ast.Expr)
+ append(&elems, elem)
+ new_attr.elems = elems[:]
+ append(&new_attrs, new_attr)
+ }
+ }
+ }
+ }
+ return new_attrs[:]
+}
+
collect_value_decl :: proc(
exprs: ^[dynamic]GlobalExpr,
file: ast.File,
file_tags: parser.File_Tags,
stmt: ^ast.Node,
skip_private: bool,
+ foreign_attrs: []^ast.Attribute,
) {
value_decl, is_value_decl := stmt.derived.(^ast.Value_Decl)
@@ -309,26 +359,20 @@ collect_value_decl :: proc(
}
comment, _ := get_file_comment(file, value_decl.pos.line)
+ attributes := merge_attributes(value_decl.attributes[:], foreign_attrs)
+
global_expr := GlobalExpr {
mutable = value_decl.is_mutable,
docs = value_decl.docs,
comment = comment,
- attributes = value_decl.attributes[:],
+ attributes = attributes,
private = file_tags.private,
}
- for attribute in value_decl.attributes {
+ for attribute in attributes {
for elem in attribute.elems {
- ident: ^ast.Ident
- value: ast.Any_Node
-
- #partial switch v in elem.derived {
- case ^ast.Field_Value:
- ident = v.field.derived.(^ast.Ident) or_continue
- value = v.value.derived
- case ^ast.Ident:
- ident = v
- case:
+ ident, value, ok := unwrap_attr_elem(elem)
+ if !ok {
continue
}
@@ -338,7 +382,9 @@ collect_value_decl :: proc(
case "builtin":
global_expr.builtin = true
case "private":
- if val, ok := value.(^ast.Basic_Lit); ok {
+ if value == nil {
+ global_expr.private = .Package
+ } else if val, ok := value.derived.(^ast.Basic_Lit); ok {
switch val.tok.text {
case "\"file\"":
global_expr.private = .File
@@ -401,11 +447,18 @@ collect_when_stmt :: proc(
if foreign_block, ok := foreign_decl.body.derived.(^ast.Block_Stmt); ok {
for foreign_stmt in foreign_block.stmts {
- collect_value_decl(exprs, file, file_tags, foreign_stmt, skip_private)
+ collect_value_decl(
+ exprs,
+ file,
+ file_tags,
+ foreign_stmt,
+ skip_private,
+ foreign_decl.attributes[:],
+ )
}
}
} else {
- collect_value_decl(exprs, file, file_tags, stmt, skip_private)
+ collect_value_decl(exprs, file, file_tags, stmt, skip_private, {})
}
}
}
@@ -423,12 +476,19 @@ collect_when_stmt :: proc(
if foreign_decl.body != nil {
if foreign_block, ok := foreign_decl.body.derived.(^ast.Block_Stmt); ok {
for foreign_stmt in foreign_block.stmts {
- collect_value_decl(exprs, file, file_tags, foreign_stmt, skip_private)
+ collect_value_decl(
+ exprs,
+ file,
+ file_tags,
+ foreign_stmt,
+ skip_private,
+ foreign_decl.attributes[:],
+ )
}
}
}
} else {
- collect_value_decl(exprs, file, file_tags, stmt, skip_private)
+ collect_value_decl(exprs, file, file_tags, stmt, skip_private, {})
}
}
}
@@ -452,7 +512,7 @@ collect_globals :: proc(file: ast.File, skip_private := false) -> []GlobalExpr {
for decl in file.decls {
if value_decl, ok := decl.derived.(^ast.Value_Decl); ok {
- collect_value_decl(&exprs, file, file_tags, decl, skip_private)
+ collect_value_decl(&exprs, file, file_tags, decl, skip_private, {})
} else if when_decl, ok := decl.derived.(^ast.When_Stmt); ok {
collect_when_stmt(&exprs, file, file_tags, when_decl, skip_private)
} else if foreign_decl, ok := decl.derived.(^ast.Foreign_Block_Decl); ok {
@@ -462,7 +522,7 @@ collect_globals :: proc(file: ast.File, skip_private := false) -> []GlobalExpr {
if block, ok := foreign_decl.body.derived.(^ast.Block_Stmt); ok {
for stmt in block.stmts {
- collect_value_decl(&exprs, file, file_tags, stmt, skip_private)
+ collect_value_decl(&exprs, file, file_tags, stmt, skip_private, foreign_decl.attributes[:])
}
}
}
@@ -482,7 +542,7 @@ get_doc :: proc(node: ^ast.Expr, comment: ^ast.Comment_Group, allocator: mem.All
// The odin parser currently incorrectly adds comments that are more than a line above
// the symbol as a doc comment. We do a quick check here to handle that specific case.
- if node != nil && comment.list[len(comment.list)-1].pos.line < node.pos.line-1 {
+ if node != nil && comment.list[len(comment.list) - 1].pos.line < node.pos.line - 1 {
return ""
}
diff --git a/src/server/documentation.odin b/src/server/documentation.odin
index 3d752eb..cdc2112 100644
--- a/src/server/documentation.odin
+++ b/src/server/documentation.odin
@@ -471,6 +471,18 @@ write_procedure_symbol_signature :: proc(sb: ^strings.Builder, value: SymbolProc
strings.write_string(sb, "proc")
if s, ok := value.calling_convention.(string); ok && detailed_signature {
fmt.sbprintf(sb, " %s ", s)
+ } else if len(value.attributes) > 0 {
+ for attr in value.attributes {
+ for elem in attr.elems {
+ if ident, value, ok := unwrap_attr_elem(elem); ok {
+ if ident.name == "default_calling_convention" {
+ strings.write_string(sb, " ")
+ build_string_node(value, sb, false)
+ strings.write_string(sb, " ")
+ }
+ }
+ }
+ }
}
write_proc_param_list_and_return(sb, value)
if detailed_signature {
@@ -677,12 +689,27 @@ write_symbol_attributes :: proc(sb: ^strings.Builder, symbol: Symbol) {
strings.write_string(sb, "@()\n")
continue
}
+ if len(attribute.elems) == 1 {
+ if ident, _, ok := unwrap_attr_elem(attribute.elems[0]); ok {
+ if ident.name == "default_calling_convention" {
+ continue
+ }
+ }
+ }
strings.write_string(sb, "@(")
for elem, i in attribute.elems {
+ if ident, value, ok := unwrap_attr_elem(elem); ok {
+ if ident.name == "default_calling_convention" {
+ continue
+ }
+
+ if value != nil {
+ build_string_node(ident, sb, false)
+ strings.write_string(sb, "=")
+ build_string_node(value, sb, false)
+ }
+ }
if directive, ok := elem.derived.(^ast.Field_Value); ok {
- build_string_node(directive.field, sb, false)
- strings.write_string(sb, "=")
- build_string_node(directive.value, sb, false)
} else {
build_string_node(elem, sb, false)
}