From d5ef3f6b4a782c5baf3a953425046a77e896db6f Mon Sep 17 00:00:00 2001 From: Brad Lewis <22850972+BradLewis@users.noreply.github.com> Date: Tue, 12 Aug 2025 07:27:53 -0400 Subject: Reapply "Merge pull request #857 from BradLewis/feat/foreign-block-attrs" This reverts commit 111e83166b1932594f51a513507bd9a26555b061. --- src/server/ast.odin | 92 ++++++++++++++++++++++++++++++++++--------- src/server/documentation.odin | 33 ++++++++++++++-- 2 files changed, 104 insertions(+), 21 deletions(-) (limited to 'src/server') diff --git a/src/server/ast.odin b/src/server/ast.odin index dc5c0a9..5c94bc1 100644 --- a/src/server/ast.odin +++ b/src/server/ast.odin @@ -295,12 +295,58 @@ 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: ^[dynamic]^ast.Attribute, foreign_attrs: []^ast.Attribute) { + if len(foreign_attrs) == 0 { + return + } + attr_names := make(map[string]bool) + for attr in attrs { + 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(attrs, new_attr) + } + } + } + } +} + 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,6 +355,8 @@ collect_value_decl :: proc( } comment, _ := get_file_comment(file, value_decl.pos.line) + merge_attributes(&value_decl.attributes, foreign_attrs) + global_expr := GlobalExpr { mutable = value_decl.is_mutable, docs = value_decl.docs, @@ -319,16 +367,8 @@ collect_value_decl :: proc( for attribute in value_decl.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 +378,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 +443,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 +472,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 +508,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 +518,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 +538,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) } -- cgit v1.2.3 From 6bdd9d0e01cc19d0a322520aca79b16532bb866f Mon Sep 17 00:00:00 2001 From: Brad Lewis <22850972+BradLewis@users.noreply.github.com> Date: Tue, 12 Aug 2025 07:33:53 -0400 Subject: Fix issue merging attributes --- src/server/ast.odin | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'src/server') diff --git a/src/server/ast.odin b/src/server/ast.odin index 5c94bc1..28591f0 100644 --- a/src/server/ast.odin +++ b/src/server/ast.odin @@ -308,12 +308,15 @@ unwrap_attr_elem :: proc(elem: ^ast.Expr) -> (^ast.Ident, ^ast.Expr, bool) { return nil, nil, false } -merge_attributes :: proc(attrs: ^[dynamic]^ast.Attribute, foreign_attrs: []^ast.Attribute) { +merge_attributes :: proc(attrs: []^ast.Attribute, foreign_attrs: []^ast.Attribute) -> []^ast.Attribute { if len(foreign_attrs) == 0 { - return + return attrs } - attr_names := make(map[string]bool) + + 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 @@ -333,11 +336,12 @@ merge_attributes :: proc(attrs: ^[dynamic]^ast.Attribute, foreign_attrs: []^ast. elems := make([dynamic]^ast.Expr) append(&elems, elem) new_attr.elems = elems[:] - append(attrs, new_attr) + append(&new_attrs, new_attr) } } } } + return new_attrs[:] } collect_value_decl :: proc( @@ -355,17 +359,17 @@ collect_value_decl :: proc( } comment, _ := get_file_comment(file, value_decl.pos.line) - merge_attributes(&value_decl.attributes, foreign_attrs) + 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, value, ok := unwrap_attr_elem(elem) if !ok { -- cgit v1.2.3