diff options
| author | DanielGavin <danielgavin5@hotmail.com> | 2023-02-25 20:46:54 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-02-25 20:46:54 +0100 |
| commit | e11bb706dfb4eacfe4c339232f3d22083078217f (patch) | |
| tree | 2223f2b82338548b5413e40a892537e4d3248103 | |
| parent | 532f4bf07c5830276dc4fef9ec497bf917adc8d5 (diff) | |
| parent | 5aba6a1d6ddb2998183f407ec502ecf2c08854ca (diff) | |
Merge pull request #172 from DanielGavin/objc-branch
Objc branch
| -rw-r--r-- | src/common/ast.odin | 86 | ||||
| -rw-r--r-- | src/odin/printer/visit.odin | 14 | ||||
| -rw-r--r-- | src/server/analysis.odin | 80 | ||||
| -rw-r--r-- | src/server/collector.odin | 131 | ||||
| -rw-r--r-- | src/server/completion.odin | 12 | ||||
| -rw-r--r-- | src/server/memory_index.odin | 8 | ||||
| -rw-r--r-- | src/server/requests.odin | 6 | ||||
| -rw-r--r-- | src/server/symbol.odin | 13 |
8 files changed, 312 insertions, 38 deletions
diff --git a/src/common/ast.odin b/src/common/ast.odin index 732c736..158882d 100644 --- a/src/common/ast.odin +++ b/src/common/ast.odin @@ -79,6 +79,92 @@ GlobalExpr :: struct { builtin: bool, } +get_attribute_objc_type :: proc(attributes: []^ast.Attribute) -> ^ast.Expr { + for attribute in attributes { + for elem in attribute.elems { + if assign, ok := elem.derived.(^ast.Field_Value); ok { + if ident, ok := assign.field.derived.(^ast.Ident); + ok && ident.name == "objc_type" { + return assign.value + } + } + } + } + + return nil +} + +get_attribute_objc_name :: proc( + attributes: []^ast.Attribute, +) -> ( + string, + bool, +) { + for attribute in attributes { + for elem in attribute.elems { + if assign, ok := elem.derived.(^ast.Field_Value); ok { + if ident, ok := assign.field.derived.(^ast.Ident); + ok && ident.name == "objc_name" { + if lit, ok := assign.value.derived.(^ast.Basic_Lit); + ok && len(lit.tok.text) > 2 { + return lit.tok.text[1:len(lit.tok.text) - 1], true + } + } + + } + } + } + + return "", false +} + +get_attribute_objc_class_name :: proc( + attributes: []^ast.Attribute, +) -> ( + string, + bool, +) { + for attribute in attributes { + for elem in attribute.elems { + if assign, ok := elem.derived.(^ast.Field_Value); ok { + if ident, ok := assign.field.derived.(^ast.Ident); + ok && ident.name == "objc_class" { + if lit, ok := assign.value.derived.(^ast.Basic_Lit); + ok && len(lit.tok.text) > 2 { + return lit.tok.text[1:len(lit.tok.text) - 1], true + } + } + + } + } + } + + return "", false +} + + +get_attribute_objc_is_class_method :: proc( + attributes: []^ast.Attribute, +) -> ( + bool, +) { + for attribute in attributes { + for elem in attribute.elems { + if assign, ok := elem.derived.(^ast.Field_Value); ok { + if ident, ok := assign.field.derived.(^ast.Ident); + ok && ident.name == "objc_is_class_method" { + if field_value, ok := assign.value.derived.(^ast.Ident); + ok && field_value.name == "true" { + return true + } + } + + } + } + } + return false +} + unwrap_pointer :: proc(expr: ^ast.Expr) -> (ast.Ident, bool) { expr := expr for expr != nil { diff --git a/src/odin/printer/visit.odin b/src/odin/printer/visit.odin index 93b8cfb..92e378a 100644 --- a/src/odin/printer/visit.odin +++ b/src/odin/printer/visit.odin @@ -1822,9 +1822,17 @@ visit_expr :: proc( switch v.inlining { case .None: case .Inline: - document = cons(document, text("#force_inline"), break_with_no_newline()) + document = cons( + document, + text("#force_inline"), + break_with_no_newline(), + ) case .No_Inline: - document = cons(document, text("#force_no_inline"), break_with_no_newline()) + document = cons( + document, + text("#force_no_inline"), + break_with_no_newline(), + ) } document = cons(document, visit_expr(p, v.expr), text("(")) @@ -2681,6 +2689,8 @@ get_node_length :: proc(node: ^ast.Node) -> int { return 0 case ^ast.Paren_Expr: return 1 + get_node_length(v.expr) + 1 + case ^ast.Pointer_Type: + return 1 + get_node_length(v.elem) case ^ast.Selector_Expr: return( get_node_length(v.expr) + diff --git a/src/server/analysis.odin b/src/server/analysis.odin index 142ee38..eb24321 100644 --- a/src/server/analysis.odin +++ b/src/server/analysis.odin @@ -866,8 +866,10 @@ resolve_function_overload :: proc( candidates := make([dynamic]Symbol, context.temp_allocator) for arg_expr in group.args { - next_fn: if f, ok := resolve_type_expression(ast_context, arg_expr); - ok { + next_fn: if f, ok := internal_resolve_type_expression( + ast_context, + arg_expr, + ); ok { if call_expr == nil || len(call_expr.args) == 0 { append(&candidates, f) break next_fn @@ -1308,7 +1310,25 @@ internal_resolve_type_expression :: proc( case ^Implicit_Selector_Expr: return Symbol{}, false case ^Selector_Call_Expr: - return internal_resolve_type_expression(ast_context, v.expr) + if selector, ok := internal_resolve_type_expression( + ast_context, + v.expr, + ); ok { + ast_context.use_locals = false + ast_context.current_package = selector.pkg + + #partial switch s in selector.value { + case SymbolProcedureValue: + if len(s.return_types) == 1 { + return internal_resolve_type_expression( + ast_context, + s.return_types[0].type, + ) + } + } + + return selector, true + } case ^Selector_Expr: if selector, ok := internal_resolve_type_expression( ast_context, @@ -1410,14 +1430,9 @@ internal_resolve_type_expression :: proc( return Symbol{}, false } } - } else { - return Symbol{}, false } case: log.warnf("default node kind, internal_resolve_type_expression: %T", v) - if v == nil { - return {}, false - } } return Symbol{}, false @@ -1956,6 +1971,37 @@ expand_struct_usings :: proc( } } + if .ObjC in symbol.flags { + pkg := indexer.index.collection.packages[symbol.pkg] + + if obj_struct, ok := pkg.objc_structs[symbol.name]; ok { + for function, i in obj_struct.functions { + base := new_type(ast.Ident, {}, {}, context.temp_allocator) + base.name = obj_struct.pkg + + field := new_type(ast.Ident, {}, {}, context.temp_allocator) + field.name = function.physical_name + + selector := new_type( + ast.Selector_Expr, + {}, + {}, + context.temp_allocator, + ) + + selector.field = field + selector.expr = base + + append(&names, function.logical_name) + append(&types, selector) + append(&ranges, obj_struct.ranges[i]) + } + + } + + //fmt.println(symbol.name) + } + return {names = names[:], types = types[:], ranges = ranges[:]} } @@ -2024,7 +2070,7 @@ resolve_symbol_return :: proc( } //expand the types and names from the using - can't be done while indexing without complicating everything(this also saves memory) - if len(v.usings) > 0 { + if len(v.usings) > 0 || .ObjC in symbol.flags { expanded := symbol expanded.value = expand_struct_usings(ast_context, symbol, v) return expanded, true @@ -2444,6 +2490,13 @@ make_symbol_procedure_from_ast :: proc( generic = v.generic, } + if _, ok := common.get_attribute_objc_name(attributes); ok { + symbol.flags |= {.ObjC} + if common.get_attribute_objc_is_class_method(attributes) { + symbol.flags |= {.ObjCIsClassMethod} + } + } + return symbol } @@ -2734,12 +2787,19 @@ make_symbol_struct_from_ast :: proc( usings = usings, } + if _, ok := common.get_attribute_objc_class_name(attributes); ok { + symbol.flags |= {.ObjC} + if common.get_attribute_objc_is_class_method(attributes) { + symbol.flags |= {.ObjCIsClassMethod} + } + } + if v.poly_params != nil { resolve_poly_struct(ast_context, v.poly_params, &symbol) } //TODO change the expand to not double copy the array, but just pass the dynamic arrays - if len(usings) > 0 { + if len(usings) > 0 || .ObjC in symbol.flags { symbol.value = expand_struct_usings( ast_context, symbol, diff --git a/src/server/collector.odin b/src/server/collector.odin index b065a9e..89ec7f6 100644 --- a/src/server/collector.odin +++ b/src/server/collector.odin @@ -15,10 +15,26 @@ import "shared:common" SymbolCollection :: struct { allocator: mem.Allocator, config: ^common.Config, - packages: map[string]map[string]Symbol, + packages: map[string]SymbolPackage, unique_strings: map[string]string, //store all our strings as unique strings and reference them to save memory. } +ObjcFunction :: struct { + physical_name: string, + logical_name: string, +} + +ObjcStruct :: struct { + functions: [dynamic]ObjcFunction, + pkg: string, + ranges: [dynamic]common.Range, +} + +SymbolPackage :: struct { + symbols: map[string]Symbol, + objc_structs: map[string]ObjcStruct, //mapping from struct name to function +} + get_index_unique_string :: proc { get_index_unique_string_collection, get_index_unique_string_collection_raw, @@ -56,7 +72,7 @@ make_symbol_collection :: proc( SymbolCollection{ allocator = allocator, config = config, - packages = make(map[string]map[string]Symbol, 16, allocator), + packages = make(map[string]SymbolPackage, 16, allocator), unique_strings = make(map[string]string, 16, allocator), } \ ) @@ -64,7 +80,7 @@ make_symbol_collection :: proc( delete_symbol_collection :: proc(collection: SymbolCollection) { for k, v in collection.packages { - for k2, v2 in v { + for k2, v2 in v.symbols { free_symbol(v2, collection.allocator) } } @@ -74,7 +90,7 @@ delete_symbol_collection :: proc(collection: SymbolCollection) { } for k, v in collection.packages { - delete(v) + delete(v.symbols) } delete(collection.packages) @@ -87,6 +103,7 @@ collect_procedure_fields :: proc( arg_list: ^ast.Field_List, return_list: ^ast.Field_List, package_map: map[string]string, + attributes: []^ast.Attribute, ) -> SymbolProcedureValue { returns := make([dynamic]^ast.Field, 0, collection.allocator) args := make([dynamic]^ast.Field, 0, collection.allocator) @@ -119,7 +136,16 @@ collect_procedure_fields :: proc( return_types = returns[:], arg_types = args[:], generic = proc_type.generic, + /* + objc_name = common.get_attribute_objc_name( + attributes, + ) or_else "", + objc_is_class_method = common.get_attribute_objc_is_class_method( + attributes, + ) or_else false, + */ } + return value } @@ -407,6 +433,64 @@ collect_generic :: proc( return value } +collect_objc :: proc( + collection: ^SymbolCollection, + attributes: []^ast.Attribute, + symbol: Symbol, +) { + pkg := &collection.packages[symbol.pkg] + + if value, ok := symbol.value.(SymbolProcedureValue); ok { + objc_name, found_objc_name := common.get_attribute_objc_name( + attributes, + ) + + if objc_type := common.get_attribute_objc_type(attributes); + objc_type != nil && found_objc_name { + + if struct_ident, ok := objc_type.derived.(^ast.Ident); ok { + struct_name := get_index_unique_string_collection( + collection, + struct_ident.name, + ) + + objc_struct := &pkg.objc_structs[struct_name] + + if objc_struct == nil { + pkg.objc_structs[struct_name] = {} + objc_struct = &pkg.objc_structs[struct_name] + objc_struct.functions = make( + [dynamic]ObjcFunction, + 0, + 10, + collection.allocator, + ) + objc_struct.ranges = make( + [dynamic]common.Range, + 0, + 10, + collection.allocator, + ) + objc_struct.pkg = symbol.pkg + } + + append(&objc_struct.ranges, symbol.range) + + append( + &objc_struct.functions, + ObjcFunction{ + logical_name = get_index_unique_string_collection( + collection, + objc_name, + ), + physical_name = symbol.name, + }, + ) + } + } + } +} + collect_symbols :: proc( collection: ^SymbolCollection, file: ast.File, @@ -456,8 +540,17 @@ collect_symbols :: proc( v.type.params, v.type.results, package_map, + expr.attributes, ) } + + if _, is_objc := common.get_attribute_objc_name(expr.attributes); + is_objc { + symbol.flags |= {.ObjC} + if common.get_attribute_objc_is_class_method(expr.attributes) { + symbol.flags |= {.ObjCIsClassMethod} + } + } case ^ast.Proc_Type: token = v^ token_type = .Function @@ -467,6 +560,7 @@ collect_symbols :: proc( v.params, v.results, package_map, + expr.attributes, ) case ^ast.Proc_Group: token = v^ @@ -488,6 +582,15 @@ collect_symbols :: proc( file, ) symbol.signature = "struct" + + if _, is_objc := common.get_attribute_objc_class_name( + expr.attributes, + ); is_objc { + symbol.flags |= {.ObjC} + if common.get_attribute_objc_is_class_method(expr.attributes) { + symbol.flags |= {.ObjCIsClassMethod} + } + } case ^ast.Enum_Type: token = v^ token_type = .Enum @@ -611,20 +714,26 @@ collect_symbols :: proc( symbol.uri = get_index_unique_string(collection, uri) - pkg: ^map[string]Symbol + pkg: ^SymbolPackage ok: bool if pkg, ok = &collection.packages[symbol.pkg]; !ok { - collection.packages[symbol.pkg] = make( - map[string]Symbol, - 100, + collection.packages[symbol.pkg] = {} + pkg = &collection.packages[symbol.pkg] + pkg.symbols = make(map[string]Symbol, 100, collection.allocator) + pkg.objc_structs = make( + map[string]ObjcStruct, + 5, collection.allocator, ) - pkg = &collection.packages[symbol.pkg] } - if v, ok := pkg[symbol.name]; !ok || v.name == "" { - pkg[symbol.name] = symbol + if .ObjC in symbol.flags { + collect_objc(collection, expr.attributes, symbol) + } + + if v, ok := pkg.symbols[symbol.name]; !ok || v.name == "" { + pkg.symbols[symbol.name] = symbol } else { free_symbol(symbol, collection.allocator) } diff --git a/src/server/completion.odin b/src/server/completion.odin index 7c3b397..d81aac7 100644 --- a/src/server/completion.odin +++ b/src/server/completion.odin @@ -519,10 +519,20 @@ get_selector_completion :: proc( } } - if position_context.arrow && symbol.type != .Function { + if position_context.arrow { + if symbol.type != .Function { + continue + } + if .ObjCIsClassMethod in symbol.flags { + assert(.ObjC in symbol.flags) + continue + } + } + if !position_context.arrow && .ObjC in symbol.flags { continue } + item := CompletionItem { label = name, kind = .Field, diff --git a/src/server/memory_index.odin b/src/server/memory_index.odin index a211b94..d803a24 100644 --- a/src/server/memory_index.odin +++ b/src/server/memory_index.odin @@ -36,9 +36,9 @@ memory_index_lookup :: proc( } if _pkg, ok := &index.collection.packages[pkg]; ok { - index.last_package = _pkg + index.last_package = &_pkg.symbols index.last_package_name = pkg - return _pkg[name] + return _pkg.symbols[name] } else { index.last_package = nil index.last_package_name = "" @@ -63,9 +63,9 @@ memory_index_fuzzy_search :: proc( for pkg in pkgs { if pkg, ok := index.collection.packages[pkg]; ok { - for _, symbol in pkg { + for _, symbol in pkg.symbols { if score, ok := common.fuzzy_match(fuzzy_matcher, symbol.name); - ok == 1 { + ok == 1 { result := FuzzyResult { symbol = symbol, score = score, diff --git a/src/server/requests.odin b/src/server/requests.odin index 9630c0b..b9ac631 100644 --- a/src/server/requests.odin +++ b/src/server/requests.odin @@ -907,7 +907,7 @@ notification_did_change :: proc( writer: ^Writer, ) -> common.Error { params_object, ok := params.(json.Object) - + if !ok { return .ParseError } @@ -1023,10 +1023,10 @@ notification_did_save :: proc( corrected_uri := common.create_uri(fullpath, context.temp_allocator) for k, v in &indexer.index.collection.packages { - for k2, v2 in &v { + for k2, v2 in &v.symbols { if corrected_uri.uri == v2.uri { free_symbol(v2, indexer.index.collection.allocator) - v[k2] = {} + v.symbols[k2] = {} } } } diff --git a/src/server/symbol.odin b/src/server/symbol.odin index 8f7a081..ce3509d 100644 --- a/src/server/symbol.odin +++ b/src/server/symbol.odin @@ -17,13 +17,11 @@ SymbolAndNode :: struct { } SymbolStructValue :: struct { - names: []string, - ranges: []common.Range, - types: []^ast.Expr, - usings: map[string]bool, - poly: ^ast.Field_List, - objc_name: string, - objc_is_class_method: bool, + names: []string, + ranges: []common.Range, + types: []^ast.Expr, + usings: map[string]bool, + poly: ^ast.Field_List, } SymbolPackageValue :: struct {} @@ -133,6 +131,7 @@ SymbolFlag :: enum { Variable, //Symbols that are variable, this means their value decl was mutable Local, ObjC, + ObjCIsClassMethod, // should be set true only when ObjC is enabled } SymbolFlags :: bit_set[SymbolFlag] |