diff options
| author | DanielGavin <danielgavin5@hotmail.com> | 2022-11-01 21:42:55 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-11-01 21:42:55 +0100 |
| commit | a62ef88da1f0b069068f9218d9136001726b7007 (patch) | |
| tree | 0c372c0aa4a889f136b7768820d176c976168f0a | |
| parent | b7f489b4215b922a40fa88417e1ed777a2690a49 (diff) | |
Try to use recursion map on pointers to prevent stackoverflow crashes (#160)
* use recursion map on pointers to prevent stack overflow crashes
* improve odinfmt on if statements
* Add support for matrix types
* Add new config to disable the `core:odin/parser` errors
* semantic token is now treating variable procedures and non-mutable the same
32 files changed, 1000 insertions, 431 deletions
@@ -10,4 +10,5 @@ *.exp
*.sqlite
*.suo
+*node_modules
@@ -7,7 +7,7 @@ then #BUG in odin test, it makes the executable with the same name as a folder and gets confused. cd tests - odin test ../tests -collection:shared=../src -opt:2 + odin test ../tests -collection:shared=../src -o:speed if ([ $? -ne 0 ]) then diff --git a/editors/vscode/package.json b/editors/vscode/package.json index a17b6a6..cf4fb6d 100644 --- a/editors/vscode/package.json +++ b/editors/vscode/package.json @@ -7,7 +7,7 @@ "type": "git", "url": "git://github.com/DanielGavin/ols.git" }, - "version": "0.1.4", + "version": "0.1.6", "engines": { "vscode": "^1.65.0" }, diff --git a/editors/vscode/syntaxes/odin.tmLanguage.json b/editors/vscode/syntaxes/odin.tmLanguage.json index d155e2d..90c5bd8 100644 --- a/editors/vscode/syntaxes/odin.tmLanguage.json +++ b/editors/vscode/syntaxes/odin.tmLanguage.json @@ -90,7 +90,7 @@ }, { "name": "keyword.control.odin", - "match": "\\b(if|else|or_else|when|for|in|defer|switch|return|or_return)\\b" + "match": "\\b(if|else|or_else|when|for|in|not_in|defer|switch|return|or_return)\\b" }, { "name": "keyword.control.odin", @@ -126,7 +126,7 @@ }, { "name": "storage.type.odin", - "match": "\\b(struct|enum|union|map|set|bit_set|typeid)\\b" + "match": "\\b(struct|enum|union|map|set|bit_set|typeid|matrix)\\b" }, { "name": "keyword.function.odin", @@ -267,7 +267,7 @@ }, { "name": "support.type.odin", - "match": "\\b((f16|f32|f64)|(complex32|complex64|complex128))\\b" + "match": "\\b((f16|f32|f64)|(complex32|complex64|complex128)|(quaternion64|quaternion128|quaternion256))\\b" }, { "name": "support.type.odin", @@ -1,16 +1,13 @@ { "collections": [ { - "name": "core", - "path": "C:\\Users\\danie\\OneDrive\\Desktop\\Computer_Science\\Odin\\core" - }, - { "name": "shared", "path": "src" } ], "enable_document_symbols": true, "enable_semantic_tokens": true, - "enable_hover": true, - "enable_snippets": true + "enable_snippets": true, + "enable_references": true, + "verbose": false } diff --git a/src/common/ast.odin b/src/common/ast.odin index 44bd643..732c736 100644 --- a/src/common/ast.odin +++ b/src/common/ast.odin @@ -8,6 +8,7 @@ import "core:strings" import path "core:path/slashpath" keyword_map: map[string]bool = { + "typeid" = true, "int" = true, "uint" = true, "string" = true, @@ -938,7 +939,7 @@ build_string_node :: proc( } } case ^Typeid_Type: - strings.write_string(builder, "$") + strings.write_string(builder, "typeid") build_string(n.specialization, builder, remove_pointers) case ^Helper_Type: build_string(n.type, builder, remove_pointers) @@ -1002,7 +1003,7 @@ repeat :: proc( count: int, allocator := context.allocator, ) -> string { - if count == 0 { + if count <= 0 { return "" } return strings.repeat(value, count, allocator) diff --git a/src/common/config.odin b/src/common/config.odin index 397545a..9c8e678 100644 --- a/src/common/config.odin +++ b/src/common/config.odin @@ -19,6 +19,7 @@ Config :: struct { enable_rename: bool, enable_std_references: bool, enable_import_fixer: bool, + disable_parser_errors: bool, thread_count: int, file_log: bool, odin_command: string, diff --git a/src/common/util_windows.odin b/src/common/util_windows.odin index a8c6243..691fcab 100644 --- a/src/common/util_windows.odin +++ b/src/common/util_windows.odin @@ -16,15 +16,7 @@ foreign import kernel32 "system:kernel32.lib" @(default_calling_convention = "std") foreign kernel32 { @(link_name = "FormatMessageA") - format_message_a :: proc( - flags: u32, - source: rawptr, - message_id: u32, - langauge_id: u32, - buffer: cstring, - size: u32, - va: rawptr, - ) -> u32 --- + format_message_a :: proc(flags: u32, source: rawptr, message_id: u32, langauge_id: u32, buffer: cstring, size: u32, va: rawptr) -> u32 --- } get_case_sensitive_path :: proc( @@ -43,8 +35,9 @@ get_case_sensitive_path :: proc( ) if (file == win32.INVALID_HANDLE) { + log.errorf("Failed on get_case_sensitive_path(%v)", path) log_last_error() - return "" + return path } buffer := make([]u16, 512, context.temp_allocator) @@ -169,4 +162,4 @@ run_executable :: proc( win32.CloseHandle(stdout_read) return exit_code, true, stdout[0:index] -}
\ No newline at end of file +} diff --git a/src/main.odin b/src/main.odin index 3842c58..7823828 100644 --- a/src/main.odin +++ b/src/main.odin @@ -95,13 +95,11 @@ run :: proc(reader: ^server.Reader, writer: ^server.Writer) { end :: proc() { } - main :: proc() { reader := server.make_reader(os_read, cast(rawptr)&os.stdin) writer := server.make_writer(os_write, cast(rawptr)&os.stdout) - /* fh, err := os.open("log.txt", os.O_RDWR|os.O_CREATE) @@ -116,14 +114,7 @@ main :: proc() { set_stacktrace() } - when ODIN_OS == .Darwin { - init_global_temporary_allocator(mem.Megabyte * 100) - } else { - init_global_temporary_allocator(mem.Megabyte * 100) - //Gives weird allocation errors - //growing_arena: common.Growing_Arena - //context.temp_allocator = common.growing_arena_allocator(&growing_arena) - } + init_global_temporary_allocator(mem.Megabyte * 100) run(&reader, &writer) diff --git a/src/odin/printer/document.odin b/src/odin/printer/document.odin index 953a846..3dd9eda 100644 --- a/src/odin/printer/document.odin +++ b/src/odin/printer/document.odin @@ -10,9 +10,8 @@ Document :: union { Document_Break, Document_Group, Document_Cons, - Document_If_Break, + Document_If_Break_Or, Document_Align, - Document_Nest_If_Break, Document_Break_Parent, Document_Line_Suffix, } @@ -37,18 +36,15 @@ Document_Nest :: struct { document: ^Document, } -Document_Nest_If_Break :: struct { - document: ^Document, - group_id: string, -} - Document_Break :: struct { value: string, newline: bool, } -Document_If_Break :: struct { - value: string, +Document_If_Break_Or :: struct { + break_document: ^Document, + fit_document: ^Document, + group_id: string, } Document_Group :: struct { @@ -127,12 +123,12 @@ nest_if_break :: proc( group_id := "", allocator := context.allocator, ) -> ^Document { - document := new(Document, allocator) - document^ = Document_Nest_If_Break { - document = nested_document, - group_id = group_id, - } - return document + return if_break_or_document( + nest(nested_document, allocator), + nested_document, + group_id, + allocator, + ) } hang :: proc( @@ -186,9 +182,39 @@ align :: proc( } if_break :: proc(value: string, allocator := context.allocator) -> ^Document { + return if_break_or_document(text(value, allocator), nil, "", allocator) +} + +if_break_or :: proc { + if_break_or_string, + if_break_or_document, +} + +if_break_or_string :: proc( + break_value: string, + fit_value: string, + group_id := "", + allocator := context.allocator, +) -> ^Document { + return if_break_or_document( + text(break_value, allocator), + text(fit_value, allocator), + group_id, + allocator, + ) +} + +if_break_or_document :: proc( + break_document: ^Document, + fit_document: ^Document, + group_id := "", + allocator := context.allocator, +) -> ^Document { document := new(Document, allocator) - document^ = Document_If_Break { - value = value, + document^ = Document_If_Break_Or { + break_document = break_document, + fit_document = fit_document, + group_id = group_id, } return document } @@ -387,28 +413,24 @@ fits :: proc(width: int, list: ^[dynamic]Tuple) -> bool { } else { width -= len(v.value) } - case Document_If_Break: - if data.mode == .Break { - width -= len(v.value) - } - case Document_Nest_If_Break: + case Document_If_Break_Or: if data.mode == .Break { append( list, Tuple{ - indentation = data.indentation + 1, + indentation = data.indentation, mode = data.mode, - document = v.document, + document = v.break_document, alignment = data.alignment, }, ) - } else { + } else if v.fit_document != nil { append( list, Tuple{ indentation = data.indentation, mode = data.mode, - document = v.document, + document = v.fit_document, alignment = data.alignment, }, ) @@ -560,30 +582,25 @@ format :: proc( strings.write_string(builder, v.value) consumed += len(v.value) } - case Document_If_Break: - if data.mode == .Break { - strings.write_string(builder, v.value) - consumed += len(v.value) - } - case Document_Nest_If_Break: + case Document_If_Break_Or: mode := v.group_id != "" ? p.group_modes[v.group_id] : data.mode if mode == .Break { append( list, Tuple{ - indentation = data.indentation + 1, + indentation = data.indentation, mode = data.mode, - document = v.document, + document = v.break_document, alignment = data.alignment, }, ) - } else { + } else if v.fit_document != nil { append( list, Tuple{ indentation = data.indentation, mode = data.mode, - document = v.document, + document = v.fit_document, alignment = data.alignment, }, ) @@ -630,7 +647,9 @@ format :: proc( alignment = data.alignment, }, ) - } else if fits(width - consumed, &list_fits) && v.mode != .Break && v.mode != .Fit { + } else if fits(width - consumed, &list_fits) && + v.mode != .Break && + v.mode != .Fit { append( list, Tuple{ diff --git a/src/odin/printer/printer.odin b/src/odin/printer/printer.odin index dd724c9..d918cf2 100644 --- a/src/odin/printer/printer.odin +++ b/src/odin/printer/printer.odin @@ -31,10 +31,10 @@ Printer :: struct { } Disabled_Info :: struct { - text: string, - empty: bool, + text: string, + empty: bool, start_line: int, - end_line: int, + end_line: int, } Config :: struct { @@ -137,9 +137,9 @@ build_disabled_lines_info :: proc(p: ^Printer) { disabled_info := Disabled_Info { start_line = disable_position.line, - end_line = comment.pos.line, - text = p.src[begin:end], - empty = empty, + end_line = comment.pos.line, + text = p.src[begin:end], + empty = empty, } for line := disable_position.line; diff --git a/src/odin/printer/visit.odin b/src/odin/printer/visit.odin index 70cc8dd..85ab6b7 100644 --- a/src/odin/printer/visit.odin +++ b/src/odin/printer/visit.odin @@ -984,35 +984,54 @@ visit_stmt :: proc( ) } - if_document := text("if") + begin_document := text("if") + end_document := empty() if v.init != nil { - if_document = cons_with_nopl( - if_document, - cons(group(visit_stmt(p, v.init)), text(";")), + begin_document = cons_with_nopl( + begin_document, + cons( + group( + visit_stmt(p, v.init), + Document_Group_Options{id = "init"}, + ), + text(";"), + ), ) } if v.cond != nil && v.init != nil { - if_document = cons( - if_document, + end_document = cons( group(cons(break_with_space(), group(visit_expr(p, v.cond)))), ) } else if v.cond != nil { - if_document = cons_with_nopl( - if_document, + end_document = cons( + break_with_no_newline(), group(visit_expr(p, v.cond)), ) } - if v.init != nil && is_value_decl_statement_ending_with_call(v.init) { - document = cons(document, group(if_document)) - } else if v.cond != nil && - v.init == nil && - is_value_expression_call(v.cond) { - document = cons(document, group(if_document)) + + if v.init != nil && is_value_decl_statement_ending_with_call(v.init) || + v.cond != nil && v.init == nil && is_value_expression_call(v.cond) { + document = cons( + document, + group( + cons( + begin_document, + if_break_or( + end_document, + hang(3, end_document), + "init", + ), + ), + ), + ) } else { - document = cons(document, group(hang(3, if_document))) + document = cons( + document, + group(hang(3, cons(begin_document, end_document))), + ) } set_source_position(p, v.body.pos) diff --git a/src/server/analysis.odin b/src/server/analysis.odin index c7081c5..2eef852 100644 --- a/src/server/analysis.odin +++ b/src/server/analysis.odin @@ -70,28 +70,28 @@ DocumentLocal :: struct { } AstContext :: struct { - locals: map[int]map[string][dynamic]DocumentLocal, //locals all the way to the document position - globals: map[string]common.GlobalExpr, - variables: map[string]bool, - parameters: map[string]bool, - in_package: map[string]string, //sometimes you have to extract types from arrays/maps and you lose package information - usings: [dynamic]string, - file: ast.File, - allocator: mem.Allocator, - imports: []Package, //imports for the current document - current_package: string, - document_package: string, - use_globals: bool, - use_locals: bool, - local_id: int, - call: ^ast.Call_Expr, //used to determene the types for generics and the correct function for overloaded functions - position: common.AbsolutePosition, - value_decl: ^ast.Value_Decl, - field_name: ast.Ident, - uri: string, - fullpath: string, - recursion_counter: int, //Sometimes the ast is so malformed that it causes infinite recursion. - non_mutable_only: bool, + locals: map[int]map[string][dynamic]DocumentLocal, //locals all the way to the document position + globals: map[string]common.GlobalExpr, + variables: map[string]bool, + parameters: map[string]bool, + in_package: map[string]string, //sometimes you have to extract types from arrays/maps and you lose package information + recursion_map: map[rawptr]bool, + usings: [dynamic]string, + file: ast.File, + allocator: mem.Allocator, + imports: []Package, //imports for the current document + current_package: string, + document_package: string, + use_globals: bool, + use_locals: bool, + local_id: int, + call: ^ast.Call_Expr, //used to determene the types for generics and the correct function for overloaded functions + position: common.AbsolutePosition, + value_decl: ^ast.Value_Decl, + field_name: ast.Ident, + uri: string, + fullpath: string, + non_mutable_only: bool, } make_ast_context :: proc( @@ -113,6 +113,7 @@ make_ast_context :: proc( usings = make([dynamic]string, allocator), parameters = make(map[string]bool, 0, allocator), in_package = make(map[string]string, 0, allocator), + recursion_map = make(map[rawptr]bool, 0, allocator), file = file, imports = imports, use_locals = true, @@ -129,6 +130,12 @@ make_ast_context :: proc( return ast_context } +reset_ast_context :: proc(ast_context: ^AstContext) { + ast_context.use_globals = true + ast_context.use_locals = true + clear(&ast_context.recursion_map) +} + tokenizer_error_handler :: proc(pos: tokenizer.Pos, msg: string, args: ..any) { } @@ -862,7 +869,7 @@ resolve_function_overload :: proc( for arg_expr in group.args { next_fn: if f, ok := resolve_type_expression(ast_context, arg_expr); - ok { + ok { if call_expr == nil || len(call_expr.args) == 0 { append(&candidates, f) break next_fn @@ -1029,12 +1036,26 @@ resolve_basic_directive :: proc( ) ident.name = "Source_Code_Location" ast_context.current_package = ast_context.document_package - return resolve_type_identifier(ast_context, ident^) + return internal_resolve_type_identifier(ast_context, ident^) } return {}, false } +check_node_recursion :: proc( + ast_context: ^AstContext, + node: ^ast.Node, +) -> bool { + raw := cast(rawptr)node + + if raw in ast_context.recursion_map { + return true + } + + ast_context.recursion_map[raw] = true + + return false +} resolve_type_expression :: proc( ast_context: ^AstContext, @@ -1043,6 +1064,17 @@ resolve_type_expression :: proc( Symbol, bool, ) { + clear(&ast_context.recursion_map) + return internal_resolve_type_expression(ast_context, node) +} + +internal_resolve_type_expression :: proc( + ast_context: ^AstContext, + node: ^ast.Expr, +) -> ( + Symbol, + bool, +) { if node == nil { return {}, false } @@ -1053,25 +1085,23 @@ resolve_type_expression :: proc( ast_context.current_package = saved_package } - if ast_context.recursion_counter > 200 { - log.error("Recursion passed 200 attempts - giving up", node) + if check_node_recursion(ast_context, node) { + //log.error("Recursion detected") return {}, false } - ast_context.recursion_counter += 1 - - defer { - ast_context.recursion_counter -= 1 - } - using ast #partial switch v in node.derived { + case ^ast.Typeid_Type: + ident := new_type(ast.Ident, v.pos, v.end, context.temp_allocator) + ident.name = "typeid" + return make_symbol_basic_type_from_ast(ast_context, ident), true case ^ast.Value_Decl: if v.type != nil { - return resolve_type_expression(ast_context, v.type) + return internal_resolve_type_expression(ast_context, v.type) } else if len(v.values) > 0 { - return resolve_type_expression(ast_context, v.values[0]) + return internal_resolve_type_expression(ast_context, v.values[0]) } case ^Union_Type: return make_symbol_union_from_ast( @@ -1112,6 +1142,13 @@ resolve_type_expression :: proc( ast_context.field_name, ), true + case ^Matrix_Type: + return make_symbol_matrix_from_ast( + ast_context, + v^, + ast_context.field_name, + ), + true case ^Dynamic_Array_Type: return make_symbol_dynamic_array_from_ast( ast_context, @@ -1144,53 +1181,56 @@ resolve_type_expression :: proc( case ^Basic_Directive: return resolve_basic_directive(ast_context, v^) case ^Binary_Expr: - return resolve_first_symbol_from_binary_expression(ast_context, v) + return resolve_binary_expression(ast_context, v) case ^Ident: - return resolve_type_identifier(ast_context, v^) + delete_key(&ast_context.recursion_map, v) + return internal_resolve_type_identifier(ast_context, v^) case ^Basic_Lit: return resolve_basic_lit(ast_context, v^) case ^Type_Cast: - return resolve_type_expression(ast_context, v.type) + return internal_resolve_type_expression(ast_context, v.type) case ^Auto_Cast: - return resolve_type_expression(ast_context, v.expr) + return internal_resolve_type_expression(ast_context, v.expr) case ^Comp_Lit: - return resolve_type_expression(ast_context, v.type) + return internal_resolve_type_expression(ast_context, v.type) case ^Unary_Expr: if v.op.kind == .And { - symbol, ok := resolve_type_expression(ast_context, v.expr) + symbol, ok := internal_resolve_type_expression(ast_context, v.expr) symbol.pointers += 1 return symbol, ok } else { - return resolve_type_expression(ast_context, v.expr) + return internal_resolve_type_expression(ast_context, v.expr) } case ^Deref_Expr: - symbol, ok := resolve_type_expression(ast_context, v.expr) + symbol, ok := internal_resolve_type_expression(ast_context, v.expr) symbol.pointers -= 1 return symbol, ok case ^Paren_Expr: - return resolve_type_expression(ast_context, v.expr) + return internal_resolve_type_expression(ast_context, v.expr) case ^Slice_Expr: - return resolve_type_expression(ast_context, v.expr) + return internal_resolve_type_expression(ast_context, v.expr) case ^Tag_Expr: - return resolve_type_expression(ast_context, v.expr) + return internal_resolve_type_expression(ast_context, v.expr) case ^Helper_Type: - return resolve_type_expression(ast_context, v.type) + return internal_resolve_type_expression(ast_context, v.type) case ^Ellipsis: - return resolve_type_expression(ast_context, v.expr) + return internal_resolve_type_expression(ast_context, v.expr) case ^Implicit: ident := new_type(Ident, v.node.pos, v.node.end, ast_context.allocator) ident.name = v.tok.text - return resolve_type_identifier(ast_context, ident^) + return internal_resolve_type_identifier(ast_context, ident^) case ^Type_Assertion: if unary, ok := v.type.derived.(^ast.Unary_Expr); ok { if unary.op.kind == .Question { - if symbol, ok := resolve_type_expression(ast_context, v.expr); - ok { + if symbol, ok := internal_resolve_type_expression( + ast_context, + v.expr, + ); ok { if union_value, ok := symbol.value.(SymbolUnionValue); ok { if len(union_value.types) != 1 { return {}, false } - return resolve_type_expression( + return internal_resolve_type_expression( ast_context, union_value.types[0], ) @@ -1198,23 +1238,30 @@ resolve_type_expression :: proc( } } } else { - return resolve_type_expression(ast_context, v.type) + return internal_resolve_type_expression(ast_context, v.type) } case ^Proc_Lit: if v.type.results != nil { if len(v.type.results.list) == 1 { - return resolve_type_expression( + return internal_resolve_type_expression( ast_context, v.type.results.list[0].type, ) } } case ^Pointer_Type: - symbol, ok := resolve_type_expression(ast_context, v.elem) + symbol, ok := internal_resolve_type_expression(ast_context, v.elem) symbol.pointers += 1 return symbol, ok + case ^Matrix_Index_Expr: + if symbol, ok := internal_resolve_type_expression(ast_context, v.expr); + ok { + if mat, ok := symbol.value.(SymbolMatrixValue); ok { + return internal_resolve_type_expression(ast_context, mat.expr) + } + } case ^Index_Expr: - indexed, ok := resolve_type_expression(ast_context, v.expr) + indexed, ok := internal_resolve_type_expression(ast_context, v.expr) if !ok { return {}, false @@ -1224,15 +1271,18 @@ resolve_type_expression :: proc( #partial switch v2 in indexed.value { case SymbolDynamicArrayValue: - symbol, ok = resolve_type_expression(ast_context, v2.expr) + symbol, ok = internal_resolve_type_expression(ast_context, v2.expr) case SymbolSliceValue: - symbol, ok = resolve_type_expression(ast_context, v2.expr) + symbol, ok = internal_resolve_type_expression(ast_context, v2.expr) case SymbolFixedArrayValue: - symbol, ok = resolve_type_expression(ast_context, v2.expr) + symbol, ok = internal_resolve_type_expression(ast_context, v2.expr) case SymbolMapValue: - symbol, ok = resolve_type_expression(ast_context, v2.value) + symbol, ok = internal_resolve_type_expression( + ast_context, + v2.value, + ) case SymbolMultiPointer: - symbol, ok = resolve_type_expression(ast_context, v2.expr) + symbol, ok = internal_resolve_type_expression(ast_context, v2.expr) } symbol.type = indexed.type @@ -1240,13 +1290,16 @@ resolve_type_expression :: proc( return symbol, ok case ^Call_Expr: ast_context.call = cast(^Call_Expr)node - return resolve_type_expression(ast_context, v.expr) + return internal_resolve_type_expression(ast_context, v.expr) case ^Implicit_Selector_Expr: return Symbol{}, false case ^Selector_Call_Expr: - return resolve_type_expression(ast_context, v.expr) + return internal_resolve_type_expression(ast_context, v.expr) case ^Selector_Expr: - if selector, ok := resolve_type_expression(ast_context, v.expr); ok { + if selector, ok := internal_resolve_type_expression( + ast_context, + v.expr, + ); ok { ast_context.use_locals = false #partial switch s in selector.value { @@ -1276,7 +1329,10 @@ resolve_type_expression :: proc( ast_context.current_package = ast_context.document_package } - symbol, ok := resolve_type_expression(ast_context, s.expr) + symbol, ok := internal_resolve_type_expression( + ast_context, + s.expr, + ) symbol.type = .Variable return symbol, ok } else { @@ -1303,7 +1359,10 @@ resolve_type_expression :: proc( ) selector_expr.expr = s.return_types[0].type selector_expr.field = v.field - return resolve_type_expression(ast_context, selector_expr) + return internal_resolve_type_expression( + ast_context, + selector_expr, + ) } case SymbolStructValue: if selector.pkg != "" { @@ -1315,7 +1374,7 @@ resolve_type_expression :: proc( for name, i in s.names { if v.field != nil && name == v.field.name { ast_context.field_name = v.field^ - symbol, ok := resolve_type_expression( + symbol, ok := internal_resolve_type_expression( ast_context, s.types[i], ) @@ -1341,7 +1400,7 @@ resolve_type_expression :: proc( return Symbol{}, false } case: - log.warnf("default node kind, resolve_type_expression: %T", v) + log.warnf("default node kind, internal_resolve_type_expression: %T", v) if v == nil { return {}, false } @@ -1474,10 +1533,20 @@ resolve_type_identifier :: proc( Symbol, bool, ) { + return internal_resolve_type_identifier(ast_context, node) +} + +internal_resolve_type_identifier :: proc( + ast_context: ^AstContext, + node: ast.Ident, +) -> ( + Symbol, + bool, +) { using ast - if ast_context.recursion_counter > 200 { - log.error("Recursion passed 200 attempts - giving up", node) + if check_node_recursion(ast_context, node.derived.(^ast.Ident)) { + //log.error("Recursion detected") return {}, false } @@ -1487,12 +1556,6 @@ resolve_type_identifier :: proc( ast_context.current_package = saved_package } - ast_context.recursion_counter += 1 - - defer { - ast_context.recursion_counter -= 1 - } - if pkg, ok := ast_context.in_package[node.name]; ok { ast_context.current_package = pkg } @@ -1561,7 +1624,10 @@ resolve_type_identifier :: proc( #partial switch v in local.derived { case ^Ident: - return_symbol, ok = resolve_type_identifier(ast_context, v^) + return_symbol, ok = internal_resolve_type_identifier( + ast_context, + v^, + ) case ^Union_Type: return_symbol, ok = make_symbol_union_from_ast(ast_context, v^, node), true @@ -1611,6 +1677,9 @@ resolve_type_identifier :: proc( case ^Dynamic_Array_Type: return_symbol, ok = make_symbol_dynamic_array_from_ast(ast_context, v^, node), true + case ^Matrix_Type: + return_symbol, ok = + make_symbol_matrix_from_ast(ast_context, v^, node), true case ^Map_Type: return_symbol, ok = make_symbol_map_from_ast(ast_context, v^, node), true @@ -1655,7 +1724,10 @@ resolve_type_identifier :: proc( #partial switch v in global.expr.derived { case ^Ident: - return_symbol, ok = resolve_type_identifier(ast_context, v^) + return_symbol, ok = internal_resolve_type_identifier( + ast_context, + v^, + ) case ^Struct_Type: return_symbol, ok = make_symbol_struct_from_ast(ast_context, v^, node), true @@ -1705,6 +1777,9 @@ resolve_type_identifier :: proc( case ^Dynamic_Array_Type: return_symbol, ok = make_symbol_dynamic_array_from_ast(ast_context, v^, node), true + case ^Matrix_Type: + return_symbol, ok = + make_symbol_matrix_from_ast(ast_context, v^, node), true case ^Map_Type: return_symbol, ok = make_symbol_map_from_ast(ast_context, v^, node), true @@ -1713,7 +1788,7 @@ resolve_type_identifier :: proc( return_symbol.name = node.name return_symbol.type = global.mutable ? .Variable : .Constant case: - return_symbol, ok = resolve_type_expression( + return_symbol, ok = internal_resolve_type_expression( ast_context, global.expr, ) @@ -2013,8 +2088,7 @@ resolve_location_selector :: proc( Symbol, bool, ) { - ast_context.use_locals = true - ast_context.use_globals = true + reset_ast_context(ast_context) ast_context.current_package = ast_context.document_package symbol, ok := resolve_type_expression(ast_context, selector.expr) @@ -2059,10 +2133,7 @@ resolve_first_symbol_from_binary_expression :: proc( Symbol, bool, ) { - //Fairly simple function to find the earliest identifier symbol in binary expression. - if binary.left != nil { - if ident, ok := binary.left.derived.(^ast.Ident); ok { if s, ok := resolve_type_identifier(ast_context, ident^); ok { return s, ok @@ -2095,6 +2166,117 @@ resolve_first_symbol_from_binary_expression :: proc( return {}, false } +resolve_binary_expression :: proc( + ast_context: ^AstContext, + binary: ^ast.Binary_Expr, +) -> ( + Symbol, + bool, +) { + if binary.left == nil || binary.right == nil { + return {}, false + } + + symbol_a, symbol_b: Symbol + ok_a, ok_b: bool + + if expr, ok := binary.left.derived.(^ast.Binary_Expr); ok { + symbol_a, ok_a = resolve_binary_expression(ast_context, expr) + } else { + ast_context.use_locals = true + symbol_a, ok_a = resolve_type_expression(ast_context, binary.left) + } + + if expr, ok := binary.right.derived.(^ast.Binary_Expr); ok { + symbol_b, ok_b = resolve_binary_expression(ast_context, expr) + } else { + ast_context.use_locals = true + symbol_b, ok_b = resolve_type_expression(ast_context, binary.right) + } + + if !ok_a || !ok_b { + return {}, false + } + + if symbol, ok := symbol_a.value.(SymbolProcedureValue); + ok && len(symbol.return_types) > 0 { + symbol_a, ok_a = resolve_type_expression( + ast_context, + symbol.return_types[0].type != nil \ + ? symbol.return_types[0].type \ + : symbol.return_types[0].default_value, + ) + } + + if symbol, ok := symbol_b.value.(SymbolProcedureValue); + ok && len(symbol.return_types) > 0 { + symbol_b, ok_b = resolve_type_expression( + ast_context, + symbol.return_types[0].type != nil \ + ? symbol.return_types[0].type \ + : symbol.return_types[0].default_value, + ) + } + + if !ok_a || !ok_b { + return {}, false + } + + + matrix_value_a, is_matrix_a := symbol_a.value.(SymbolMatrixValue) + matrix_value_b, is_matrix_b := symbol_b.value.(SymbolMatrixValue) + + vector_value_a, is_vector_a := symbol_a.value.(SymbolFixedArrayValue) + vector_value_b, is_vector_b := symbol_b.value.(SymbolFixedArrayValue) + + //Handle matrix multication specially because it can actual change the return type dimension + if is_matrix_a && is_matrix_b && binary.op.kind == .Mul { + symbol_a.value = SymbolMatrixValue { + expr = matrix_value_a.expr, + x = matrix_value_a.x, + y = matrix_value_b.y, + } + return symbol_a, true + } else if is_matrix_a && is_vector_b && binary.op.kind == .Mul { + symbol_a.value = SymbolFixedArrayValue { + expr = matrix_value_a.expr, + len = matrix_value_a.y, + } + return symbol_a, true + + } else if is_vector_a && is_matrix_b && binary.op.kind == .Mul { + symbol_a.value = SymbolFixedArrayValue { + expr = matrix_value_b.expr, + len = matrix_value_b.x, + } + return symbol_a, true + } else if is_vector_a && + !is_matrix_b && + !is_vector_b && + binary.op.kind == .Mul { + return symbol_a, true + } else if is_vector_b && + !is_matrix_a && + !is_vector_a && + binary.op.kind == .Mul { + return symbol_b, true + } else if is_matrix_a && + !is_matrix_b && + !is_vector_b && + binary.op.kind == .Mul { + return symbol_a, true + } else if is_matrix_b && + !is_matrix_a && + !is_vector_a && + binary.op.kind == .Mul { + return symbol_b, true + } + + + //Otherwise just choose the first type, we do not handle error cases - that is done with the checker + return symbol_a, ok_a +} + find_position_in_call_param :: proc( ast_context: ^AstContext, call: ast.Call_Expr, @@ -2235,7 +2417,7 @@ make_symbol_array_from_ast :: proc( ) -> Symbol { symbol := Symbol { range = common.get_token_range(v.node, ast_context.file.src), - type = .Variable, + type = .Constant, pkg = get_package_from_node(v.node), name = name.name, } @@ -2261,7 +2443,7 @@ make_symbol_dynamic_array_from_ast :: proc( ) -> Symbol { symbol := Symbol { range = common.get_token_range(v.node, ast_context.file.src), - type = .Variable, + type = .Constant, pkg = get_package_from_node(v.node), name = name.name, } @@ -2273,6 +2455,28 @@ make_symbol_dynamic_array_from_ast :: proc( return symbol } +make_symbol_matrix_from_ast :: proc( + ast_context: ^AstContext, + v: ast.Matrix_Type, + name: ast.Ident, +) -> Symbol { + symbol := Symbol { + range = common.get_token_range(v.node, ast_context.file.src), + type = .Constant, + pkg = get_package_from_node(v.node), + name = name.name, + } + + symbol.value = SymbolMatrixValue { + expr = v.elem, + x = v.row_count, + y = v.column_count, + } + + return symbol +} + + make_symbol_multi_pointer_from_ast :: proc( ast_context: ^AstContext, v: ast.Multi_Pointer_Type, @@ -2280,7 +2484,7 @@ make_symbol_multi_pointer_from_ast :: proc( ) -> Symbol { symbol := Symbol { range = common.get_token_range(v.node, ast_context.file.src), - type = .Variable, + type = .Constant, pkg = get_package_from_node(v.node), name = name.name, } @@ -2299,7 +2503,7 @@ make_symbol_map_from_ast :: proc( ) -> Symbol { symbol := Symbol { range = common.get_token_range(v.node, ast_context.file.src), - type = .Variable, + type = .Constant, pkg = get_package_from_node(v.node), name = name.name, } @@ -2314,8 +2518,7 @@ make_symbol_map_from_ast :: proc( make_symbol_basic_type_from_ast :: proc( ast_context: ^AstContext, - n: ^ast.Node, - v: ^ast.Ident, + n: ^ast.Ident, ) -> Symbol { symbol := Symbol { range = common.get_token_range(n^, ast_context.file.src), @@ -2324,7 +2527,7 @@ make_symbol_basic_type_from_ast :: proc( } symbol.value = SymbolBasicValue { - ident = v, + ident = n, } return symbol @@ -2657,8 +2860,7 @@ get_generic_assignment :: proc( ) { using ast - ast_context.use_locals = true - ast_context.use_globals = true + reset_ast_context(ast_context) #partial switch v in value.derived { case ^Or_Return_Expr: @@ -2788,8 +2990,7 @@ get_locals_stmt :: proc( document_position: ^DocumentPositionContext, save_assign := false, ) { - ast_context.use_locals = true - ast_context.use_globals = true + reset_ast_context(ast_context) ast_context.current_package = ast_context.document_package using ast @@ -3420,8 +3621,8 @@ resolve_entire_decl :: proc( } data := cast(^Visit_Data)visitor.data ast_context := data.ast_context - ast_context.use_locals = true - ast_context.use_globals = true + + reset_ast_context(ast_context) data.last_visit = node @@ -3509,7 +3710,7 @@ resolve_entire_decl :: proc( } case ^ast.Selector_Expr: if symbol, ok := resolve_type_expression(ast_context, &v.node); - ok { + ok { data.symbols[cast(uintptr)node] = SymbolAndNode { node = v, symbol = symbol, @@ -3522,7 +3723,7 @@ resolve_entire_decl :: proc( } case ^ast.Call_Expr: if symbol, ok := resolve_type_expression(ast_context, &v.node); - ok { + ok { data.symbols[cast(uintptr)node] = SymbolAndNode { node = v, symbol = symbol, @@ -3549,7 +3750,7 @@ resolve_entire_decl :: proc( ) if symbol, ok := resolve_location_selector(ast_context, v); - ok { + ok { data.symbols[cast(uintptr)node] = SymbolAndNode { node = v.field, symbol = symbol, @@ -3593,7 +3794,7 @@ resolve_entire_decl :: proc( } if symbol, ok := resolve_location_identifier(ast_context, v^); - ok { + ok { data.symbols[cast(uintptr)node] = SymbolAndNode { node = v, symbol = symbol, @@ -3777,9 +3978,20 @@ get_signature :: proc( is_variable := symbol.type == .Variable + + pointer_prefix := common.repeat( + "^", + symbol.pointers, + context.temp_allocator, + ) + + #partial switch v in symbol.value { case SymbolBasicValue: - return common.node_to_string(v.ident) + return strings.concatenate( + {pointer_prefix, common.node_to_string(v.ident)}, + ast_context.allocator, + ) case SymbolBitSetValue: return common.node_to_string(v.expr) case SymbolEnumValue: @@ -3791,6 +4003,7 @@ get_signature :: proc( case SymbolMapValue: return strings.concatenate( a = { + pointer_prefix, "map[", common.node_to_string(v.key), "]", @@ -3802,34 +4015,41 @@ get_signature :: proc( return "proc" case SymbolStructValue: if is_variable { - return symbol.name + return strings.concatenate( + {pointer_prefix, symbol.name}, + ast_context.allocator, + ) } else { return "struct" } case SymbolUnionValue: if is_variable { - return symbol.name + return strings.concatenate( + {pointer_prefix, symbol.name}, + ast_context.allocator, + ) } else { return "union" } case SymbolMultiPointer: return strings.concatenate( - a = {"[^]", common.node_to_string(v.expr)}, + a = {pointer_prefix, "[^]", common.node_to_string(v.expr)}, allocator = ast_context.allocator, ) case SymbolDynamicArrayValue: return strings.concatenate( - a = {"[dynamic]", common.node_to_string(v.expr)}, + a = {pointer_prefix, "[dynamic]", common.node_to_string(v.expr)}, allocator = ast_context.allocator, ) case SymbolSliceValue: return strings.concatenate( - a = {"[]", common.node_to_string(v.expr)}, + a = {pointer_prefix, "[]", common.node_to_string(v.expr)}, allocator = ast_context.allocator, ) case SymbolFixedArrayValue: return strings.concatenate( a = { + pointer_prefix, "[", common.node_to_string(v.len), "]", @@ -3837,6 +4057,20 @@ get_signature :: proc( }, allocator = ast_context.allocator, ) + case SymbolMatrixValue: + return strings.concatenate( + a = { + pointer_prefix, + "matrix", + "[", + common.node_to_string(v.x), + ",", + common.node_to_string(v.y), + "]", + common.node_to_string(v.expr), + }, + allocator = ast_context.allocator, + ) case SymbolPackageValue: return "package" case SymbolUntypedValue: @@ -4489,6 +4723,14 @@ get_document_position_node :: proc( } case ^Undef: case ^Basic_Lit: + case ^Matrix_Index_Expr: + get_document_position(n.expr, position_context) + get_document_position(n.row_index, position_context) + get_document_position(n.column_index, position_context) + case ^Matrix_Type: + get_document_position(n.row_count, position_context) + get_document_position(n.column_count, position_context) + get_document_position(n.elem, position_context) case ^Ellipsis: get_document_position(n.expr, position_context) case ^Proc_Lit: diff --git a/src/server/collector.odin b/src/server/collector.odin index 11b6b89..b065a9e 100644 --- a/src/server/collector.odin +++ b/src/server/collector.odin @@ -320,6 +320,36 @@ collect_dynamic_array :: proc( return SymbolDynamicArrayValue{expr = elem} } +collect_matrix :: proc( + collection: ^SymbolCollection, + mat: ast.Matrix_Type, + package_map: map[string]string, +) -> SymbolMatrixValue { + elem := clone_type( + mat.elem, + collection.allocator, + &collection.unique_strings, + ) + + y := clone_type( + mat.column_count, + collection.allocator, + &collection.unique_strings, + ) + + x := clone_type( + mat.row_count, + collection.allocator, + &collection.unique_strings, + ) + + replace_package_alias(elem, package_map, collection) + replace_package_alias(x, package_map, collection) + replace_package_alias(y, package_map, collection) + + return SymbolMatrixValue{expr = elem, x = x, y = y} +} + collect_multi_pointer :: proc( collection: ^SymbolCollection, array: ast.Multi_Pointer_Type, @@ -336,6 +366,7 @@ collect_multi_pointer :: proc( return SymbolMultiPointer{expr = elem} } + collect_generic :: proc( collection: ^SymbolCollection, expr: ^ast.Expr, @@ -410,6 +441,10 @@ collect_symbols :: proc( } #partial switch v in col_expr.derived { + case ^ast.Matrix_Type: + token = v^ + token_type = .Variable + symbol.value = collect_matrix(collection, v^, package_map) case ^ast.Proc_Lit: token = v^ token_type = .Function @@ -492,6 +527,15 @@ collect_symbols :: proc( token = v^ token_type = .Variable symbol.value = collect_multi_pointer(collection, v^, package_map) + case ^ast.Typeid_Type: + if v.specialization == nil { + continue + } + + ident := new_type(ast.Ident, v.pos, v.end, context.temp_allocator) + ident.name = "typeid" + + symbol.value = collect_generic(collection, ident, package_map, uri) case ^ast.Basic_Lit: token = v^ symbol.value = collect_generic( @@ -500,11 +544,6 @@ collect_symbols :: proc( package_map, uri, ) - if expr.mutable { - token_type = .Variable - } else { - token_type = .Constant - } case ^ast.Ident: token = v^ symbol.value = collect_generic( @@ -513,6 +552,7 @@ collect_symbols :: proc( package_map, uri, ) + if expr.mutable { token_type = .Variable } else { @@ -526,14 +566,17 @@ collect_symbols :: proc( package_map, uri, ) + if expr.mutable { token_type = .Variable } else { token_type = .Unresolved } + token = expr.expr } + symbol.range = common.get_token_range(expr.name_expr, file.src) symbol.name = get_index_unique_string(collection, name) symbol.type = token_type diff --git a/src/server/completion.odin b/src/server/completion.odin index bb29bfb..59e762c 100644 --- a/src/server/completion.odin +++ b/src/server/completion.odin @@ -101,10 +101,15 @@ get_completion_list :: proc( completion_type = .Package } - if position_context.switch_type_stmt != nil && - position_context.case_clause != nil && - position_context.switch_type_stmt.pos.offset > - position_context.switch_stmt.pos.offset { + done: if position_context.switch_type_stmt != nil && + position_context.case_clause != nil { + + if position_context.switch_stmt != nil && + position_context.switch_type_stmt.pos.offset <= + position_context.switch_stmt.pos.offset { + break done + } + if assign, ok := position_context.switch_type_stmt.tag.derived.(^ast.Assign_Stmt); ok && assign.rhs != nil && len(assign.rhs) == 1 { ast_context.use_globals = true @@ -270,8 +275,7 @@ get_selector_completion :: proc( selector: Symbol ok: bool - ast_context.use_locals = true - ast_context.use_globals = true + reset_ast_context(ast_context) selector, ok = resolve_type_expression( ast_context, @@ -443,9 +447,13 @@ get_selector_completion :: proc( documentation = symbol.doc, } + //Might be a hack... + _, is_selector := type.derived.(^ast.Selector_Expr) + if symbol.pkg == ast_context.document_package || base == "runtime" || - base == "$builtin" { + base == "$builtin" || + is_selector { item.label = fmt.aprintf( "(%v%v)", common.repeat( @@ -495,7 +503,7 @@ get_selector_completion :: proc( } if symbol, ok := resolve_type_expression(ast_context, v.types[i]); - ok { + ok { if expr, ok := position_context.selector.derived.(^ast.Selector_Expr); ok { if expr.op.text == "->" && symbol.type != .Function { @@ -604,8 +612,7 @@ get_implicit_completion :: proc( selector: Symbol - ast_context.use_locals = true - ast_context.use_globals = true + reset_ast_context(ast_context) if selector.pkg != "" { ast_context.current_package = selector.pkg @@ -819,7 +826,7 @@ get_implicit_completion :: proc( } } } else if s, ok := unwrap_bitset(ast_context, comp_symbol); - ok { + ok { for enum_name in s.names { item := CompletionItem { label = enum_name, @@ -844,15 +851,15 @@ get_implicit_completion :: proc( enum_node: ^ast.Expr if position_in_node( - position_context.binary.right, - position_context.position, - ) { + position_context.binary.right, + position_context.position, + ) { context_node = position_context.binary.right enum_node = position_context.binary.left } else if position_in_node( - position_context.binary.left, - position_context.position, - ) { + position_context.binary.left, + position_context.position, + ) { context_node = position_context.binary.left enum_node = position_context.binary.right } @@ -886,7 +893,7 @@ get_implicit_completion :: proc( } else { //procedures are the only types that can return more than one value if symbol, ok := resolve_type_expression(ast_context, elem); - ok { + ok { if procedure, ok := symbol.value.(SymbolProcedureValue); ok { if procedure.return_types == nil { @@ -972,7 +979,7 @@ get_implicit_completion :: proc( call^, ) if symbol, ok := resolve_type_expression(ast_context, call.expr); - ok && parameter_ok { + ok && parameter_ok { if proc_value, ok := symbol.value.(SymbolProcedureValue); ok { if len(proc_value.arg_types) <= parameter_index { return @@ -1080,8 +1087,7 @@ get_identifier_completion :: proc( } } - ast_context.use_locals = true - ast_context.use_globals = true + reset_ast_context(ast_context) ast_context.current_package = ast_context.document_package ident := new_type( @@ -1126,8 +1132,8 @@ get_identifier_completion :: proc( k, ) - ast_context.use_locals = true - ast_context.use_globals = true + reset_ast_context(ast_context) + ast_context.current_package = ast_context.document_package ident := new_type( @@ -1144,7 +1150,7 @@ get_identifier_completion :: proc( build_procedure_symbol_signature(&symbol) if score, ok := common.fuzzy_match(matcher, ident.name); - ok == 1 { + ok == 1 { append( &combined, CombinedResult{ @@ -1438,8 +1444,7 @@ get_type_switch_completion :: proc( } } - ast_context.use_locals = true - ast_context.use_globals = true + reset_ast_context(ast_context) if assign, ok := position_context.switch_type_stmt.tag.derived.(^ast.Assign_Stmt); ok && assign.rhs != nil && len(assign.rhs) == 1 { @@ -1589,8 +1594,6 @@ append_magic_map_completion :: proc( append(items, item) } - - } append_magic_dynamic_array_completion :: proc( diff --git a/src/server/definition.odin b/src/server/definition.odin index 309cde1..fbea155 100644 --- a/src/server/definition.odin +++ b/src/server/definition.odin @@ -67,9 +67,9 @@ get_definition_location :: proc( if position_in_node(base, position_context.position) { if resolved, ok := resolve_location_identifier( - &ast_context, - ident^, - ); ok { + &ast_context, + ident^, + ); ok { location.range = resolved.range if resolved.uri == "" { @@ -88,17 +88,17 @@ get_definition_location :: proc( } if resolved, ok := resolve_location_selector( - &ast_context, - position_context.selector_expr, - ); ok { + &ast_context, + position_context.selector_expr, + ); ok { location.range = resolved.range uri = resolved.uri } } else if position_context.identifier != nil { if resolved, ok := resolve_location_identifier( - &ast_context, - position_context.identifier.derived.(^ast.Ident)^, - ); ok { + &ast_context, + position_context.identifier.derived.(^ast.Ident)^, + ); ok { location.range = resolved.range uri = resolved.uri } else { diff --git a/src/server/documents.odin b/src/server/documents.odin index 5adfdfb..7f99e52 100644 --- a/src/server/documents.odin +++ b/src/server/documents.odin @@ -331,7 +331,7 @@ document_refresh :: proc( return .ParseError } - if writer != nil && len(errors) > 0 { + if writer != nil && len(errors) > 0 && !config.disable_parser_errors { document.diagnosed_errors = true params := NotificationPublishDiagnosticsParams { diff --git a/src/server/hover.odin b/src/server/hover.odin index 0b1661b..602258d 100644 --- a/src/server/hover.odin +++ b/src/server/hover.odin @@ -139,8 +139,9 @@ get_hover_information :: proc( position_context.identifier^, ast_context.file.src, ) - ast_context.use_locals = true - ast_context.use_globals = true + + reset_ast_context(&ast_context) + ast_context.current_package = ast_context.document_package //if the base selector is the client wants to go to. @@ -150,9 +151,9 @@ get_hover_information :: proc( if position_in_node(base, position_context.position) { if resolved, ok := resolve_type_identifier( - &ast_context, - ident, - ); ok { + &ast_context, + ident, + ); ok { resolved.signature = get_signature( &ast_context, ident, @@ -199,9 +200,9 @@ get_hover_information :: proc( for name, i in v.names { if name == field { if symbol, ok := resolve_type_expression( - &ast_context, - v.types[i], - ); ok { + &ast_context, + v.types[i], + ); ok { symbol.name = name //TODO refractor - never set symbol name after creation - change writer_hover_content symbol.pkg = selector.name symbol.signature = common.node_to_string(v.types[i]) @@ -218,9 +219,9 @@ get_hover_information :: proc( if ident, ok := position_context.field.derived.(^ast.Ident); ok { if symbol, ok := resolve_type_identifier( - &ast_context, - ident^, - ); ok { + &ast_context, + ident^, + ); ok { hover.contents = write_hover_content( &ast_context, symbol, @@ -231,8 +232,8 @@ get_hover_information :: proc( } } } else if position_context.identifier != nil { - ast_context.use_locals = true - ast_context.use_globals = true + reset_ast_context(&ast_context) + ast_context.current_package = ast_context.document_package ident := position_context.identifier.derived.(^ast.Ident)^ diff --git a/src/server/memory_index.odin b/src/server/memory_index.odin index f609ca2..a211b94 100644 --- a/src/server/memory_index.odin +++ b/src/server/memory_index.odin @@ -65,7 +65,7 @@ memory_index_fuzzy_search :: proc( if pkg, ok := index.collection.packages[pkg]; ok { for _, symbol in pkg { 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/references.odin b/src/server/references.odin index d7ffb9e..de5b3cb 100644 --- a/src/server/references.odin +++ b/src/server/references.odin @@ -75,8 +75,7 @@ resolve_references :: proc( walk_directories, ) - ast_context.use_locals = true - ast_context.use_globals = true + reset_ast_context(ast_context) if position_context.struct_type != nil && position_in_struct_names( @@ -92,9 +91,9 @@ resolve_references :: proc( return {}, true } else if position_context.selector_expr != nil { if resolved, ok := resolve_type_expression( - ast_context, - position_context.selector, - ); ok { + ast_context, + position_context.selector, + ); ok { if _, is_package := resolved.value.(SymbolPackageValue); !is_package { return {}, true diff --git a/src/server/requests.odin b/src/server/requests.odin index 586a2a1..96df6e3 100644 --- a/src/server/requests.odin +++ b/src/server/requests.odin @@ -429,6 +429,8 @@ request_initialize :: proc( if unmarshal(value, ols_config, context.temp_allocator) == nil { + config.disable_parser_errors = + ols_config.disable_parser_errors config.thread_count = ols_config.thread_pool_count config.enable_document_symbols = ols_config.enable_document_symbols.(bool) or_else true diff --git a/src/server/semantic_tokens.odin b/src/server/semantic_tokens.odin index b22d53f..f2ca16f 100644 --- a/src/server/semantic_tokens.odin +++ b/src/server/semantic_tokens.odin @@ -32,11 +32,12 @@ SemanticTokenTypes :: enum { Method, } -SemanticTokenModifiers :: enum (u32) { +SemanticTokenModifiers :: enum (u8) { None = 0, - Declaration = 2, - Definition = 4, - Deprecated = 8, + Declaration = 1, + Definition = 2, + Deprecated = 4, + ReadOnly = 8, } SemanticTokensClientCapabilities :: struct { @@ -84,7 +85,7 @@ SemanticTokenBuilder :: struct { make_token_builder :: proc( allocator := context.temp_allocator, ) -> SemanticTokenBuilder { - return {tokens = make([dynamic]u32, 1000, context.temp_allocator)} + return {tokens = make([dynamic]u32, 10000, context.temp_allocator)} } get_tokens :: proc(builder: SemanticTokenBuilder) -> SemanticTokens { @@ -259,19 +260,39 @@ visit_node :: proc( ) visit(n.expr, builder, ast_context) case ^Ident: + modifier: SemanticTokenModifiers + if symbol_and_node, ok := builder.symbols[cast(uintptr)node]; ok { - if symbol_and_node.symbol.type == .Variable || + if symbol_and_node.symbol.type == .Constant || + symbol_and_node.symbol.type != .Variable { + //modifier = .ReadOnly + } + + if .Distinct in symbol_and_node.symbol.flags && symbol_and_node.symbol.type == .Constant { write_semantic_node( builder, node, ast_context.file.src, - .Variable, + .Type, .None, ) return } + _, is_proc := symbol_and_node.symbol.value.(SymbolProcedureValue) + + if symbol_and_node.symbol.type == .Variable && !is_proc { + write_semantic_node( + builder, + node, + ast_context.file.src, + .Variable, + modifier, + ) + return + } + #partial switch v in symbol_and_node.symbol.value { case SymbolPackageValue: write_semantic_node( @@ -287,7 +308,7 @@ visit_node :: proc( node, ast_context.file.src, .Struct, - .None, + modifier, ) case SymbolEnumValue: write_semantic_node( @@ -295,7 +316,7 @@ visit_node :: proc( node, ast_context.file.src, .Enum, - .None, + modifier, ) case SymbolUnionValue: write_semantic_node( @@ -303,7 +324,7 @@ visit_node :: proc( node, ast_context.file.src, .Enum, - .None, + modifier, ) case SymbolProcedureValue: write_semantic_node( @@ -311,7 +332,7 @@ visit_node :: proc( node, ast_context.file.src, .Function, - .None, + modifier, ) case SymbolProcedureGroupValue: write_semantic_node( @@ -319,7 +340,7 @@ visit_node :: proc( node, ast_context.file.src, .Function, - .None, + modifier, ) case SymbolUntypedValue: write_semantic_node( @@ -327,7 +348,7 @@ visit_node :: proc( node, ast_context.file.src, .Type, - .None, + modifier, ) case SymbolBasicValue: write_semantic_node( @@ -335,7 +356,15 @@ visit_node :: proc( node, ast_context.file.src, .Type, - .None, + modifier, + ) + case SymbolMatrixValue: + write_semantic_node( + builder, + node, + ast_context.file.src, + .Type, + modifier, ) case: //log.errorf("Unexpected symbol value: %v", symbol.value); @@ -373,6 +402,22 @@ visit_node :: proc( visit(n.stmts, builder, ast_context) case ^Expr_Stmt: visit(n.expr, builder, ast_context) + case ^Matrix_Type: + write_semantic_string( + builder, + n.tok_pos, + "matrix", + ast_context.file.src, + .Keyword, + .None, + ) + visit(n.row_count, builder, ast_context) + visit(n.column_count, builder, ast_context) + visit(n.elem, builder, ast_context) + case ^ast.Matrix_Index_Expr: + visit(n.expr, builder, ast_context) + visit(n.row_index, builder, ast_context) + visit(n.column_index, builder, ast_context) case ^Branch_Stmt: write_semantic_token( builder, @@ -702,6 +747,48 @@ visit_node :: proc( visit(n.cond, builder, ast_context) visit(n.x, builder, ast_context) visit(n.y, builder, ast_context) + case ^Union_Type: + write_semantic_string( + builder, + n.pos, + "union", + ast_context.file.src, + .Keyword, + .None, + ) + visit(n.variants, builder, ast_context) + case ^ast.Enum_Type: + write_semantic_string( + builder, + n.pos, + "enum", + ast_context.file.src, + .Keyword, + .None, + ) + visit_enum_fields(n^, builder, ast_context) + case ^Proc_Type: + write_semantic_string( + builder, + n.pos, + "proc", + ast_context.file.src, + .Keyword, + .None, + ) + visit_proc_type(n, builder, ast_context) + case ^Proc_Lit: + write_semantic_string( + builder, + n.pos, + "proc", + ast_context.file.src, + .Keyword, + .None, + ) + visit_proc_type(n.type, builder, ast_context) + + visit(n.body, builder, ast_context) case: //log.errorf("unhandled semantic token node %v", n); //panic(fmt.tprintf("Missed semantic token handling %v", n)); @@ -778,15 +865,7 @@ visit_value_decl :: proc( .Enum, .None, ) - write_semantic_string( - builder, - v.pos, - "union", - ast_context.file.src, - .Keyword, - .None, - ) - visit(v.variants, builder, ast_context) + visit(value_decl.values[0], builder, ast_context) case ^Struct_Type: write_semantic_node( builder, @@ -795,15 +874,7 @@ visit_value_decl :: proc( .Struct, .None, ) - write_semantic_string( - builder, - v.pos, - "struct", - ast_context.file.src, - .Keyword, - .None, - ) - visit_struct_fields(v^, builder, ast_context) + visit(value_decl.values[0], builder, ast_context) case ^Enum_Type: write_semantic_node( builder, @@ -812,15 +883,7 @@ visit_value_decl :: proc( .Enum, .None, ) - write_semantic_string( - builder, - v.pos, - "enum", - ast_context.file.src, - .Keyword, - .None, - ) - visit_enum_fields(v^, builder, ast_context) + visit(value_decl.values[0], builder, ast_context) case ^Proc_Group: write_semantic_node( builder, @@ -856,6 +919,8 @@ visit_value_decl :: proc( .Function, .None, ) + visit(value_decl.values[0], builder, ast_context) + case ^ast.Proc_Type: write_semantic_string( builder, v.pos, @@ -864,9 +929,7 @@ visit_value_decl :: proc( .Keyword, .None, ) - visit_proc_type(v.type, builder, ast_context) - - visit(v.body, builder, ast_context) + visit_proc_type(v, builder, ast_context) case: for name in value_decl.names { write_semantic_node( diff --git a/src/server/snippets.odin b/src/server/snippets.odin index c6a93aa..cd790a9 100644 --- a/src/server/snippets.odin +++ b/src/server/snippets.odin @@ -17,7 +17,11 @@ snippets: map[string]Snippet_Info = { packages = []string{"fmt"}, detail = "println", }, - "if" = {insert = "if ${1} {\n\t${0}\n}", packages = {}, detail = "if statement"}, + "if" = { + insert = "if ${1} {\n\t${0}\n}", + packages = {}, + detail = "if statement", + }, "forr" = { insert = "for ${2:elem} in ${1:range} {\n\t${0}\n}", packages = {}, diff --git a/src/server/symbol.odin b/src/server/symbol.odin index 0c6a4dc..215e01c 100644 --- a/src/server/symbol.odin +++ b/src/server/symbol.odin @@ -89,6 +89,12 @@ SymbolMapValue :: struct { value: ^ast.Expr, } +SymbolMatrixValue :: struct { + x: ^ast.Expr, + y: ^ast.Expr, + expr: ^ast.Expr, +} + /* Generic symbol that is used by the indexer for any variable type(constants, defined global variables, etc), */ @@ -113,6 +119,7 @@ SymbolValue :: union { SymbolSliceValue, SymbolBasicValue, SymbolUntypedValue, + SymbolMatrixValue, } SymbolFlag :: enum { @@ -178,6 +185,10 @@ free_symbol :: proc(symbol: Symbol, allocator: mem.Allocator) { } switch v in symbol.value { + case SymbolMatrixValue: + common.free_ast(v.expr, allocator) + common.free_ast(v.x, allocator) + common.free_ast(v.y, allocator) case SymbolMultiPointer: common.free_ast(v.expr, allocator) case SymbolProcedureValue: diff --git a/src/server/types.odin b/src/server/types.odin index 7e034bc..cbb168f 100644 --- a/src/server/types.odin +++ b/src/server/types.odin @@ -327,6 +327,7 @@ OlsConfig :: struct { enable_snippets: bool, enable_inlay_hints: bool, enable_references: bool, + disable_parser_errors: bool, verbose: bool, file_log: bool, odin_command: string, diff --git a/src/server/unmarshal.odin b/src/server/unmarshal.odin index bda15a7..7f520fc 100644 --- a/src/server/unmarshal.odin +++ b/src/server/unmarshal.odin @@ -41,10 +41,10 @@ unmarshal :: proc( //TEMP most likely have to rewrite the entire unmarshal using tags instead, because i sometimes have to support names like 'context', which can't be written like that if field[len(field) - 1] == '_' { if ret := unmarshal( - j[field[:len(field) - 1]], - a, - allocator, - ); ret != nil { + j[field[:len(field) - 1]], + a, + allocator, + ); ret != nil { return ret } } else { diff --git a/src/testing/testing.odin b/src/testing/testing.odin index 65694e6..0d97870 100644 --- a/src/testing/testing.odin +++ b/src/testing/testing.odin @@ -58,9 +58,9 @@ setup :: proc(src: ^Source) { } else if current == '\n' { current_line += 1 current_character = 0 - } else if current == '*' { + } else if src.main[current_index:current_index + 3] == "{*}" { dst_slice := transmute([]u8)src.main[current_index:] - src_slice := transmute([]u8)src.main[current_index + 1:] + src_slice := transmute([]u8)src.main[current_index + 3:] copy(dst_slice, src_slice) src.position.character = current_character src.position.line = current_line @@ -92,9 +92,9 @@ setup :: proc(src: ^Source) { fullpath := uri.path p := parser.Parser { - //err = parser.default_error_handler, - err = server.log_error_handler, - warn = server.log_warning_handler, + err = parser.default_error_handler, + warn = parser.default_error_handler, + flags = {.Optional_Semicolons}, } dir := filepath.base(filepath.dir(fullpath, context.temp_allocator)) @@ -122,11 +122,10 @@ setup :: proc(src: ^Source) { } if ret := server.collect_symbols( - &server.indexer.index.collection, - file, - uri.uri, - ); - ret != .None { + &server.indexer.index.collection, + file, + uri.uri, + ); ret != .None { return } } diff --git a/tests/completions_test.odin b/tests/completions_test.odin index 930ede3..21b89a2 100644 --- a/tests/completions_test.odin +++ b/tests/completions_test.odin @@ -18,7 +18,7 @@ ast_simple_struct_completion :: proc(t: ^testing.T) { main :: proc() { my_struct: My_Struct; - my_struct.* + my_struct.{*} } `, packages = {}, @@ -45,7 +45,7 @@ ast_index_array_completion :: proc(t: ^testing.T) { main :: proc() { my_struct: [] My_Struct; - my_struct[2].* + my_struct[2].{*} } `, packages = {}, @@ -72,7 +72,7 @@ ast_struct_pointer_completion :: proc(t: ^testing.T) { main :: proc() { my_struct: ^My_Struct; - my_struct.* + my_struct.{*} } `, packages = {}, @@ -100,7 +100,7 @@ ast_struct_take_address_completion :: proc(t: ^testing.T) { main :: proc() { my_struct: My_Struct; my_pointer := &my_struct; - my_pointer.* + my_pointer.{*} } `, packages = {}, @@ -128,7 +128,7 @@ ast_struct_deref_completion :: proc(t: ^testing.T) { main :: proc() { my_struct: ^^My_Struct; my_deref := my_struct^; - my_deref.* + my_deref.{*} } `, packages = {}, @@ -157,7 +157,7 @@ ast_range_map :: proc(t: ^testing.T) { my_map: map[int]My_Struct; for key, value in my_map { - value.* + value.{*} } } @@ -188,7 +188,7 @@ ast_range_array :: proc(t: ^testing.T) { my_array: []My_Struct; for value in my_array { - value.* + value.{*} } } @@ -224,7 +224,7 @@ ast_completion_identifier_proc_group :: proc(t: ^testing.T) { }; main :: proc() { - grou* + grou{*} } `, packages = {}, @@ -250,7 +250,7 @@ ast_completion_in_comp_lit_type :: proc(t: ^testing.T) { } main :: proc() { - my_comp := My_* { + my_comp := My_{*} { }; } `, @@ -274,7 +274,7 @@ ast_completion_range_struct_selector_strings :: proc(t: ^testing.T) { my_struct: My_Struct; for value in my_struct.array { - val* + val{*} } } `, @@ -286,7 +286,6 @@ ast_completion_range_struct_selector_strings :: proc(t: ^testing.T) { @(test) ast_completion_selector_on_indexed_array :: proc(t: ^testing.T) { - source := test.Source { main = `package test @@ -302,7 +301,7 @@ ast_completion_selector_on_indexed_array :: proc(t: ^testing.T) { main :: proc() { my_struct: My_Struct; - my_struct.array[len(my_struct.array)-1].* + my_struct.array[len(my_struct.array)-1].{*} } `, packages = {}, @@ -341,7 +340,7 @@ index_package_completion :: proc(t: ^testing.T) { import "my_package" main :: proc() { - my_package.* + my_package.{*} } `, packages = packages[:], @@ -378,7 +377,7 @@ ast_generic_make_slice :: proc(t: ^testing.T) { main :: proc() { my_slice := make_slice([]My_Struct, 23); - my_slic* + my_slic{*} } `, packages = {}, @@ -407,7 +406,7 @@ ast_named_procedure_1 :: proc(t: ^testing.T) { main :: proc() { my_bool := my_group(b = false, a = 2); - my_boo* + my_boo{*} } `, packages = {}, @@ -430,7 +429,7 @@ ast_named_procedure_2 :: proc(t: ^testing.T) { main :: proc() { my_bool := my_group(b = false); - my_boo* + my_boo{*} } `, packages = {}, @@ -445,7 +444,7 @@ ast_swizzle_completion :: proc(t: ^testing.T) { main = `package test main :: proc() { my_array: [4] f32; - my_array.* + my_array.{*} } `, packages = {}, @@ -474,7 +473,7 @@ ast_swizzle_completion_one_component :: proc(t: ^testing.T) { main = `package test main :: proc() { my_array: [4] f32; - my_array.x* + my_array.x{*} } `, packages = {}, @@ -494,7 +493,7 @@ ast_swizzle_completion_few_components :: proc(t: ^testing.T) { main = `package test main :: proc() { my_array: [2] f32; - my_array.x* + my_array.x{*} } `, packages = {}, @@ -516,7 +515,7 @@ ast_swizzle_resolve_one_components :: proc(t: ^testing.T) { main :: proc() { my_array: [4]f32; my_swizzle := my_array.x; - my_swizz* + my_swizz{*} } `, packages = {}, @@ -532,7 +531,7 @@ ast_swizzle_resolve_two_components :: proc(t: ^testing.T) { main :: proc() { my_array: [4]f32; my_swizzle := my_array.xx; - my_swizz* + my_swizz{*} } `, packages = {}, @@ -551,7 +550,7 @@ ast_swizzle_resolve_one_component_struct_completion :: proc(t: ^testing.T) { }; main :: proc() { my_array: [4] My_Struct; - my_array.x.* + my_array.x.{*} } `, packages = {}, @@ -581,7 +580,7 @@ ast_for_in_identifier_completion :: proc(t: ^testing.T) { for my_element in my_array { - my_elem* + my_elem{*} } } @@ -610,7 +609,7 @@ ast_completion_poly_struct_proc :: proc(t: ^testing.T) { } execute_lighting_pass2 :: proc(pass : RenderPass(LightingAccumPass2)) { - pass.* + pass.{*} } `, packages = {}, @@ -649,7 +648,7 @@ ast_generic_make_completion :: proc(t: ^testing.T) { main :: proc() { allocator: Allocator; my_array := make([dynamic]My_Struct, 343); - my_array[2].* + my_array[2].{*} } `, packages = {}, @@ -689,7 +688,7 @@ ast_generic_make_completion_2 :: proc(t: ^testing.T) { main :: proc() { allocator: Allocator; my_array := make([]My_Struct, 343); - my_array[2].* + my_array[2].{*} } `, packages = {}, @@ -718,7 +717,7 @@ ast_struct_for_in_switch_stmt_completion :: proc(t: ^testing.T) { switch (message) { case win32.WM_SIZE: for w in platform_context.windows { - w.* + w.{*} } } } @@ -745,7 +744,7 @@ ast_overload_with_autocast_completion :: proc(t: ^testing.T) { main :: proc() { my_uint: uint = 0; my_value := my_group(my_uint); - my_val* + my_val{*} } `, packages = {}, @@ -772,7 +771,7 @@ ast_overload_with_any_int_completion :: proc(t: ^testing.T) { main :: proc() { my_uint: uint = 0; my_value := my_group(my_uint); - my_val* + my_val{*} } `, packages = {}, @@ -798,7 +797,7 @@ ast_overload_with_any_int_with_poly_completion :: proc(t: ^testing.T) { main :: proc() { my_uint: uint = 0; my_value := my_group([dynamic]f32, my_uint); - my_val* + my_val{*} } `, packages = {}, @@ -821,7 +820,7 @@ ast_completion_in_between_struct :: proc(t: ^testing.T) { current_token: ^Format_Token, previous_token: ^Format_Token, line: ^Unwrapped_Line, - a* + a{*} indent: int, width: int, penalty: f32, @@ -864,7 +863,7 @@ ast_overload_with_any_int_index_completion :: proc(t: ^testing.T) { main :: proc() { my_uint: uint = 0; my_value := my_package.my_group([dynamic]f32, my_uint); - my_val* + my_val{*} } `, packages = packages[:], @@ -900,7 +899,7 @@ ast_package_procedure_completion :: proc(t: ^testing.T) { import "my_package" main :: proc() { - my_package.* + my_package.{*} } `, packages = packages[:], @@ -928,7 +927,7 @@ ast_poly_with_comp_lit_empty_completion :: proc(t: ^testing.T) { main :: proc() { t := new_type(My_Struct, {}, {}) - t.* + t.{*} } `, packages = {}, @@ -946,7 +945,7 @@ ast_global_struct_completion :: proc(t: ^testing.T) { Foo :: struct { x: int } foo := Foo{} main :: proc() { - x := foo.* + x := foo.{*} } `, packages = {}, @@ -962,7 +961,7 @@ ast_global_non_mutable_completion :: proc(t: ^testing.T) { Foo :: struct { x: int } main :: proc() { - x := Foo.* + x := Foo.{*} } `, packages = {}, @@ -978,7 +977,7 @@ ast_basic_value_untyped_completion :: proc(t: ^testing.T) { main :: proc() { xaa := 2 - xa* + xa{*} } `, packages = {}, @@ -995,7 +994,7 @@ ast_basic_value_binary_completion :: proc(t: ^testing.T) { main :: proc() { xaa := 2 xb2 := xaa - 2 - xb* + xb{*} } `, packages = {}, @@ -1024,7 +1023,7 @@ ast_file_private_completion :: proc(t: ^testing.T) { main = `package main import "my_package" main :: proc() { - my_package.* + my_package.{*} } `, packages = packages[:], @@ -1052,7 +1051,7 @@ ast_non_mutable_variable_struct_completion :: proc(t: ^testing.T) { main = `package main import "my_package" main :: proc() { - my_package.* + my_package.{*} } `, packages = packages[:], @@ -1080,7 +1079,7 @@ ast_mutable_variable_struct_completion :: proc(t: ^testing.T) { main = `package main import "my_package" main :: proc() { - my_package.var.* + my_package.var.{*} } `, packages = packages[:], @@ -1097,7 +1096,7 @@ ast_out_of_block_scope_completion :: proc(t: ^testing.T) { { aabb := 2 } - aab* + aab{*} } `, } @@ -1112,7 +1111,7 @@ ast_value_decl_multiple_name_same_type :: proc(t: ^testing.T) { main :: proc() { xaaaa, yaaaa: string xaaaa = "hi" - yaaa* + yaaa{*} } `, } @@ -1132,7 +1131,7 @@ ast_value_decl_comp_lit :: proc(t: ^testing.T) { a = 2, } - my_struct.* + my_struct.{*} } `, } @@ -1146,7 +1145,7 @@ ast_multi_pointer_completion :: proc(t: ^testing.T) { main = `package main main :: proc() { faa: [^]int - fa* + fa{*} } `, } @@ -1161,7 +1160,7 @@ ast_multi_pointer_indexed_completion :: proc(t: ^testing.T) { main :: proc() { faa: [^]int sap := faa[1] - sa* + sa{*} } `, } @@ -1181,7 +1180,7 @@ ast_implicit_named_comp_lit_bitset :: proc(t: ^testing.T) { main :: proc() { inst := My_Struct { - bits = {.*} + bits = {.{*}} } } `, @@ -1203,7 +1202,7 @@ ast_implicit_unnamed_comp_lit_bitset :: proc(t: ^testing.T) { main :: proc() { inst := My_Struct { - {.A}, {.*}, + {.A}, {.{*}}, } } `, @@ -1225,7 +1224,7 @@ ast_implicit_unnamed_comp_lit_enum :: proc(t: ^testing.T) { main :: proc() { inst := My_Struct { - .A, .* + .A, .{*} } } `, @@ -1250,7 +1249,7 @@ ast_implicit_mixed_named_and_unnamed_comp_lit_bitset :: proc(t: ^testing.T) { main :: proc() { inst := My_Struct { - foo = {{.A}, {.*}, {.B} } + foo = {{.A}, {.{*}}, {.B} } } } `, @@ -1274,7 +1273,7 @@ ast_comp_lit_in_complit_completion :: proc(t: ^testing.T) { main :: proc() { inst := My_Struct { foo = { - a* + a{*} } } } @@ -1302,7 +1301,7 @@ ast_inlined_struct :: proc(t: ^testing.T) { main :: proc() { inst: My_Struct - inst.foo.* + inst.foo.{*} } `, } @@ -1326,7 +1325,7 @@ ast_inlined_union :: proc(t: ^testing.T) { main :: proc() { inst: My_Struct - inst.* + inst.{*} } `, } @@ -1348,7 +1347,7 @@ ast_union_identifier_completion :: proc(t: ^testing.T) { } main :: proc() { - a: My_* + a: My_{*} } `, } @@ -1364,7 +1363,7 @@ ast_union_poly :: proc(t: ^testing.T) { main :: proc() { m: My_Union(int) - m.* + m.{*} } `, } @@ -1381,7 +1380,7 @@ ast_maybe_first_value :: proc(t: ^testing.T) { main :: proc() { m: Maybe(int) v, ok := m.? - v* + v{*} } `, } @@ -1396,7 +1395,7 @@ ast_maybe_second_value :: proc(t: ^testing.T) { main :: proc() { m: Maybe(int) v, ok := m.? - ok* + ok{*} } `, } @@ -1412,7 +1411,7 @@ ast_maybe_array :: proc(t: ^testing.T) { main :: proc() { m: My_Union([5]u8) - m.* + m.{*} } `, } @@ -1440,7 +1439,7 @@ ast_maybe_index_completion :: proc(t: ^testing.T) { import "my_package" main :: proc() { m: my_package.Maybe(int) - m.* + m.{*} } `, packages = packages[:], @@ -1457,7 +1456,7 @@ ast_distinct_u32_completion :: proc(t: ^testing.T) { Distinct_Type :: distinct u32 d: Distinct_Type - d* + d{*} } `, } @@ -1474,7 +1473,7 @@ ast_new_completion :: proc(t: ^testing.T) { main :: proc() { adzz := new(int); - adzz* + adzz{*} } `, @@ -1494,7 +1493,7 @@ ast_new_clone_completion :: proc(t: ^testing.T) { main :: proc() { adzz := new_clone(Foo{}); - adzz* + adzz{*} } `, @@ -1511,7 +1510,7 @@ ast_rawtr_cast_completion :: proc(t: ^testing.T) { main :: proc() { raw: rawptr my_int := cast(int)raw; - my_i* + my_i{*} } `, @@ -1538,7 +1537,7 @@ ast_overload_with_procedure_return :: proc(t: ^testing.T) { test_int :: proc() -> int {} main :: proc() { my_in := my_group([]int, test_int()) - my_in* + my_in{*} } `, } @@ -1568,7 +1567,7 @@ ast_index_proc_parameter_completion :: proc(t: ^testing.T) { main = `package main import "my_package" f :: proc(param: my_package.My_Struct) { - para* + para{*} } `, packages = packages[:], @@ -1590,7 +1589,7 @@ ast_implicit_completion_in_enum_array_comp_lit :: proc(t: ^testing.T) { foo :: enum{ one, two } bar := [foo]int{ .one = 1, - .*two = 2, + .{*}two = 2, } } `, @@ -1606,7 +1605,7 @@ ast_implicit_enum_value_decl_type :: proc(t: ^testing.T) { main = `package main Foo :: enum { Aa, Ab, Ac, Ad } main :: proc() { - foo: Foo = .* + foo: Foo = .{*} } `, } @@ -1621,7 +1620,7 @@ ast_implicit_bitset_value_decl :: proc(t: ^testing.T) { Foo :: enum { Aa, Ab, Ac, Ad } Foo_Set :: bit_set[Foo] main :: proc() { - foo_set := Foo_Set { .* } + foo_set := Foo_Set { .{*} } } `, } @@ -1637,7 +1636,7 @@ ast_implicit_bitset_add :: proc(t: ^testing.T) { Foo_Set :: bit_set[Foo] main :: proc() { foo_set: Foo_Set - foo_set += .* + foo_set += .{*} } `, } @@ -1651,7 +1650,7 @@ ast_enum_complete :: proc(t: ^testing.T) { main = `package main Foo :: enum { Aa, Ab, Ac, Ad } main :: proc() { - foo := Foo.* + foo := Foo.{*} } `, } @@ -1688,7 +1687,7 @@ ast_comp_lit_with_all_symbols_indexed_enum_implicit :: proc(t: ^testing.T) { import "my_package" main :: proc() { a := my_package.Bar { - c = .* + c = .{*} } } `, @@ -1725,7 +1724,7 @@ ast_package_uppercase_test :: proc(t: ^testing.T) { main = `package main import "My_package" main :: proc() { - My_package.* + My_package.{*} } `, packages = packages[:], @@ -1763,7 +1762,7 @@ ast_index_enum_infer :: proc(t: ^testing.T) { main :: proc() { my_enum: My_package.Foo - if my_enum == *. + if my_enum == {*}. } `, packages = packages[:], @@ -1777,7 +1776,7 @@ ast_index_builtin_ODIN_OS :: proc(t: ^testing.T) { source := test.Source { main = `package test main :: proc() { - when ODIN_OS == .* + when ODIN_OS == .{*} } `, packages = {}, @@ -1794,7 +1793,7 @@ ast_for_in_range_half_completion_1 :: proc(t: ^testing.T) { ints: []int for int_idx in 0..<len(ints) { - ints[int_idx] = int_i* + ints[int_idx] = int_i{*} } } `, @@ -1810,7 +1809,7 @@ ast_for_in_range_half_completion_2 :: proc(t: ^testing.T) { main = `package test advance_rune_n :: proc(t: ^Tokenizer, n: int) { for in 0..<n { - advance_rune(n*) + advance_rune(n{*}) } } `, @@ -1841,7 +1840,7 @@ ast_for_in_switch_type :: proc(t: ^testing.T) { switch v in my_union { case My_Struct: for item in v.my { - item.* + item.{*} } } } @@ -1860,7 +1859,7 @@ ast_procedure_in_procedure_non_mutable_completion :: proc(t: ^testing.T) { Int :: int my_procedure_two :: proc() { - b : In* + b : In{*} } } `, @@ -1884,7 +1883,7 @@ ast_switch_completion_for_maybe_enum :: proc(t: ^testing.T) { switch v in a { case My_Enum: switch v { - case .* + case .{*} } } @@ -1895,3 +1894,140 @@ ast_switch_completion_for_maybe_enum :: proc(t: ^testing.T) { test.expect_completion_details(t, &source, ".", {"One", "Two"}) } + +@(test) +ast_union_with_type_from_different_package :: proc(t: ^testing.T) { + packages := make([dynamic]test.Package) + + append( + &packages, + test.Package{ + pkg = "my_package", + source = `package my_package + My_Int :: int + `, + }, + ) + + source := test.Source { + main = `package main + import "my_package" + + My_Union :: union { + bool, + my_package.My_Int, + } + + main :: proc() { + my_union: My_Union + my_union.{*} + } + `, + packages = packages[:], + } + + test.expect_completion_labels(t, &source, ".", {"(my_package.My_Int)"}) +} + +@(test) +ast_completion_union_with_typeid :: proc(t: ^testing.T) { + source := test.Source { + main = `package main + Maybe :: union($T: typeid) {T} + + main :: proc() { + my_maybe: Maybe(typeid) + my_maybe.{*} + } + `, + } + + test.expect_completion_labels(t, &source, ".", {"(typeid)"}) +} + +@(test) +ast_completion_with_pointer :: proc(t: ^testing.T) { + source := test.Source { + main = `package main + + main :: proc() { + my_pointer: ^int + my_p{*} + } + `, + } + + test.expect_completion_details(t, &source, "", {"test.my_pointer: ^int"}) +} + + +@(test) +ast_matrix_completion_index :: proc(t: ^testing.T) { + source := test.Source { + main = `package main + main :: proc() { + m := matrix[2, 3]f32 { + 1, 9, -13, + 20, 5, -6, + } + + my_float := m[2, 3] + my_f{*} + } + `, + } + + test.expect_completion_details(t, &source, "", {"test.my_float: f32"}) +} + +@(test) +ast_matrix_with_matrix_mult :: proc(t: ^testing.T) { + source := test.Source { + main = `package main + main :: proc() { + a := matrix[2, 3]f32 { + 2, 3, 1, + 4, 5, 0, + } + + b := matrix[3, 2]f32 { + 1, 2, + 3, 4, + 5, 6, + } + + my_matrix := a * b + + my_matri{*} + } + `, + } + + test.expect_completion_details( + t, + &source, + "", + {"test.my_matrix: matrix[2,2]f32"}, + ) +} + +@(test) +ast_vector_with_matrix_mult :: proc(t: ^testing.T) { + source := test.Source { + main = `package main + + My_Matrix :: matrix[2, 4]f32 + + main :: proc() { + m := My_Matrix{1, 2, 3, 4, 5, 5, 4, 2} + v := [4]f32{1, 5, 4, 3} + + my_vector := m * v + + my_vecto{*} + } + `, + } + + test.expect_completion_details(t, &source, "", {"test.my_vector: [4]f32"}) +} diff --git a/tests/hover_test.odin b/tests/hover_test.odin index 1c975cc..910f0be 100644 --- a/tests/hover_test.odin +++ b/tests/hover_test.odin @@ -11,7 +11,7 @@ ast_hover_default_intialized_parameter :: proc(t: ^testing.T) { main = `package test my_function :: proc(a := false) { - b := a*; + b := a{*}; } `, @@ -29,7 +29,7 @@ ast_hover_default_parameter_enum :: proc(t: ^testing.T) { } main :: proc() { - procedure* + procedure{*} } `, packages = {}, @@ -47,7 +47,7 @@ ast_hover_parameter :: proc(t: ^testing.T) { main = `package test main :: proc(cool: int) { - cool* + cool{*} } `, packages = {}, @@ -77,7 +77,7 @@ ast_hover_external_package_parameter :: proc(t: ^testing.T) { main = `package test import "my_package" main :: proc(cool: my_package.My_Struct) { - cool* + cool{*} } `, packages = packages[:], @@ -106,7 +106,7 @@ ast_hover_procedure_package_parameter :: proc(t: ^testing.T) { source := test.Source { main = `package test import "my_package" - main :: proc(cool: my_packa*ge.My_Struct) { + main :: proc(cool: my_packa{*}ge.My_Struct) { } `, @@ -127,7 +127,7 @@ ast_hover_procedure_with_default_comp_lit :: proc(t: ^testing.T) { a: int, } - fa* :: proc(color_ : Color = { 255, 255, 255, 255 }) + fa{*} :: proc(color_ : Color = { 255, 255, 255, 255 }) `, } @@ -149,7 +149,7 @@ ast_hover_same_name_in_selector_and_field :: proc(t: ^testing.T) { f :: proc() { color: Color - color.colo*r + color.colo{*}r } `, } diff --git a/tests/signatures_test.odin b/tests/signatures_test.odin index 9795710..b6de667 100644 --- a/tests/signatures_test.odin +++ b/tests/signatures_test.odin @@ -10,7 +10,7 @@ import test "shared:testing" ast_declare_proc_signature :: proc(t: ^testing.T) { source := test.Source { main = `package test - main :: proc(*) + main :: proc({*}) `, packages = {}, } @@ -28,7 +28,7 @@ ast_naked_parens :: proc(t: ^testing.T) { return; } - (*) + ({*}) switch n in node.derived { } @@ -48,7 +48,7 @@ ast_simple_proc_signature :: proc(t: ^testing.T) { } main :: proc() { - cool_function(*) + cool_function({*}) } `, packages = {}, @@ -69,7 +69,7 @@ ast_default_assignment_proc_signature :: proc(t: ^testing.T) { } main :: proc() { - cool_function(*) + cool_function({*}) } `, packages = {}, @@ -90,7 +90,7 @@ ast_proc_signature_argument_last_position :: proc(t: ^testing.T) { } main :: proc() { - cool_function(2,* + cool_function(2,{*} } `, packages = {}, @@ -107,7 +107,7 @@ ast_proc_signature_argument_first_position :: proc(t: ^testing.T) { } main :: proc() { - cool_function(2*,) + cool_function(2{*},) } `, packages = {}, @@ -125,7 +125,7 @@ ast_proc_signature_argument_move_position :: proc(t: ^testing.T) { } main :: proc() { - cool_function(2,3*, 3); + cool_function(2,3{*}, 3); } `, packages = {}, @@ -142,7 +142,7 @@ ast_proc_signature_argument_complex :: proc(t: ^testing.T) { } main :: proc() { - cool_function(a(2,5,b(3,sdf[2],{})), *); + cool_function(a(2,5,b(3,sdf[2],{})), {*}); } `, packages = {}, @@ -159,7 +159,7 @@ ast_proc_signature_argument_open_brace_position :: proc(t: ^testing.T) { } main :: proc() { - cool_function(2,3, 3* + cool_function(2,3, 3{*} } `, packages = {}, @@ -176,7 +176,7 @@ ast_proc_signature_argument_any_ellipsis_position :: proc(t: ^testing.T) { } main :: proc() { - cool_function(3, 4, 5*) + cool_function(3, 4, 5{*}) } `, packages = {}, @@ -201,7 +201,7 @@ ast_proc_group_signature_empty_call :: proc(t: ^testing.T) { }; main :: proc() { - group_function(*) + group_function({*}) } `, packages = {}, @@ -228,7 +228,7 @@ ast_proc_signature_generic :: proc(t: ^testing.T) { } main :: proc() { - clone_array(*) + clone_array({*}) } `, packages = {}, @@ -259,7 +259,7 @@ ast_proc_group_signature_basic_types :: proc(t: ^testing.T) { }; main :: proc() { - group_function(2, true, *) + group_function(2, true, {*}) } `, packages = {}, @@ -295,7 +295,7 @@ ast_proc_group_signature_distinct_basic_types :: proc(t: ^testing.T) { a: My_Int; - group_function(a, *) + group_function(a, {*}) } `, packages = {}, @@ -339,7 +339,7 @@ ast_proc_group_signature_struct :: proc(t: ^testing.T) { main :: proc() { a: int; b: My_Struct; - group_function(a, b, *) + group_function(a, b, {*}) } `, packages = {}, @@ -374,7 +374,7 @@ index_simple_signature :: proc(t: ^testing.T) { import "my_package" main :: proc() { - my_package.my_function(*) + my_package.my_function({*}) } `, packages = packages[:], @@ -392,7 +392,7 @@ ast_index_builtin_len_proc :: proc(t: ^testing.T) { source := test.Source { main = `package test main :: proc() { - len(*) + len({*}) } `, packages = {}, @@ -411,7 +411,7 @@ ast_signature_on_invalid_package :: proc(t: ^testing.T) { main = `package test import "core:totallyReal" main :: proc() { - a := totallyReal.read_cycle_counter(*) + a := totallyReal.read_cycle_counter({*}) } `, packages = {}, @@ -431,7 +431,7 @@ ast_signature_variable_pointer :: proc(t: ^testing.T) { main :: proc() { my_fun_ptr: My_Fun; - my_fun_ptr(*) + my_fun_ptr({*}) } `, packages = {}, @@ -453,7 +453,7 @@ ast_signature_global_variable_pointer :: proc(t: ^testing.T) { my_fun_ptr: My_Fun; main :: proc() { - my_fun_ptr(*) + my_fun_ptr({*}) } `, packages = {}, @@ -484,7 +484,7 @@ index_variable_pointer_signature :: proc(t: ^testing.T) { import "my_package" main :: proc() { - my_package.my_fun_ptr(*) + my_package.my_fun_ptr({*}) } `, packages = packages[:], @@ -507,7 +507,7 @@ shared_value_decl_type_signature :: proc(t: ^testing.T) { } main :: proc() { - my_function(*) + my_function({*}) } `, packages = {}, @@ -532,7 +532,7 @@ proc_with_struct_poly :: proc(t: ^testing.T) { } main :: proc() { - uf(*) + uf({*}) } `, packages = {}, @@ -549,7 +549,7 @@ proc_signature_move_outside :: proc(t: ^testing.T) { } main :: proc() { - my_cool_function()* + my_cool_function(){*} } `, packages = {}, @@ -562,7 +562,6 @@ proc_signature_move_outside :: proc(t: ^testing.T) { ) } - /* @(test) signature_function_inside_when :: proc(t: ^testing.T) { @@ -574,7 +573,7 @@ signature_function_inside_when :: proc(t: ^testing.T) { } main :: proc() { - ProcAllocationFunction(*) + ProcAllocationFunction({*}) } `, packages = {}, diff --git a/tools/odinfmt/tests/.snapshots/if.odin b/tools/odinfmt/tests/.snapshots/if.odin new file mode 100644 index 0000000..e1c05d1 --- /dev/null +++ b/tools/odinfmt/tests/.snapshots/if.odin @@ -0,0 +1,25 @@ +package odinfmt_test + + +if_one :: proc() { + if i := strings.index(imp.fullpath, ":"); + i != -1 && i > 1 && i < len(imp.fullpath) - 1 { + } +} + +if_two :: proc() { + if ret := unmarshal( + j[field[:len(field) - 1]], + a, + allocadsdsdsdsdsdsdsdtor, + ); ret != nil { + } +} + +if_three :: proc() { + if position_in_node( + position_context.binary.raaaaaaaaaaaaaaaaaaaight, + position_context.position, + ) { + } +} diff --git a/tools/odinfmt/tests/if.odin b/tools/odinfmt/tests/if.odin new file mode 100644 index 0000000..26ada3d --- /dev/null +++ b/tools/odinfmt/tests/if.odin @@ -0,0 +1,19 @@ +package odinfmt_test + + +if_one :: proc() { + if i := strings.index(imp.fullpath, ":"); i != -1 && i > 1 && i < len(imp.fullpath) - 1 { + } +} + +if_two :: proc() { + if ret := unmarshal(j[field[:len(field) - 1]], a, allocadsdsdsdsdsdsdsdtor); ret != nil { + } +} + +if_three :: proc() { + if position_in_node( + position_context.binary.raaaaaaaaaaaaaaaaaaaight, + position_context.position) { + } +}
\ No newline at end of file |