diff options
| author | Brad Lewis <22850972+BradLewis@users.noreply.github.com> | 2025-08-11 21:30:51 -0400 |
|---|---|---|
| committer | Brad Lewis <22850972+BradLewis@users.noreply.github.com> | 2025-08-11 21:30:51 -0400 |
| commit | b06bdfc06254448bf3b6a3338d4d3d07454691e1 (patch) | |
| tree | cb88a0fe325dc257a22526ae54114dff94e5e324 /src/server | |
| parent | 848d46e939d91c9b5067d2f5b3cc034f20b20612 (diff) | |
Pass foreign block attributes to the body elements
Diffstat (limited to 'src/server')
| -rw-r--r-- | src/server/ast.odin | 92 | ||||
| -rw-r--r-- | src/server/documentation.odin | 33 |
2 files changed, 104 insertions, 21 deletions
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) } |