diff options
50 files changed, 6718 insertions, 2669 deletions
diff --git a/src/common/allocator.odin b/src/common/allocator.odin index 6d2d371..c231102 100644 --- a/src/common/allocator.odin +++ b/src/common/allocator.odin @@ -11,15 +11,24 @@ Scratch_Allocator :: struct { leaked_allocations: [dynamic][]byte,
}
-scratch_allocator_init :: proc (s: ^Scratch_Allocator, size: int, backup_allocator := context.allocator) {
- s.data, _ = mem.make_aligned([]byte, size, 2 * align_of(rawptr), backup_allocator)
- s.curr_offset = 0
- s.prev_allocation = nil
- s.backup_allocator = backup_allocator
+scratch_allocator_init :: proc(
+ s: ^Scratch_Allocator,
+ size: int,
+ backup_allocator := context.allocator,
+) {
+ s.data, _ = mem.make_aligned(
+ []byte,
+ size,
+ 2 * align_of(rawptr),
+ backup_allocator,
+ )
+ s.curr_offset = 0
+ s.prev_allocation = nil
+ s.backup_allocator = backup_allocator
s.leaked_allocations.allocator = backup_allocator
}
-scratch_allocator_destroy :: proc (s: ^Scratch_Allocator) {
+scratch_allocator_destroy :: proc(s: ^Scratch_Allocator) {
if s == nil {
return
}
@@ -31,14 +40,25 @@ scratch_allocator_destroy :: proc (s: ^Scratch_Allocator) { s^ = {}
}
-scratch_allocator_proc :: proc (allocator_data: rawptr, mode: mem.Allocator_Mode, size, alignment: int, old_memory: rawptr, old_size: int, loc := #caller_location) -> ([]byte, mem.Allocator_Error) {
+scratch_allocator_proc :: proc(
+ allocator_data: rawptr,
+ mode: mem.Allocator_Mode,
+ size,
+ alignment: int,
+ old_memory: rawptr,
+ old_size: int,
+ loc := #caller_location,
+) -> (
+ []byte,
+ mem.Allocator_Error,
+) {
s := (^Scratch_Allocator)(allocator_data)
if s.data == nil {
DEFAULT_BACKING_SIZE :: 1 << 22
if !(context.allocator.procedure != scratch_allocator_proc &&
- context.allocator.data != allocator_data) {
+ context.allocator.data != allocator_data) {
panic("cyclic initialization of the scratch allocator with itself")
}
scratch_allocator_init(s, DEFAULT_BACKING_SIZE)
@@ -50,7 +70,7 @@ scratch_allocator_proc :: proc (allocator_data: rawptr, mode: mem.Allocator_Mode case .Alloc:
size = mem.align_forward_int(size, alignment)
- switch {
+ switch {
case s.curr_offset + size <= len(s.data):
start := uintptr(raw_data(s.data))
ptr := start + uintptr(s.curr_offset)
@@ -80,7 +100,13 @@ scratch_allocator_proc :: proc (allocator_data: rawptr, mode: mem.Allocator_Mode if logger := context.logger; logger.lowest_level <= .Warning {
if logger.procedure != nil {
- logger.procedure(logger.data, .Warning, "mem.Scratch_Allocator resorted to backup_allocator" , logger.options, loc)
+ logger.procedure(
+ logger.data,
+ .Warning,
+ "mem.Scratch_Allocator resorted to backup_allocator",
+ logger.options,
+ loc,
+ )
}
}
@@ -100,13 +126,29 @@ scratch_allocator_proc :: proc (allocator_data: rawptr, mode: mem.Allocator_Mode end := begin + uintptr(len(s.data))
old_ptr := uintptr(old_memory)
- data, err := scratch_allocator_proc(allocator_data, .Alloc, size, alignment, old_memory, old_size, loc)
+ data, err := scratch_allocator_proc(
+ allocator_data,
+ .Alloc,
+ size,
+ alignment,
+ old_memory,
+ old_size,
+ loc,
+ )
if err != nil {
return data, err
}
runtime.copy(data, mem.byte_slice(old_memory, old_size))
- _, err = scratch_allocator_proc(allocator_data, .Free, 0, alignment, old_memory, old_size, loc)
+ _, err = scratch_allocator_proc(
+ allocator_data,
+ .Free,
+ 0,
+ alignment,
+ old_memory,
+ old_size,
+ loc,
+ )
return data, err
case .Query_Features:
@@ -122,9 +164,6 @@ scratch_allocator_proc :: proc (allocator_data: rawptr, mode: mem.Allocator_Mode return nil, nil
}
-scratch_allocator :: proc (allocator: ^Scratch_Allocator) -> mem.Allocator {
- return mem.Allocator {
- procedure = scratch_allocator_proc,
- data = allocator,
- }
+scratch_allocator :: proc(allocator: ^Scratch_Allocator) -> mem.Allocator {
+ return mem.Allocator{procedure = scratch_allocator_proc, data = allocator}
}
diff --git a/src/common/ast.odin b/src/common/ast.odin index 71f74a4..e4eb0fd 100644 --- a/src/common/ast.odin +++ b/src/common/ast.odin @@ -8,61 +8,61 @@ import "core:strings" import path "core:path/slashpath" keyword_map: map[string]bool = { - "int" = true, - "uint" = true, - "string" = true, - "cstring" = true, - "u64" = true, - "f32" = true, - "f64" = true, - "i64" = true, - "i128" = true, - "i32" = true, - "i16" = true, - "u16" = true, - "bool" = true, - "rawptr" = true, - "any" = true, - "u32" = true, - "u128" = true, - "b32" = true, - "b64" = true, - "true" = true, - "false" = true, - "nil" = true, - "byte" = true, - "u8" = true, - "i8" = true, - "rune" = true, - "f16be" = true, - "f16le" = true, - "f32be" = true, - "f32le" = true, - "f64be" = true, - "f64le" = true, - "i16be" = true, - "i16le" = true, - "i32be" = true, - "i32le" = true, - "i64be" = true, - "i64le" = true, - "u16be" = true, - "u16le" = true, - "u32be" = true, - "u32le" = true, - "u64be" = true, - "u64le" = true, - "i128be" = true, - "i128le" = true, - "u128be" = true, - "u128le" = true, - "complex32" = true, - "complex64" = true, - "complex128" = true, - "quaternion64" = true, - "quaternion128" = true, - "quaternion256" = true, - "uintptr" = true, + "int" = true, + "uint" = true, + "string" = true, + "cstring" = true, + "u64" = true, + "f32" = true, + "f64" = true, + "i64" = true, + "i128" = true, + "i32" = true, + "i16" = true, + "u16" = true, + "bool" = true, + "rawptr" = true, + "any" = true, + "u32" = true, + "u128" = true, + "b32" = true, + "b64" = true, + "true" = true, + "false" = true, + "nil" = true, + "byte" = true, + "u8" = true, + "i8" = true, + "rune" = true, + "f16be" = true, + "f16le" = true, + "f32be" = true, + "f32le" = true, + "f64be" = true, + "f64le" = true, + "i16be" = true, + "i16le" = true, + "i32be" = true, + "i32le" = true, + "i64be" = true, + "i64le" = true, + "u16be" = true, + "u16le" = true, + "u32be" = true, + "u32le" = true, + "u64be" = true, + "u64le" = true, + "i128be" = true, + "i128le" = true, + "u128be" = true, + "u128le" = true, + "complex32" = true, + "complex64" = true, + "complex128" = true, + "quaternion64" = true, + "quaternion128" = true, + "quaternion256" = true, + "uintptr" = true, } GlobalExpr :: struct { @@ -99,7 +99,12 @@ unwrap_pointer :: proc(expr: ^ast.Expr) -> (ast.Ident, bool) { return {}, false } -collect_value_decl :: proc(exprs: ^[dynamic]GlobalExpr, file: ast.File, stmt: ^ast.Node, skip_private: bool) { +collect_value_decl :: proc( + exprs: ^[dynamic]GlobalExpr, + file: ast.File, + stmt: ^ast.Node, + skip_private: bool, +) { if value_decl, ok := stmt.derived.(^ast.Value_Decl); ok { is_deprecated := false is_private_file := false @@ -112,7 +117,8 @@ collect_value_decl :: proc(exprs: ^[dynamic]GlobalExpr, file: ast.File, stmt: ^a if ident, ok := value.field.derived.(^ast.Ident); ok { switch ident.name { case "private": - if val, ok := value.value.derived.(^ast.Basic_Lit); ok { + if val, ok := value.value.derived.(^ast.Basic_Lit); + ok { switch val.tok.text { case "\"file\"": is_private_file = true @@ -141,35 +147,44 @@ collect_value_decl :: proc(exprs: ^[dynamic]GlobalExpr, file: ast.File, stmt: ^a str := get_ast_node_string(name, file.src) if value_decl.type != nil { - append(exprs, GlobalExpr { - name = str, - name_expr = name, - expr = value_decl.type, - mutable = value_decl.is_mutable, - docs = value_decl.docs, - attributes = value_decl.attributes[:], - deprecated = is_deprecated, - builtin = is_builtin, - }) - } else { - if len(value_decl.values) > i { - append(exprs, GlobalExpr { + append( + exprs, + GlobalExpr{ name = str, name_expr = name, - expr = value_decl.values[i], - mutable = value_decl.is_mutable, - docs = value_decl.docs, + expr = value_decl.type, + mutable = value_decl.is_mutable, + docs = value_decl.docs, attributes = value_decl.attributes[:], deprecated = is_deprecated, builtin = is_builtin, - }) + }, + ) + } else { + if len(value_decl.values) > i { + append( + exprs, + GlobalExpr{ + name = str, + name_expr = name, + expr = value_decl.values[i], + mutable = value_decl.is_mutable, + docs = value_decl.docs, + attributes = value_decl.attributes[:], + deprecated = is_deprecated, + builtin = is_builtin, + }, + ) } } } } } -collect_globals :: proc(file: ast.File, skip_private := false) -> []GlobalExpr { +collect_globals :: proc( + file: ast.File, + skip_private := false, +) -> []GlobalExpr { exprs := make([dynamic]GlobalExpr, context.temp_allocator) for decl in file.decls { @@ -205,16 +220,29 @@ collect_globals :: proc(file: ast.File, skip_private := false) -> []GlobalExpr { } if ident != nil && implicit != nil { - if ident.name == "ODIN_OS" && implicit.tok.text == fmt.tprint(ODIN_OS) { - if block, ok := when_decl.body.derived.(^ast.Block_Stmt); ok { + if ident.name == "ODIN_OS" && + implicit.tok.text == fmt.tprint(ODIN_OS) { + if block, ok := when_decl.body.derived.(^ast.Block_Stmt); + ok { for stmt in block.stmts { - collect_value_decl(&exprs, file, stmt, skip_private) + collect_value_decl( + &exprs, + file, + stmt, + skip_private, + ) } } } else if ident.name != "ODIN_OS" { - if block, ok := when_decl.body.derived.(^ast.Block_Stmt); ok { + if block, ok := when_decl.body.derived.(^ast.Block_Stmt); + ok { for stmt in block.stmts { - collect_value_decl(&exprs, file, stmt, skip_private) + collect_value_decl( + &exprs, + file, + stmt, + skip_private, + ) } } } @@ -226,7 +254,8 @@ collect_globals :: proc(file: ast.File, skip_private := false) -> []GlobalExpr { } } } - } else if foreign_decl, ok := decl.derived.(^ast.Foreign_Block_Decl); ok { + } else if foreign_decl, ok := decl.derived.(^ast.Foreign_Block_Decl); + ok { if foreign_decl.body == nil { continue } @@ -246,18 +275,39 @@ get_ast_node_string :: proc(node: ^ast.Node, src: string) -> string { return string(src[node.pos.offset:node.end.offset]) } -get_doc :: proc(comment: ^ast.Comment_Group, allocator: mem.Allocator) -> string { +get_doc :: proc( + comment: ^ast.Comment_Group, + allocator: mem.Allocator, +) -> string { if comment != nil { tmp: string for doc in comment.list { - tmp = strings.concatenate({tmp, "\n", doc.text}, context.temp_allocator) + tmp = strings.concatenate( + {tmp, "\n", doc.text}, + context.temp_allocator, + ) } if tmp != "" { - no_lines, _ := strings.replace_all(tmp, "//", "", context.temp_allocator) - no_begin_comments, _ := strings.replace_all(no_lines, "/*", "", context.temp_allocator) - no_end_comments, _ := strings.replace_all(no_begin_comments, "*/", "", context.temp_allocator) + no_lines, _ := strings.replace_all( + tmp, + "//", + "", + context.temp_allocator, + ) + no_begin_comments, _ := strings.replace_all( + no_lines, + "/*", + "", + context.temp_allocator, + ) + no_end_comments, _ := strings.replace_all( + no_begin_comments, + "*/", + "", + context.temp_allocator, + ) return strings.clone(no_end_comments, allocator) } } @@ -265,7 +315,7 @@ get_doc :: proc(comment: ^ast.Comment_Group, allocator: mem.Allocator) -> string return "" } -free_ast :: proc{ +free_ast :: proc { free_ast_node, free_ast_array, free_ast_dynamic_array, @@ -291,7 +341,10 @@ free_ast_array :: proc(array: $A/[]^$T, allocator: mem.Allocator) { delete(array, allocator) } -free_ast_dynamic_array :: proc(array: $A/[dynamic]^$T, allocator: mem.Allocator) { +free_ast_dynamic_array :: proc( + array: $A/[dynamic]^$T, + allocator: mem.Allocator, +) { for elem, i in array { free_ast(elem, allocator) } @@ -307,195 +360,195 @@ free_ast_node :: proc(node: ^ast.Node, allocator: mem.Allocator) { } if node.derived != nil do #partial switch n in node.derived { - case ^Bad_Expr: - case ^Ident: - case ^Implicit: - case ^Undef: - case ^Basic_Directive: - case ^Basic_Lit: - case ^Ellipsis: - free_ast(n.expr, allocator) - case ^Proc_Lit: - free_ast(n.type, allocator) - free_ast(n.body, allocator) - free_ast(n.where_clauses, allocator) - case ^Comp_Lit: - free_ast(n.type, allocator) - free_ast(n.elems, allocator) - case ^Tag_Expr: - free_ast(n.expr, allocator) - case ^Unary_Expr: - free_ast(n.expr, allocator) - case ^Binary_Expr: - free_ast(n.left, allocator) - free_ast(n.right, allocator) - case ^Paren_Expr: - free_ast(n.expr, allocator) - case ^Call_Expr: - free_ast(n.expr, allocator) - free_ast(n.args, allocator) - case ^Selector_Expr: - free_ast(n.expr, allocator) - free_ast(n.field, allocator) - case ^Implicit_Selector_Expr: - free_ast(n.field, allocator) - case ^Index_Expr: - free_ast(n.expr, allocator) - free_ast(n.index, allocator) - case ^Deref_Expr: - free_ast(n.expr, allocator) - case ^Slice_Expr: - free_ast(n.expr, allocator) - free_ast(n.low, allocator) - free_ast(n.high, allocator) - case ^Field_Value: - free_ast(n.field, allocator) - free_ast(n.value, allocator) - case ^Ternary_If_Expr: - free_ast(n.x, allocator) - free_ast(n.cond, allocator) - free_ast(n.y, allocator) - case ^Ternary_When_Expr: - free_ast(n.x, allocator) - free_ast(n.cond, allocator) - free_ast(n.y, allocator) - case ^Type_Assertion: - free_ast(n.expr, allocator) - free_ast(n.type, allocator) - case ^Type_Cast: - free_ast(n.type, allocator) - free_ast(n.expr, allocator) - case ^Auto_Cast: - free_ast(n.expr, allocator) - case ^Bad_Stmt: - case ^Empty_Stmt: - case ^Expr_Stmt: - free_ast(n.expr, allocator) - case ^Tag_Stmt: - r := cast(^Expr_Stmt)node - free_ast(r.expr, allocator) - case ^Assign_Stmt: - free_ast(n.lhs, allocator) - free_ast(n.rhs, allocator) - case ^Block_Stmt: - free_ast(n.label, allocator) - free_ast(n.stmts, allocator) - case ^If_Stmt: - free_ast(n.label, allocator) - free_ast(n.init, allocator) - free_ast(n.cond, allocator) - free_ast(n.body, allocator) - free_ast(n.else_stmt, allocator) - case ^When_Stmt: - free_ast(n.cond, allocator) - free_ast(n.body, allocator) - free_ast(n.else_stmt, allocator) - case ^Return_Stmt: - free_ast(n.results, allocator) - case ^Defer_Stmt: - free_ast(n.stmt, allocator) - case ^For_Stmt: - free_ast(n.label, allocator) - free_ast(n.init, allocator) - free_ast(n.cond, allocator) - free_ast(n.post, allocator) - free_ast(n.body, allocator) - case ^Range_Stmt: - free_ast(n.label, allocator) - free_ast(n.vals, allocator) - free_ast(n.expr, allocator) - free_ast(n.body, allocator) - case ^Case_Clause: - free_ast(n.list, allocator) - free_ast(n.body, allocator) - case ^Switch_Stmt: - free_ast(n.label, allocator) - free_ast(n.init, allocator) - free_ast(n.cond, allocator) - free_ast(n.body, allocator) - case ^Type_Switch_Stmt: - free_ast(n.label, allocator) - free_ast(n.tag, allocator) - free_ast(n.expr, allocator) - free_ast(n.body, allocator) - case ^Branch_Stmt: - free_ast(n.label, allocator) - case ^Using_Stmt: - free_ast(n.list, allocator) - case ^Bad_Decl: - case ^Value_Decl: - free_ast(n.attributes, allocator) - free_ast(n.names, allocator) - free_ast(n.type, allocator) - free_ast(n.values, allocator) - case ^Package_Decl: - case ^Import_Decl: - case ^Foreign_Block_Decl: - free_ast(n.attributes, allocator) - free_ast(n.foreign_library, allocator) - free_ast(n.body, allocator) - case ^Foreign_Import_Decl: - free_ast(n.name, allocator) - free_ast(n.attributes, allocator) - case ^Proc_Group: - free_ast(n.args, allocator) - case ^Attribute: - free_ast(n.elems, allocator) - case ^Field: - free_ast(n.names, allocator) - free_ast(n.type, allocator) - free_ast(n.default_value, allocator) - //free_ast(n.docs); - //free_ast(n.comment); - case ^Field_List: - free_ast(n.list, allocator) - case ^Typeid_Type: - free_ast(n.specialization, allocator) - case ^Helper_Type: - free_ast(n.type, allocator) - case ^Distinct_Type: - free_ast(n.type, allocator) - case ^Poly_Type: - free_ast(n.type, allocator) - free_ast(n.specialization, allocator) - case ^Proc_Type: - free_ast(n.params, allocator) - free_ast(n.results, allocator) - case ^Pointer_Type: - free_ast(n.elem, allocator) - case ^Array_Type: - free_ast(n.len, allocator) - free_ast(n.elem, allocator) - free_ast(n.tag, allocator) - case ^Dynamic_Array_Type: - free_ast(n.elem, allocator) - free_ast(n.tag, allocator) - case ^Struct_Type: - free_ast(n.poly_params, allocator) - free_ast(n.align, allocator) - free_ast(n.fields, allocator) - free_ast(n.where_clauses, allocator) - case ^Union_Type: - free_ast(n.poly_params, allocator) - free_ast(n.align, allocator) - free_ast(n.variants, allocator) - free_ast(n.where_clauses, allocator) - case ^Enum_Type: - free_ast(n.base_type, allocator) - free_ast(n.fields, allocator) - case ^Bit_Set_Type: - free_ast(n.elem, allocator) - free_ast(n.underlying, allocator) - case ^Map_Type: - free_ast(n.key, allocator) - free_ast(n.value, allocator) - case ^Multi_Pointer_Type: - free_ast(n.elem, allocator) - case ^Matrix_Type: - free_ast(n.elem, allocator) - case: - panic(fmt.aprintf("free Unhandled node kind: %T", n)) - } + case ^Bad_Expr: + case ^Ident: + case ^Implicit: + case ^Undef: + case ^Basic_Directive: + case ^Basic_Lit: + case ^Ellipsis: + free_ast(n.expr, allocator) + case ^Proc_Lit: + free_ast(n.type, allocator) + free_ast(n.body, allocator) + free_ast(n.where_clauses, allocator) + case ^Comp_Lit: + free_ast(n.type, allocator) + free_ast(n.elems, allocator) + case ^Tag_Expr: + free_ast(n.expr, allocator) + case ^Unary_Expr: + free_ast(n.expr, allocator) + case ^Binary_Expr: + free_ast(n.left, allocator) + free_ast(n.right, allocator) + case ^Paren_Expr: + free_ast(n.expr, allocator) + case ^Call_Expr: + free_ast(n.expr, allocator) + free_ast(n.args, allocator) + case ^Selector_Expr: + free_ast(n.expr, allocator) + free_ast(n.field, allocator) + case ^Implicit_Selector_Expr: + free_ast(n.field, allocator) + case ^Index_Expr: + free_ast(n.expr, allocator) + free_ast(n.index, allocator) + case ^Deref_Expr: + free_ast(n.expr, allocator) + case ^Slice_Expr: + free_ast(n.expr, allocator) + free_ast(n.low, allocator) + free_ast(n.high, allocator) + case ^Field_Value: + free_ast(n.field, allocator) + free_ast(n.value, allocator) + case ^Ternary_If_Expr: + free_ast(n.x, allocator) + free_ast(n.cond, allocator) + free_ast(n.y, allocator) + case ^Ternary_When_Expr: + free_ast(n.x, allocator) + free_ast(n.cond, allocator) + free_ast(n.y, allocator) + case ^Type_Assertion: + free_ast(n.expr, allocator) + free_ast(n.type, allocator) + case ^Type_Cast: + free_ast(n.type, allocator) + free_ast(n.expr, allocator) + case ^Auto_Cast: + free_ast(n.expr, allocator) + case ^Bad_Stmt: + case ^Empty_Stmt: + case ^Expr_Stmt: + free_ast(n.expr, allocator) + case ^Tag_Stmt: + r := cast(^Expr_Stmt)node + free_ast(r.expr, allocator) + case ^Assign_Stmt: + free_ast(n.lhs, allocator) + free_ast(n.rhs, allocator) + case ^Block_Stmt: + free_ast(n.label, allocator) + free_ast(n.stmts, allocator) + case ^If_Stmt: + free_ast(n.label, allocator) + free_ast(n.init, allocator) + free_ast(n.cond, allocator) + free_ast(n.body, allocator) + free_ast(n.else_stmt, allocator) + case ^When_Stmt: + free_ast(n.cond, allocator) + free_ast(n.body, allocator) + free_ast(n.else_stmt, allocator) + case ^Return_Stmt: + free_ast(n.results, allocator) + case ^Defer_Stmt: + free_ast(n.stmt, allocator) + case ^For_Stmt: + free_ast(n.label, allocator) + free_ast(n.init, allocator) + free_ast(n.cond, allocator) + free_ast(n.post, allocator) + free_ast(n.body, allocator) + case ^Range_Stmt: + free_ast(n.label, allocator) + free_ast(n.vals, allocator) + free_ast(n.expr, allocator) + free_ast(n.body, allocator) + case ^Case_Clause: + free_ast(n.list, allocator) + free_ast(n.body, allocator) + case ^Switch_Stmt: + free_ast(n.label, allocator) + free_ast(n.init, allocator) + free_ast(n.cond, allocator) + free_ast(n.body, allocator) + case ^Type_Switch_Stmt: + free_ast(n.label, allocator) + free_ast(n.tag, allocator) + free_ast(n.expr, allocator) + free_ast(n.body, allocator) + case ^Branch_Stmt: + free_ast(n.label, allocator) + case ^Using_Stmt: + free_ast(n.list, allocator) + case ^Bad_Decl: + case ^Value_Decl: + free_ast(n.attributes, allocator) + free_ast(n.names, allocator) + free_ast(n.type, allocator) + free_ast(n.values, allocator) + case ^Package_Decl: + case ^Import_Decl: + case ^Foreign_Block_Decl: + free_ast(n.attributes, allocator) + free_ast(n.foreign_library, allocator) + free_ast(n.body, allocator) + case ^Foreign_Import_Decl: + free_ast(n.name, allocator) + free_ast(n.attributes, allocator) + case ^Proc_Group: + free_ast(n.args, allocator) + case ^Attribute: + free_ast(n.elems, allocator) + case ^Field: + free_ast(n.names, allocator) + free_ast(n.type, allocator) + free_ast(n.default_value, allocator) + //free_ast(n.docs); + //free_ast(n.comment); + case ^Field_List: + free_ast(n.list, allocator) + case ^Typeid_Type: + free_ast(n.specialization, allocator) + case ^Helper_Type: + free_ast(n.type, allocator) + case ^Distinct_Type: + free_ast(n.type, allocator) + case ^Poly_Type: + free_ast(n.type, allocator) + free_ast(n.specialization, allocator) + case ^Proc_Type: + free_ast(n.params, allocator) + free_ast(n.results, allocator) + case ^Pointer_Type: + free_ast(n.elem, allocator) + case ^Array_Type: + free_ast(n.len, allocator) + free_ast(n.elem, allocator) + free_ast(n.tag, allocator) + case ^Dynamic_Array_Type: + free_ast(n.elem, allocator) + free_ast(n.tag, allocator) + case ^Struct_Type: + free_ast(n.poly_params, allocator) + free_ast(n.align, allocator) + free_ast(n.fields, allocator) + free_ast(n.where_clauses, allocator) + case ^Union_Type: + free_ast(n.poly_params, allocator) + free_ast(n.align, allocator) + free_ast(n.variants, allocator) + free_ast(n.where_clauses, allocator) + case ^Enum_Type: + free_ast(n.base_type, allocator) + free_ast(n.fields, allocator) + case ^Bit_Set_Type: + free_ast(n.elem, allocator) + free_ast(n.underlying, allocator) + case ^Map_Type: + free_ast(n.key, allocator) + free_ast(n.value, allocator) + case ^Multi_Pointer_Type: + free_ast(n.elem, allocator) + case ^Matrix_Type: + free_ast(n.elem, allocator) + case: + panic(fmt.aprintf("free Unhandled node kind: %T", n)) + } mem.free(node, allocator) } @@ -516,7 +569,7 @@ free_ast_file :: proc(file: ast.File, allocator := context.allocator) { delete(file.decls) } -node_equal :: proc{ +node_equal :: proc { node_equal_node, node_equal_array, node_equal_dynamic_array, @@ -722,37 +775,52 @@ node_to_string :: proc(node: ^ast.Node, remove_pointers := false) -> string { return strings.to_string(builder) } -build_string :: proc{ +build_string :: proc { build_string_ast_array, build_string_dynamic_array, build_string_node, } -build_string_dynamic_array :: proc(array: $A/[]^$T, builder: ^strings.Builder, remove_pointers: bool) { +build_string_dynamic_array :: proc( + array: $A/[]^$T, + builder: ^strings.Builder, + remove_pointers: bool, +) { for elem, i in array { build_string(elem, builder, remove_pointers) } } -build_string_ast_array :: proc(array: $A/[dynamic]^$T, builder: ^strings.Builder, remove_pointers: bool) { +build_string_ast_array :: proc( + array: $A/[dynamic]^$T, + builder: ^strings.Builder, + remove_pointers: bool, +) { for elem, i in array { build_string(elem, builder, remove_pointers) } } -build_string_node :: proc(node: ^ast.Node, builder: ^strings.Builder, remove_pointers: bool) { - +build_string_node :: proc( + node: ^ast.Node, + builder: ^strings.Builder, + remove_pointers: bool, +) { + using ast - + if node == nil { return } - + #partial switch n in node.derived { case ^Bad_Expr: case ^Ident: if strings.contains(n.name, "/") { - strings.write_string(builder, path.base(n.name, false, context.temp_allocator)) + strings.write_string( + builder, + path.base(n.name, false, context.temp_allocator), + ) } else { strings.write_string(builder, n.name) } @@ -760,7 +828,7 @@ build_string_node :: proc(node: ^ast.Node, builder: ^strings.Builder, remove_poi strings.write_string(builder, n.tok.text) case ^Undef: case ^Basic_Lit: - strings.write_string(builder, n.tok.text) + strings.write_string(builder, n.tok.text) case ^Basic_Directive: strings.write_string(builder, n.name) case ^Implicit_Selector_Expr: @@ -850,7 +918,7 @@ build_string_node :: proc(node: ^ast.Node, builder: ^strings.Builder, remove_poi } else { build_string(n.type, builder, remove_pointers) } - + build_string(n.default_value, builder, remove_pointers) case ^Field_List: for field, i in n.list { @@ -919,7 +987,11 @@ build_string_node :: proc(node: ^ast.Node, builder: ^strings.Builder, remove_poi } } -repeat :: proc(value: string, count: int, allocator := context.allocator) -> string { +repeat :: proc( + value: string, + count: int, + allocator := context.allocator, +) -> string { if count == 0 { return "" } diff --git a/src/common/config.odin b/src/common/config.odin index b4114c0..62e80cc 100644 --- a/src/common/config.odin +++ b/src/common/config.odin @@ -11,7 +11,7 @@ Config :: struct { enable_format: bool, enable_hover: bool, enable_document_symbols: bool, - enable_semantic_tokens: bool, + enable_semantic_tokens: bool, enable_inlay_hints: bool, enable_procedure_context: bool, enable_snippets: bool, @@ -24,4 +24,4 @@ Config :: struct { checker_args: string, } -config: Config;
\ No newline at end of file +config: Config diff --git a/src/common/fuzzy.odin b/src/common/fuzzy.odin index 04bb0ad..c425051 100644 --- a/src/common/fuzzy.odin +++ b/src/common/fuzzy.odin @@ -52,6 +52,7 @@ FuzzyMatcher :: struct { word_role: [max_word]FuzzyCharRole, } +//odinfmt: disable char_roles: []u8 = { // clang-format off // Curr= Empty Lower Upper Separ @@ -76,6 +77,8 @@ char_types: []u8 = { 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55, 0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55, } +//odinfmt: enable + make_fuzzy_matcher :: proc(pattern: string, allocator := context.temp_allocator) -> ^FuzzyMatcher { matcher := new(FuzzyMatcher, allocator) diff --git a/src/common/position.odin b/src/common/position.odin index e8c5ff2..5d2ae4f 100644 --- a/src/common/position.odin +++ b/src/common/position.odin @@ -33,7 +33,13 @@ AbsoluteRange :: struct { AbsolutePosition :: int -get_absolute_position :: proc(position: Position, document_text: []u8) -> (AbsolutePosition, bool) { +get_absolute_position :: proc( + position: Position, + document_text: []u8, +) -> ( + AbsolutePosition, + bool, +) { absolute: AbsolutePosition if len(document_text) == 0 { @@ -45,16 +51,31 @@ get_absolute_position :: proc(position: Position, document_text: []u8) -> (Absol index := 1 last := document_text[0] - if !get_index_at_line(&index, &line_count, &last, document_text, position.line) { + if !get_index_at_line( + &index, + &line_count, + &last, + document_text, + position.line, + ) { return absolute, false } - absolute = index + get_character_offset_u16_to_u8(position.character, document_text[index:]) + absolute = + index + + get_character_offset_u16_to_u8( + position.character, + document_text[index:], + ) return absolute, true } -get_relative_token_position :: proc(offset: int, document_text: []u8, current_start: int) -> Position { +get_relative_token_position :: proc( + offset: int, + document_text: []u8, + current_start: int, +) -> Position { start_index := current_start data := document_text[start_index:] @@ -66,10 +87,10 @@ get_relative_token_position :: proc(offset: int, document_text: []u8, current_st for i + start_index < offset { r, w := utf8.decode_rune(data[i:]) - if r == '\n' { //\r? + if r == '\n' { //\r? position.character = 0 position.line += 1 - i += 1 + i += 1 } else if w == 0 { return position } else { @@ -95,7 +116,10 @@ get_token_range :: proc(node: ast.Node, document_text: string) -> Range { go_backwards_to_endline :: proc(offset: int, document_text: []u8) -> int { index := offset - for index > 0 && document_text[index] != '\n' && document_text[index] != '\r' { + for + index > 0 && + document_text[index] != '\n' && + document_text[index] != '\r' { index -= 1 } @@ -112,34 +136,60 @@ get_token_range :: proc(node: ast.Node, document_text: string) -> Range { offset := go_backwards_to_endline(pos_offset, transmute([]u8)document_text) range.start.line = node.pos.line - 1 - range.start.character = get_character_offset_u8_to_u16(node.pos.column - 1, transmute([]u8)document_text[offset:]) + range.start.character = get_character_offset_u8_to_u16( + node.pos.column - 1, + transmute([]u8)document_text[offset:], + ) - offset = go_backwards_to_endline(end_offset - 1, transmute([]u8)document_text) + offset = go_backwards_to_endline( + end_offset - 1, + transmute([]u8)document_text, + ) range.end.line = node.end.line - 1 - range.end.character = get_character_offset_u8_to_u16(node.end.column - 1, transmute([]u8)document_text[offset:]) + range.end.character = get_character_offset_u8_to_u16( + node.end.column - 1, + transmute([]u8)document_text[offset:], + ) return range } -get_absolute_range :: proc(range: Range, document_text: []u8) -> (AbsoluteRange, bool) { +get_absolute_range :: proc( + range: Range, + document_text: []u8, +) -> ( + AbsoluteRange, + bool, +) { absolute: AbsoluteRange if len(document_text) == 0 { absolute.start = 0 - absolute.end = 0 + absolute.end = 0 return absolute, true } line_count := 0 - index := 1 - last := document_text[0] + index := 1 + last := document_text[0] - if !get_index_at_line(&index, &line_count, &last, document_text, range.start.line) { + if !get_index_at_line( + &index, + &line_count, + &last, + document_text, + range.start.line, + ) { return absolute, false } - absolute.start = index + get_character_offset_u16_to_u8(range.start.character, document_text[index:]) + absolute.start = + index + + get_character_offset_u16_to_u8( + range.start.character, + document_text[index:], + ) //if the last line was indexed at zero we have to move it back to index 1. //This happens when line = 0 @@ -147,16 +197,33 @@ get_absolute_range :: proc(range: Range, document_text: []u8) -> (AbsoluteRange, index = 1 } - if !get_index_at_line(&index, &line_count, &last, document_text, range.end.line) { + if !get_index_at_line( + &index, + &line_count, + &last, + document_text, + range.end.line, + ) { return absolute, false } - absolute.end = index + get_character_offset_u16_to_u8(range.end.character, document_text[index:]) + absolute.end = + index + + get_character_offset_u16_to_u8( + range.end.character, + document_text[index:], + ) return absolute, true } -get_index_at_line :: proc(current_index: ^int, current_line: ^int, last: ^u8, document_text: []u8, end_line: int) -> bool { +get_index_at_line :: proc( + current_index: ^int, + current_line: ^int, + last: ^u8, + document_text: []u8, + end_line: int, +) -> bool { if end_line == 0 { current_index^ = 0 return true @@ -193,8 +260,11 @@ get_index_at_line :: proc(current_index: ^int, current_line: ^int, last: ^u8, do return false } -get_character_offset_u16_to_u8 :: proc(character_offset: int, document_text: []u8) -> int { - utf8_idx := 0 +get_character_offset_u16_to_u8 :: proc( + character_offset: int, + document_text: []u8, +) -> int { + utf8_idx := 0 utf16_idx := 0 for utf16_idx < character_offset { @@ -216,8 +286,11 @@ get_character_offset_u16_to_u8 :: proc(character_offset: int, document_text: []u return utf8_idx } -get_character_offset_u8_to_u16 :: proc(character_offset: int, document_text: []u8) -> int { - utf8_idx := 0 +get_character_offset_u8_to_u16 :: proc( + character_offset: int, + document_text: []u8, +) -> int { + utf8_idx := 0 utf16_idx := 0 for utf8_idx < character_offset { @@ -237,4 +310,4 @@ get_character_offset_u8_to_u16 :: proc(character_offset: int, document_text: []u } return utf16_idx -}
\ No newline at end of file +} diff --git a/src/common/types.odin b/src/common/types.odin index 8481f50..e95b86a 100644 --- a/src/common/types.odin +++ b/src/common/types.odin @@ -24,4 +24,4 @@ WorkspaceFolder :: struct { } parser_warning_handler :: proc(pos: tokenizer.Pos, msg: string, args: ..any) { -}
\ No newline at end of file +} diff --git a/src/common/uri.odin b/src/common/uri.odin index 4dbed0f..0e2c705 100644 --- a/src/common/uri.odin +++ b/src/common/uri.odin @@ -14,7 +14,6 @@ Uri :: struct { } //Note(Daniel, This is an extremely incomplete uri parser and for now ignores fragment and query and only handles file schema) - parse_uri :: proc(value: string, allocator: mem.Allocator) -> (Uri, bool) { uri: Uri @@ -57,7 +56,10 @@ create_uri :: proc(path: string, allocator: mem.Allocator) -> Uri { strings.write_string(&builder, "file://") } - strings.write_string(&builder, encode_percent(path_forward, context.temp_allocator)) + strings.write_string( + &builder, + encode_percent(path_forward, context.temp_allocator), + ) uri: Uri @@ -89,8 +91,13 @@ encode_percent :: proc(value: string, allocator: mem.Allocator) -> string { if r > 127 || r == ':' { for i := 0; i < w; i += 1 { - strings.write_string(&builder, strings.concatenate({"%", fmt.tprintf("%X", data[index + i])}, - context.temp_allocator)) + strings.write_string( + &builder, + strings.concatenate( + {"%", fmt.tprintf("%X", data[index + i])}, + context.temp_allocator, + ), + ) } } else { strings.write_byte(&builder, data[index]) @@ -118,7 +125,13 @@ starts_with :: proc(value: string, starts_with: string) -> bool { } @(private) -decode_percent :: proc(value: string, allocator: mem.Allocator) -> (string, bool) { +decode_percent :: proc( + value: string, + allocator: mem.Allocator, +) -> ( + string, + bool, +) { builder := strings.builder_make(allocator) for i := 0; i < len(value); i += 1 { diff --git a/src/common/util.odin b/src/common/util.odin index aa113ae..0466b6e 100644 --- a/src/common/util.odin +++ b/src/common/util.odin @@ -22,14 +22,22 @@ lookup_in_path :: proc(name: string) -> (string, bool) { for directory in strings.split_iterator(&path, delimiter) { when ODIN_OS == .Windows { - name := filepath.join(elems = {directory, fmt.tprintf("%v.exe", name)}, allocator = context.temp_allocator) + name := filepath.join( + elems = {directory, fmt.tprintf("%v.exe", name)}, + allocator = context.temp_allocator, + ) if os.exists(name) { return name, true } } else { - name := filepath.join(elems = {directory, name}, allocator = context.temp_allocator) + name := filepath.join( + elems = {directory, name}, + allocator = context.temp_allocator, + ) if os.exists(name) { - if info, err := os.stat(name, context.temp_allocator); err == os.ERROR_NONE && (File_Mode_User_Executable & info.mode) != 0 { + if info, err := os.stat(name, context.temp_allocator); + err == os.ERROR_NONE && + (File_Mode_User_Executable & info.mode) != 0 { return name, true } } @@ -42,30 +50,39 @@ lookup_in_path :: proc(name: string) -> (string, bool) { when ODIN_OS == .Darwin || ODIN_OS == .Linux { FILE :: struct {} - run_executable :: proc(command: string, stdout: ^[]byte) -> (u32, bool, []byte) { - fp := popen(strings.clone_to_cstring(command, context.temp_allocator), "r") + run_executable :: proc( + command: string, + stdout: ^[]byte, + ) -> ( + u32, + bool, + []byte, + ) { + fp := popen( + strings.clone_to_cstring(command, context.temp_allocator), + "r", + ) if fp == nil { return 0, false, stdout[0:] } defer pclose(fp) - + read_buffer: [50]byte index: int - + for fgets(&read_buffer[0], size_of(read_buffer), fp) != nil { read := bytes.index_byte(read_buffer[:], 0) defer index += cast(int)read - + if read > 0 && index + cast(int)read <= len(stdout) { mem.copy(&stdout[index], &read_buffer[0], cast(int)read) } } - - - + + return 0, true, stdout[0:index] } - + foreign libc { popen :: proc(command: cstring, type: cstring) -> ^FILE --- diff --git a/src/common/util_windows.odin b/src/common/util_windows.odin index 23a58cd..59a9bcf 100644 --- a/src/common/util_windows.odin +++ b/src/common/util_windows.odin @@ -27,19 +27,34 @@ foreign kernel32 { ) -> u32 --- } -get_case_sensitive_path :: proc(path: string, allocator := context.temp_allocator) -> string { +get_case_sensitive_path :: proc( + path: string, + allocator := context.temp_allocator, +) -> string { wide := win32.utf8_to_utf16(path) - file := win32.CreateFileW(&wide[0], 0, win32.FILE_SHARE_READ, nil, win32.OPEN_EXISTING, win32.FILE_FLAG_BACKUP_SEMANTICS, nil) - - if(file == win32.INVALID_HANDLE) - { + file := win32.CreateFileW( + &wide[0], + 0, + win32.FILE_SHARE_READ, + nil, + win32.OPEN_EXISTING, + win32.FILE_FLAG_BACKUP_SEMANTICS, + nil, + ) + + if (file == win32.INVALID_HANDLE) { log_last_error() - return ""; - } + return "" + } buffer := make([]u16, 512, context.temp_allocator) - ret := win32.GetFinalPathNameByHandleW(file, &buffer[0], cast(u32)len(buffer), 0) + ret := win32.GetFinalPathNameByHandleW( + file, + &buffer[0], + cast(u32)len(buffer), + 0, + ) res, _ := win32.utf16_to_utf8(buffer[4:], allocator) @@ -56,21 +71,29 @@ log_last_error :: proc() { error_string := cstring(&err_text[0]) if (format_message_a( - FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - nil, - err, - (1 << 10) | 0, - error_string, - len(err_text) - 1, - nil, - ) != 0) { + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + nil, + err, + (1 << 10) | 0, + error_string, + len(err_text) - 1, + nil, + ) != + 0) { log.error(error_string) } } -run_executable :: proc(command: string, stdout: ^[]byte) -> (u32, bool, []byte) { - stdout_read: win32.HANDLE +run_executable :: proc( + command: string, + stdout: ^[]byte, +) -> ( + u32, + bool, + []byte, +) { + stdout_read: win32.HANDLE stdout_write: win32.HANDLE attributes: win32.SECURITY_ATTRIBUTES @@ -95,21 +118,38 @@ run_executable :: proc(command: string, stdout: ^[]byte) -> (u32, bool, []byte) startup_info.hStdOutput = stdout_write startup_info.dwFlags |= win32.STARTF_USESTDHANDLES - if !win32.CreateProcessW(nil, &win32.utf8_to_utf16(command)[0], nil, nil, true, 0, nil, nil, &startup_info, &process_info) { + if !win32.CreateProcessW( + nil, + &win32.utf8_to_utf16(command)[0], + nil, + nil, + true, + 0, + nil, + nil, + &startup_info, + &process_info, + ) { return 0, false, stdout[0:] } win32.CloseHandle(stdout_write) index: int - read: u32 + read: u32 read_buffer: [50]byte success: win32.BOOL = true for success { - success = win32.ReadFile(stdout_read, &read_buffer[0], len(read_buffer), &read, nil) + success = win32.ReadFile( + stdout_read, + &read_buffer[0], + len(read_buffer), + &read, + nil, + ) if read > 0 && index + cast(int)read <= len(stdout) { mem.copy(&stdout[index], &read_buffer[0], cast(int)read) @@ -135,4 +175,4 @@ run_executable :: proc(command: string, stdout: ^[]byte) -> (u32, bool, []byte) import "core:mem/virtual" Growing_Arena :: virtual.Growing_Arena -growing_arena_allocator :: virtual.growing_arena_allocator
\ No newline at end of file +growing_arena_allocator :: virtual.growing_arena_allocator diff --git a/src/dump_windows.odin b/src/dump_windows.odin index 96908fd..d44aaa3 100644 --- a/src/dump_windows.odin +++ b/src/dump_windows.odin @@ -19,60 +19,71 @@ set_stacktrace :: proc() { pdb.SetUnhandledExceptionFilter(dump_stack_trace_on_exception_logger) } -print_source_code_location_builder :: proc (using scl: runtime.Source_Code_Location) -> string { - using runtime +print_source_code_location_builder :: proc( + using scl: runtime.Source_Code_Location, +) -> string { + using runtime builder := strings.builder_make() - strings.write_string(&builder, file_path) - when ODIN_ERROR_POS_STYLE == .Unix { - strings.write_string(&builder, ':') + strings.write_string(&builder, file_path) + when ODIN_ERROR_POS_STYLE == .Unix { + strings.write_string(&builder, ':') strings.write_i64(&builder, cast(i64)line) strings.write_string(&builder, ':') strings.write_i64(&builder, cast(i64)column) strings.write_string(&builder, ':') - } else { - strings.write_string(&builder, "(") + } else { + strings.write_string(&builder, "(") strings.write_i64(&builder, cast(i64)line) - strings.write_string(&builder,":") + strings.write_string(&builder, ":") strings.write_i64(&builder, cast(i64)column) strings.write_string(&builder, ")") - } - strings.write_string(&builder,procedure) - strings.write_string(&builder,"()\n") + } + strings.write_string(&builder, procedure) + strings.write_string(&builder, "()\n") return strings.to_string(builder) } -dump_stack_trace_on_exception_logger :: proc "stdcall" (ExceptionInfo: ^windows.EXCEPTION_POINTERS) -> windows.LONG { +dump_stack_trace_on_exception_logger :: proc "stdcall" ( + ExceptionInfo: ^windows.EXCEPTION_POINTERS, +) -> windows.LONG { using pdb - context = runtime.default_context() // TODO: use a more efficient one-off allocators + context = runtime.default_context() // TODO: use a more efficient one-off allocators context.logger = logger - builder := strings.builder_make() - - sync.guard(&_dumpStackTrackMutex) - - if ExceptionInfo.ExceptionRecord != nil { - strings.write_string(&builder, fmt.tprintf("%v, Flags: 0x %v", ExceptionInfo.ExceptionRecord.ExceptionCode, ExceptionInfo.ExceptionRecord.ExceptionFlags)) - } - - ctxt := cast(^CONTEXT)ExceptionInfo.ContextRecord - traceBuf : [64]StackFrame - traceCount := capture_stack_trace_from_context(ctxt, traceBuf[:]) - strings.write_string(&builder, " Stacktrace:") - strings.write_uint(&builder, traceCount) - strings.write_string(&builder, "\n") - srcCodeLocs : RingBuffer(runtime.Source_Code_Location) - init_rb(&srcCodeLocs, 64) - parse_stack_trace(traceBuf[:traceCount], true, &srcCodeLocs) - for i in 0..<srcCodeLocs.len { - scl := get_rb(&srcCodeLocs, i) - strings.write_string(&builder, print_source_code_location_builder(scl)) - } - - log.error(strings.to_string(builder)) + builder := strings.builder_make() - return windows.EXCEPTION_CONTINUE_SEARCH + sync.guard(&_dumpStackTrackMutex) + + if ExceptionInfo.ExceptionRecord != nil { + strings.write_string( + &builder, + fmt.tprintf( + "%v, Flags: 0x %v", + ExceptionInfo.ExceptionRecord.ExceptionCode, + ExceptionInfo.ExceptionRecord.ExceptionFlags, + ), + ) + } + + ctxt := cast(^CONTEXT)ExceptionInfo.ContextRecord + traceBuf: [64]StackFrame + traceCount := capture_stack_trace_from_context(ctxt, traceBuf[:]) + strings.write_string(&builder, " Stacktrace:") + strings.write_uint(&builder, traceCount) + strings.write_string(&builder, "\n") + srcCodeLocs: RingBuffer(runtime.Source_Code_Location) + init_rb(&srcCodeLocs, 64) + parse_stack_trace(traceBuf[:traceCount], true, &srcCodeLocs) + for i in 0 ..< srcCodeLocs.len { + scl := get_rb(&srcCodeLocs, i) + strings.write_string(&builder, print_source_code_location_builder(scl)) + } + + log.error(strings.to_string(builder)) + + return windows.EXCEPTION_CONTINUE_SEARCH } diff --git a/src/main.odin b/src/main.odin index ac9cf72..b685147 100644 --- a/src/main.odin +++ b/src/main.odin @@ -18,13 +18,13 @@ import "shared:server" import "shared:common" os_read :: proc(handle: rawptr, data: []byte) -> (int, int) { - ptr := cast(^os.Handle)handle + ptr := cast(^os.Handle)handle a, b := os.read(ptr^, data) return a, cast(int)b } os_write :: proc(handle: rawptr, data: []byte) -> (int, int) { - ptr := cast(^os.Handle)handle + ptr := cast(^os.Handle)handle a, b := os.write(ptr^, data) return a, cast(int)b } @@ -56,9 +56,12 @@ run :: proc(reader: ^server.Reader, writer: ^server.Writer) { server.requests = make([dynamic]server.Request, context.allocator) server.deletings = make([dynamic]server.Request, context.allocator) - request_thread = thread.create_and_start_with_data(cast(rawptr)&request_thread_data, server.thread_request_main) + request_thread = thread.create_and_start_with_data( + cast(rawptr)&request_thread_data, + server.thread_request_main, + ) - server.setup_index(); + server.setup_index() for common.config.running { if common.config.verbose { @@ -95,7 +98,6 @@ end :: proc() { } - main :: proc() { reader := server.make_reader(os_read, cast(rawptr)&os.stdin) @@ -117,9 +119,9 @@ main :: proc() { } when ODIN_OS == .Darwin { - init_global_temporary_allocator(mem.Megabyte*100) + init_global_temporary_allocator(mem.Megabyte * 100) } else { - init_global_temporary_allocator(mem.Megabyte*100) + 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) diff --git a/src/odin/format/format.odin b/src/odin/format/format.odin index eee51b3..be6bd87 100644 --- a/src/odin/format/format.odin +++ b/src/odin/format/format.odin @@ -4,7 +4,7 @@ import "shared:odin/printer" import "core:odin/parser" import "core:odin/ast" import "core:encoding/json" -import "core:os" +import "core:os" import "core:path/filepath" import "core:fmt" @@ -34,7 +34,10 @@ find_config_file_or_default :: proc(path: string) -> printer.Config { } } } else { - new_path := filepath.join(elems = {path, ".."}, allocator = context.temp_allocator) + new_path := filepath.join( + elems = {path, ".."}, + allocator = context.temp_allocator, + ) //Currently the filepath implementation seems to stop at the root level, this might not be the best solution. if new_path == path { return default_style @@ -49,7 +52,16 @@ find_config_file_or_default :: proc(path: string) -> printer.Config { return config } -format :: proc(filepath: string, source: string, config: printer.Config, parser_flags := parser.Flags{.Optional_Semicolons}, allocator := context.allocator) -> (string, bool) { +format :: proc( + filepath: string, + source: string, + config: printer.Config, + parser_flags := parser.Flags{.Optional_Semicolons}, + allocator := context.allocator, +) -> ( + string, + bool, +) { config := config pkg := ast.Package { @@ -57,8 +69,8 @@ format :: proc(filepath: string, source: string, config: printer.Config, parser_ } file := ast.File { - pkg = &pkg, - src = source, + pkg = &pkg, + src = source, fullpath = filepath, } @@ -69,7 +81,7 @@ format :: proc(filepath: string, source: string, config: printer.Config, parser_ ok := parser.parse_file(&p, &file) - if !ok || file.syntax_error_count > 0 { + if !ok || file.syntax_error_count > 0 { return {}, false } diff --git a/src/odin/printer/document.odin b/src/odin/printer/document.odin index c2e59ea..3f3ed00 100644 --- a/src/odin/printer/document.odin +++ b/src/odin/printer/document.odin @@ -17,9 +17,7 @@ Document :: union { Document_Line_Suffix, } -Document_Nil :: struct { - -} +Document_Nil :: struct {} Document_Newline :: struct { amount: int, @@ -35,8 +33,8 @@ Document_Line_Suffix :: struct { Document_Nest :: struct { alignment: int, //Is only used when hanging a document - negate: bool, - document: ^Document, + negate: bool, + document: ^Document, } Document_Nest_If_Break :: struct { @@ -45,7 +43,7 @@ Document_Nest_If_Break :: struct { } Document_Break :: struct { - value: string, + value: string, newline: bool, } @@ -55,8 +53,8 @@ Document_If_Break :: struct { Document_Group :: struct { document: ^Document, - mode: Document_Group_Mode, - options: Document_Group_Options, + mode: Document_Group_Mode, + options: Document_Group_Options, } Document_Cons :: struct { @@ -77,12 +75,11 @@ Document_Group_Options :: struct { id: string, } -Document_Break_Parent :: struct { -} +Document_Break_Parent :: struct {} empty :: proc(allocator := context.allocator) -> ^Document { document := new(Document, allocator) - document^ = Document_Nil {} + document^ = Document_Nil{} return document } @@ -102,7 +99,10 @@ newline :: proc(amount: int, allocator := context.allocator) -> ^Document { return document } -nest :: proc(nested_document: ^Document, allocator := context.allocator) -> ^Document { +nest :: proc( + nested_document: ^Document, + allocator := context.allocator, +) -> ^Document { document := new(Document, allocator) document^ = Document_Nest { document = nested_document, @@ -110,16 +110,23 @@ nest :: proc(nested_document: ^Document, allocator := context.allocator) -> ^Doc return document } -escape_nest :: proc(nested_document: ^Document, allocator := context.allocator) -> ^Document { +escape_nest :: proc( + nested_document: ^Document, + allocator := context.allocator, +) -> ^Document { document := new(Document, allocator) document^ = Document_Nest { document = nested_document, - negate = true, + negate = true, } return document } -nest_if_break :: proc(nested_document: ^Document, group_id := "", allocator := context.allocator) -> ^Document { +nest_if_break :: proc( + nested_document: ^Document, + group_id := "", + allocator := context.allocator, +) -> ^Document { document := new(Document, allocator) document^ = Document_Nest_If_Break { document = nested_document, @@ -128,35 +135,49 @@ nest_if_break :: proc(nested_document: ^Document, group_id := "", allocator := c return document } -hang :: proc(align: int, hanged_document: ^Document, allocator := context.allocator) -> ^Document { +hang :: proc( + align: int, + hanged_document: ^Document, + allocator := context.allocator, +) -> ^Document { document := new(Document, allocator) document^ = Document_Nest { alignment = align, - document = hanged_document, + document = hanged_document, } return document } -enforce_fit :: proc(fitted_document: ^Document, allocator := context.allocator) -> ^Document { +enforce_fit :: proc( + fitted_document: ^Document, + allocator := context.allocator, +) -> ^Document { document := new(Document, allocator) - document^ = Document_Group { + document^ = Document_Group { document = fitted_document, - mode = .Fit, + mode = .Fit, } return document } -enforce_break :: proc(fitted_document: ^Document, options := Document_Group_Options{}, allocator := context.allocator) -> ^Document { +enforce_break :: proc( + fitted_document: ^Document, + options := Document_Group_Options{}, + allocator := context.allocator, +) -> ^Document { document := new(Document, allocator) - document^ = Document_Group { + document^ = Document_Group { document = fitted_document, - mode = .Break, - options = options, + mode = .Break, + options = options, } return document } -align :: proc(aligned_document: ^Document, allocator := context.allocator) -> ^Document { +align :: proc( + aligned_document: ^Document, + allocator := context.allocator, +) -> ^Document { document := new(Document, allocator) document^ = Document_Align { document = aligned_document, @@ -172,10 +193,14 @@ if_break :: proc(value: string, allocator := context.allocator) -> ^Document { return document } -break_with :: proc(value: string, newline := true, allocator := context.allocator) -> ^Document { +break_with :: proc( + value: string, + newline := true, + allocator := context.allocator, +) -> ^Document { document := new(Document, allocator) document^ = Document_Break { - value = value, + value = value, newline = newline, } return document @@ -183,12 +208,14 @@ break_with :: proc(value: string, newline := true, allocator := context.allocato break_parent :: proc(allocator := context.allocator) -> ^Document { document := new(Document, allocator) - document^ = Document_Break_Parent { - } + document^ = Document_Break_Parent{} return document } -line_suffix :: proc(value: string, allocator := context.allocator) -> ^Document { +line_suffix :: proc( + value: string, + allocator := context.allocator, +) -> ^Document { document := new(Document, allocator) document^ = Document_Line_Suffix { value = value, @@ -204,11 +231,15 @@ break_with_no_newline :: proc(allocator := context.allocator) -> ^Document { return break_with(" ", false, allocator) } -group :: proc(grouped_document: ^Document, options := Document_Group_Options{}, allocator := context.allocator) -> ^Document { +group :: proc( + grouped_document: ^Document, + options := Document_Group_Options{}, + allocator := context.allocator, +) -> ^Document { document := new(Document, allocator) document^ = Document_Group { document = grouped_document, - options = options, + options = options, } return document } @@ -220,7 +251,7 @@ cons :: proc(elems: ..^Document, allocator := context.allocator) -> ^Document { for elem in elems { append(&elements, elem) } - + c := Document_Cons { elements = elements[:], } @@ -228,7 +259,11 @@ cons :: proc(elems: ..^Document, allocator := context.allocator) -> ^Document { return document } -cons_with_opl :: proc(lhs: ^Document, rhs: ^Document, allocator := context.allocator) -> ^Document { +cons_with_opl :: proc( + lhs: ^Document, + rhs: ^Document, + allocator := context.allocator, +) -> ^Document { if _, ok := lhs.(Document_Nil); ok { return rhs } @@ -237,10 +272,17 @@ cons_with_opl :: proc(lhs: ^Document, rhs: ^Document, allocator := context.alloc return lhs } - return cons(elems = {lhs, break_with_space(allocator), rhs}, allocator = allocator) + return cons( + elems = {lhs, break_with_space(allocator), rhs}, + allocator = allocator, + ) } -cons_with_nopl:: proc(lhs: ^Document, rhs: ^Document, allocator := context.allocator) -> ^Document { +cons_with_nopl :: proc( + lhs: ^Document, + rhs: ^Document, + allocator := context.allocator, +) -> ^Document { if _, ok := lhs.(Document_Nil); ok { return rhs } @@ -249,14 +291,17 @@ cons_with_nopl:: proc(lhs: ^Document, rhs: ^Document, allocator := context.alloc return lhs } - return cons(elems = {lhs, break_with_no_newline(allocator), rhs}, allocator = allocator) + return cons( + elems = {lhs, break_with_no_newline(allocator), rhs}, + allocator = allocator, + ) } Tuple :: struct { indentation: int, - alignment: int, - mode: Document_Group_Mode, - document: ^Document, + alignment: int, + mode: Document_Group_Mode, + document: ^Document, } list_fits: [dynamic]Tuple @@ -291,16 +336,48 @@ fits :: proc(width: int, list: ^[dynamic]Tuple) -> bool { } case Document_Cons: for i := len(v.elements) - 1; i >= 0; i -= 1 { - append(list, Tuple {indentation = data.indentation, mode = data.mode, document = v.elements[i], alignment = data.alignment}) + append( + list, + Tuple{ + indentation = data.indentation, + mode = data.mode, + document = v.elements[i], + alignment = data.alignment, + }, + ) } case Document_Align: - append(list, Tuple {indentation = 0, mode = data.mode, document = v.document, alignment = start_width - width}) + append( + list, + Tuple{ + indentation = 0, + mode = data.mode, + document = v.document, + alignment = start_width - width, + }, + ) case Document_Nest: if v.alignment != 0 { - append(list, Tuple {indentation = data.indentation, mode = data.mode, document = v.document, alignment = data.alignment + v.alignment}) + append( + list, + Tuple{ + indentation = data.indentation, + mode = data.mode, + document = v.document, + alignment = data.alignment + v.alignment, + }, + ) } else { - append(list, Tuple {indentation = data.indentation + (v.negate ? -1 : 1), mode = data.mode, document = v.document, alignment = data.alignment + v.alignment}) + append( + list, + Tuple{ + indentation = data.indentation + (v.negate ? -1 : 1), + mode = data.mode, + document = v.document, + alignment = data.alignment + v.alignment, + }, + ) } case Document_Text: width -= len(v.value) @@ -316,19 +393,49 @@ fits :: proc(width: int, list: ^[dynamic]Tuple) -> bool { } case Document_Nest_If_Break: if data.mode == .Break { - append(list, Tuple {indentation = data.indentation + 1, mode = data.mode, document = v.document, alignment = data.alignment}) + append( + list, + Tuple{ + indentation = data.indentation + 1, + mode = data.mode, + document = v.document, + alignment = data.alignment, + }, + ) } else { - append(list, Tuple {indentation = data.indentation, mode = data.mode, document = v.document, alignment = data.alignment}) + append( + list, + Tuple{ + indentation = data.indentation, + mode = data.mode, + document = v.document, + alignment = data.alignment, + }, + ) } case Document_Group: - append(list, Tuple {indentation = data.indentation, mode = (v.mode == .Break ? .Break : data.mode), document = v.document, alignment = data.alignment}) + append( + list, + Tuple{ + indentation = data.indentation, + mode = (v.mode == .Break ? .Break : data.mode), + document = v.document, + alignment = data.alignment, + }, + ) } } return width > 0 } -format_newline :: proc(indentation: int, alignment: int, consumed: ^int, builder: ^strings.Builder, p: ^Printer) { +format_newline :: proc( + indentation: int, + alignment: int, + consumed: ^int, + builder: ^strings.Builder, + p: ^Printer, +) { strings.write_string(builder, p.newline) for i := 0; i < indentation; i += 1 { strings.write_string(builder, p.indentation) @@ -340,17 +447,25 @@ format_newline :: proc(indentation: int, alignment: int, consumed: ^int, builder consumed^ = indentation * p.indentation_width + alignment } -flush_line_suffix :: proc(builder: ^strings.Builder, suffix_builder: ^strings.Builder) { +flush_line_suffix :: proc( + builder: ^strings.Builder, + suffix_builder: ^strings.Builder, +) { strings.write_string(builder, strings.to_string(suffix_builder^)) strings.builder_reset(suffix_builder) } -format :: proc(width: int, list: ^[dynamic]Tuple, builder: ^strings.Builder, p: ^Printer) { +format :: proc( + width: int, + list: ^[dynamic]Tuple, + builder: ^strings.Builder, + p: ^Printer, +) { assert(list != nil) assert(builder != nil) consumed := 0 - recalculate := false; + recalculate := false suffix_builder := strings.builder_make() @@ -361,8 +476,8 @@ format :: proc(width: int, list: ^[dynamic]Tuple, builder: ^strings.Builder, p: switch v in data.document { case Document_Nil: - case Document_Line_Suffix: - strings.write_string(&suffix_builder, v.value) + case Document_Line_Suffix: + strings.write_string(&suffix_builder, v.value) case Document_Break_Parent: case Document_Newline: if v.amount > 0 { @@ -376,36 +491,75 @@ format :: proc(width: int, list: ^[dynamic]Tuple, builder: ^strings.Builder, p: for i := 0; i < data.alignment; i += 1 { strings.write_string(builder, " ") } - consumed = data.indentation * p.indentation_width + data.alignment + consumed = + data.indentation * p.indentation_width + data.alignment if data.mode == .Flat { recalculate = true } - } + } case Document_Cons: for i := len(v.elements) - 1; i >= 0; i -= 1 { - append(list, Tuple {indentation = data.indentation, mode = data.mode, document = v.elements[i], alignment = data.alignment}) + append( + list, + Tuple{ + indentation = data.indentation, + mode = data.mode, + document = v.elements[i], + alignment = data.alignment, + }, + ) } case Document_Nest: if v.alignment != 0 { - append(list, Tuple {indentation = data.indentation, mode = data.mode, document = v.document, alignment = data.alignment + v.alignment}) + append( + list, + Tuple{ + indentation = data.indentation, + mode = data.mode, + document = v.document, + alignment = data.alignment + v.alignment, + }, + ) } else { - append(list, Tuple {indentation = data.indentation + (v.negate ? -1 : 1), mode = data.mode, document = v.document, alignment = data.alignment + v.alignment}) + append( + list, + Tuple{ + indentation = data.indentation + (v.negate ? -1 : 1), + mode = data.mode, + document = v.document, + alignment = data.alignment + v.alignment, + }, + ) } case Document_Align: - append(list, Tuple {indentation = 0, mode = data.mode, document = v.document, alignment = consumed}) + append( + list, + Tuple{ + indentation = 0, + mode = data.mode, + document = v.document, + alignment = consumed, + }, + ) case Document_Text: strings.write_string(builder, v.value) consumed += len(v.value) case Document_Break: if data.mode == .Break && v.newline { flush_line_suffix(builder, &suffix_builder) - format_newline(data.indentation, data.alignment, &consumed, builder, p) + format_newline( + data.indentation, + data.alignment, + &consumed, + builder, + p, + ) } else { strings.write_string(builder, v.value) consumed += len(v.value) - } + } case Document_If_Break: if data.mode == .Break { strings.write_string(builder, v.value) @@ -414,41 +568,103 @@ format :: proc(width: int, list: ^[dynamic]Tuple, builder: ^strings.Builder, p: case Document_Nest_If_Break: mode := v.group_id != "" ? p.group_modes[v.group_id] : data.mode if mode == .Break { - append(list, Tuple {indentation = data.indentation + 1, mode = data.mode, document = v.document, alignment = data.alignment}) + append( + list, + Tuple{ + indentation = data.indentation + 1, + mode = data.mode, + document = v.document, + alignment = data.alignment, + }, + ) } else { - append(list, Tuple {indentation = data.indentation, mode = data.mode, document = v.document, alignment = data.alignment}) + append( + list, + Tuple{ + indentation = data.indentation, + mode = data.mode, + document = v.document, + alignment = data.alignment, + }, + ) } case Document_Group: if data.mode == .Flat && !recalculate { - append(list, Tuple {indentation = data.indentation, mode = v.mode, document = v.document, alignment = data.alignment}) + append( + list, + Tuple{ + indentation = data.indentation, + mode = v.mode, + document = v.document, + alignment = data.alignment, + }, + ) break } clear(&list_fits) - + for element in list { append(&list_fits, element) } - append(&list_fits, Tuple {indentation = data.indentation, mode = .Fit, document = v.document, alignment = data.alignment}) + append( + &list_fits, + Tuple{ + indentation = data.indentation, + mode = .Fit, + document = v.document, + alignment = data.alignment, + }, + ) recalculate = false if data.mode == .Fit { - append(list, Tuple {indentation = data.indentation, mode = .Fit, document = v.document, alignment = data.alignment}) - } - else if fits(width-consumed, &list_fits) && v.mode != .Break { - append(list, Tuple {indentation = data.indentation, mode = .Flat, document = v.document, alignment = data.alignment}) + append( + list, + Tuple{ + indentation = data.indentation, + mode = .Fit, + document = v.document, + alignment = data.alignment, + }, + ) + } else if fits(width - consumed, &list_fits) && v.mode != .Break { + append( + list, + Tuple{ + indentation = data.indentation, + mode = .Flat, + document = v.document, + alignment = data.alignment, + }, + ) } else { if v.mode == .Fit { - append(list, Tuple {indentation = data.indentation, mode = .Fit, document = v.document, alignment = data.alignment}) + append( + list, + Tuple{ + indentation = data.indentation, + mode = .Fit, + document = v.document, + alignment = data.alignment, + }, + ) } else { - append(list, Tuple {indentation = data.indentation, mode = .Break, document = v.document, alignment = data.alignment}) + append( + list, + Tuple{ + indentation = data.indentation, + mode = .Break, + document = v.document, + alignment = data.alignment, + }, + ) } } - p.group_modes[v.options.id] = list[len(list)-1].mode + p.group_modes[v.options.id] = list[len(list) - 1].mode } } } - diff --git a/src/odin/printer/printer.odin b/src/odin/printer/printer.odin index 7c444a1..b033d68 100644 --- a/src/odin/printer/printer.odin +++ b/src/odin/printer/printer.odin @@ -30,20 +30,20 @@ Printer :: struct { } Disabled_Info :: struct { - text: string, + text: string, end_line: int, } Config :: struct { - character_width: int, - spaces: int, //Spaces per indentation - newline_limit: int, //The limit of newlines between statements and declarations. - tabs: bool, //Enable or disable tabs - tabs_width: int, - convert_do: bool, //Convert all do statements to brace blocks - brace_style: Brace_Style, - indent_cases: bool, - newline_style: Newline_Style, + character_width: int, + spaces: int, //Spaces per indentation + newline_limit: int, //The limit of newlines between statements and declarations. + tabs: bool, //Enable or disable tabs + tabs_width: int, + convert_do: bool, //Convert all do statements to brace blocks + brace_style: Brace_Style, + indent_cases: bool, + newline_style: Newline_Style, } Brace_Style :: enum { @@ -81,41 +81,41 @@ Line_Suffix_Option :: enum { } -when ODIN_OS == .Windows { +when ODIN_OS == .Windows { default_style := Config { - spaces = 4, - newline_limit = 2, - convert_do = false, - tabs = true, - tabs_width = 4, - brace_style = ._1TBS, - indent_cases = false, - newline_style = .CRLF, - character_width = 100, + spaces = 4, + newline_limit = 2, + convert_do = false, + tabs = true, + tabs_width = 4, + brace_style = ._1TBS, + indent_cases = false, + newline_style = .CRLF, + character_width = 100, } } else { default_style := Config { - spaces = 4, - newline_limit = 2, - convert_do = false, - tabs = true, - tabs_width = 4, - brace_style = ._1TBS, - indent_cases = false, - newline_style = .LF, - character_width = 100, + spaces = 4, + newline_limit = 2, + convert_do = false, + tabs = true, + tabs_width = 4, + brace_style = ._1TBS, + indent_cases = false, + newline_style = .LF, + character_width = 100, } } -make_printer :: proc(config: Config, allocator := context.allocator) -> Printer { - return { - config = config, - allocator = allocator, - } +make_printer :: proc( + config: Config, + allocator := context.allocator, +) -> Printer { + return {config = config, allocator = allocator} } -@private +@(private) build_disabled_lines_info :: proc(p: ^Printer) { found_disable := false disable_position: tokenizer.Pos @@ -125,27 +125,34 @@ build_disabled_lines_info :: proc(p: ^Printer) { if strings.contains(comment.text[:], "//odinfmt: disable") { found_disable = true disable_position = comment.pos - } else if strings.contains(comment.text[:], "//odinfmt: enable") && found_disable { + } else if strings.contains(comment.text[:], "//odinfmt: enable") && + found_disable { begin := disable_position.offset - (comment.pos.column - 1) - end := comment.pos.offset+len(comment.text) + end := comment.pos.offset + len(comment.text) disabled_info := Disabled_Info { end_line = comment.pos.line, - text = p.src[begin:end], + text = p.src[begin:end], } - for line := disable_position.line; line <= comment.pos.line; line += 1 { + for line := disable_position.line; + line <= comment.pos.line; + line += 1 { p.disabled_lines[line] = disabled_info } - + found_disable = false } } } } -@private -set_comment_option :: proc(p: ^Printer, line: int, option: Line_Suffix_Option) { +@(private) +set_comment_option :: proc( + p: ^Printer, + line: int, + option: Line_Suffix_Option, +) { p.comments_option[line] = option } @@ -155,17 +162,14 @@ print :: proc { } print_expr :: proc(p: ^Printer, expr: ^ast.Expr) -> string { - p.document = empty(); + p.document = empty() p.document = cons(p.document, visit_expr(p, expr)) p.string_builder = strings.builder_make(p.allocator) context.allocator = p.allocator list := make([dynamic]Tuple, p.allocator) - append(&list, Tuple { - document = p.document, - indentation = 0, - }) + append(&list, Tuple{document = p.document, indentation = 0}) format(p.config.character_width, &list, &p.string_builder, p) @@ -174,10 +178,10 @@ print_expr :: proc(p: ^Printer, expr: ^ast.Expr) -> string { print_file :: proc(p: ^Printer, file: ^ast.File) -> string { p.comments = file.comments - p.string_builder = strings.builder_make(0, len(file.src)*2, p.allocator) + p.string_builder = strings.builder_make(0, len(file.src) * 2, p.allocator) p.src = file.src context.allocator = p.allocator - + if p.config.tabs { p.indentation = "\t" p.indentation_width = p.config.tabs_width @@ -193,12 +197,15 @@ print_file :: proc(p: ^Printer, file: ^ast.File) -> string { } build_disabled_lines_info(p) - + p.source_position.line = 1 p.source_position.column = 1 p.document = move_line(p, file.pkg_token.pos) - p.document = cons(p.document, cons_with_nopl(text(file.pkg_token.text), text(file.pkg_name))) + p.document = cons( + p.document, + cons_with_nopl(text(file.pkg_token.text), text(file.pkg_name)), + ) for decl in file.decls { p.document = cons(p.document, visit_decl(p, cast(^ast.Decl)decl)) @@ -215,13 +222,9 @@ print_file :: proc(p: ^Printer, file: ^ast.File) -> string { list := make([dynamic]Tuple, p.allocator) - append(&list, Tuple { - document = p.document, - indentation = 0, - }) + append(&list, Tuple{document = p.document, indentation = 0}) format(p.config.character_width, &list, &p.string_builder, p) return strings.to_string(p.string_builder) } - diff --git a/src/odin/printer/visit.odin b/src/odin/printer/visit.odin index 43e4321..134c4ee 100644 --- a/src/odin/printer/visit.odin +++ b/src/odin/printer/visit.odin @@ -11,21 +11,23 @@ import "core:strconv" //right now the attribute order is not linearly parsed(bug?) @(private) sort_attribute :: proc(s: ^[dynamic]^ast.Attribute) -> sort.Interface { - return sort.Interface { - collection = rawptr(s), - len = proc(it: sort.Interface) -> int { - s := (^[dynamic]^ast.Attribute)(it.collection) - return len(s^) - }, - less = proc(it: sort.Interface, i, j: int) -> bool { - s := (^[dynamic]^ast.Attribute)(it.collection) - return s[i].pos.offset < s[j].pos.offset - }, - swap = proc(it: sort.Interface, i, j: int) { - s := (^[dynamic]^ast.Attribute)(it.collection) - s[i], s[j] = s[j], s[i] - }, - } + return( + sort.Interface{ + collection = rawptr(s), + len = proc(it: sort.Interface) -> int { + s := (^[dynamic]^ast.Attribute)(it.collection) + return len(s^) + }, + less = proc(it: sort.Interface, i, j: int) -> bool { + s := (^[dynamic]^ast.Attribute)(it.collection) + return s[i].pos.offset < s[j].pos.offset + }, + swap = proc(it: sort.Interface, i, j: int) { + s := (^[dynamic]^ast.Attribute)(it.collection) + s[i], s[j] = s[j], s[i] + }, + } \ + ) } @(private) @@ -62,13 +64,21 @@ text_token :: proc(p: ^Printer, token: tokenizer.Token) -> ^Document { } @(private) -text_position :: proc(p: ^Printer, value: string, pos: tokenizer.Pos) -> ^Document { +text_position :: proc( + p: ^Printer, + value: string, + pos: tokenizer.Pos, +) -> ^Document { document, _ := visit_comments(p, pos) return cons(document, text(value)) } @(private) -newline_position :: proc(p: ^Printer, amount: int, pos: tokenizer.Pos) -> ^Document { +newline_position :: proc( + p: ^Printer, + amount: int, + pos: tokenizer.Pos, +) -> ^Document { document, _ := visit_comments(p, pos) return cons(document, newline(amount)) } @@ -80,12 +90,19 @@ set_source_position :: proc(p: ^Printer, pos: tokenizer.Pos) { @(private) move_line :: proc(p: ^Printer, pos: tokenizer.Pos) -> ^Document { - l, _ := move_line_limit(p, pos, p.config.newline_limit+1) + l, _ := move_line_limit(p, pos, p.config.newline_limit + 1) return l } @(private) -move_line_limit :: proc(p: ^Printer, pos: tokenizer.Pos, limit: int) -> (^Document, bool) { +move_line_limit :: proc( + p: ^Printer, + pos: tokenizer.Pos, + limit: int, +) -> ( + ^Document, + bool, +) { lines := pos.line - p.source_position.line if lines < 0 { @@ -96,18 +113,30 @@ move_line_limit :: proc(p: ^Printer, pos: tokenizer.Pos, limit: int) -> (^Docume p.source_position = pos - return cons(document, newline(max(min(lines-comments_newlined, limit), 0))), lines > 0 + return cons( + document, + newline(max(min(lines - comments_newlined, limit), 0)), + ), lines > 0 } @(private) -visit_comment :: proc(p: ^Printer, comment: tokenizer.Token) -> (int, ^Document) { +visit_comment :: proc( + p: ^Printer, + comment: tokenizer.Token, +) -> ( + int, + ^Document, +) { document := empty() if len(comment.text) == 0 { return 0, document } - + newlines_before_comment := comment.pos.line - p.source_position.line - newlines_before_comment_limited := min(newlines_before_comment, p.config.newline_limit + 1) + newlines_before_comment_limited := min( + newlines_before_comment, + p.config.newline_limit + 1, + ) document = cons(document, newline(newlines_before_comment_limited)) @@ -115,33 +144,45 @@ visit_comment :: proc(p: ^Printer, comment: tokenizer.Token) -> (int, ^Document) if comment.pos.line in p.disabled_lines { p.source_position = comment.pos return 1, empty() - } else if comment.pos.line == p.source_position.line && p.source_position.column != 1 { + } else if comment.pos.line == p.source_position.line && + p.source_position.column != 1 { p.source_position = comment.pos - if comment_option, exist := p.comments_option[comment.pos.line]; exist && comment_option == .Indent { + if comment_option, exist := p.comments_option[comment.pos.line]; + exist && comment_option == .Indent { delete_key(&p.comments_option, comment.pos.line) - return newlines_before_comment, cons_with_nopl(document, cons(text(p.indentation), line_suffix(comment.text))) + return newlines_before_comment, cons_with_nopl( + document, + cons(text(p.indentation), line_suffix(comment.text)), + ) } else { - return newlines_before_comment, cons_with_nopl(document, line_suffix(comment.text)) + return newlines_before_comment, cons_with_nopl( + document, + line_suffix(comment.text), + ) } } else { p.source_position = comment.pos - return newlines_before_comment, cons(document, line_suffix(comment.text)) + return newlines_before_comment, cons( + document, + line_suffix(comment.text), + ) } - } else { + } else { newlines := strings.count(comment.text, "\n") if comment.pos.line in p.disabled_lines { p.source_position = comment.pos p.source_position.line += newlines return 1, empty() - } else if comment.pos.line == p.source_position.line && p.source_position.column != 1 { + } else if comment.pos.line == p.source_position.line && + p.source_position.column != 1 { p.source_position = comment.pos p.source_position.line += newlines - return newlines_before_comment+newlines, cons_with_opl(document, text(comment.text)) + return newlines_before_comment + newlines, cons_with_opl(document, text(comment.text)) } else { p.source_position = comment.pos p.source_position.line += newlines - return newlines_before_comment+newlines, cons(document, text(comment.text)) + return newlines_before_comment + newlines, cons(document, text(comment.text)) } return 0, document @@ -170,7 +211,7 @@ visit_comments :: proc(p: ^Printer, pos: tokenizer.Pos) -> (^Document, int) { @(private) visit_disabled :: proc(p: ^Printer, node: ^ast.Node) -> ^Document { - + if node.pos.line not_in p.disabled_lines { return empty() } @@ -198,9 +239,13 @@ visit_disabled :: proc(p: ^Printer, node: ^ast.Node) -> ^Document { } @(private) -visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) -> ^Document { +visit_decl :: proc( + p: ^Printer, + decl: ^ast.Decl, + called_in_stmt := false, +) -> ^Document { using ast - + if decl == nil { return empty() } @@ -222,14 +267,23 @@ visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) -> ^Do case ^Foreign_Import_Decl: document := empty() if len(v.attributes) > 0 { - document = cons(document, visit_attributes(p, &v.attributes, v.pos)) + document = cons( + document, + visit_attributes(p, &v.attributes, v.pos), + ) } document = cons(document, move_line(p, decl.pos)) - document = cons(document, cons_with_opl(text(v.foreign_tok.text), text(v.import_tok.text))) + document = cons( + document, + cons_with_opl(text(v.foreign_tok.text), text(v.import_tok.text)), + ) if v.name != nil { - document = cons_with_opl(document, text_position(p, v.name.name, v.pos)) + document = cons_with_opl( + document, + text_position(p, v.name.name, v.pos), + ) } if len(v.fullpaths) > 1 { @@ -238,7 +292,7 @@ visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) -> ^Do document = cons(document, text(path)) if i != len(v.fullpaths) - 1 { document = cons(document, text(","), break_with_space()) - } + } } document = cons(document, text("}")) } else if len(v.fullpaths) == 1 { @@ -249,11 +303,17 @@ visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) -> ^Do case ^Foreign_Block_Decl: document := empty() if len(v.attributes) > 0 { - document = cons(document, visit_attributes(p, &v.attributes, v.pos)) + document = cons( + document, + visit_attributes(p, &v.attributes, v.pos), + ) } document = cons(document, move_line(p, decl.pos)) - document = cons(document, cons_with_opl(text("foreign"), visit_expr(p, v.foreign_library))) + document = cons( + document, + cons_with_opl(text("foreign"), visit_expr(p, v.foreign_library)), + ) document = cons_with_nopl(document, visit_stmt(p, v.body)) return document case ^Import_Decl: @@ -274,7 +334,10 @@ visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) -> ^Do case ^Value_Decl: document := empty() if len(v.attributes) > 0 { - document = cons(document, visit_attributes(p, &v.attributes, v.pos)) + document = cons( + document, + visit_attributes(p, &v.attributes, v.pos), + ) } document = cons(document, move_line(p, decl.pos)) @@ -306,22 +369,49 @@ visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) -> ^Do lhs = cons(lhs, text("=")) } - rhs = cons_with_nopl(rhs, visit_exprs(p, v.values, {.Add_Comma}, .Value_Decl)) + rhs = cons_with_nopl( + rhs, + visit_exprs(p, v.values, {.Add_Comma}, .Value_Decl), + ) } else if len(v.values) > 0 && v.type != nil { - rhs = cons_with_nopl(rhs, cons_with_nopl(text(":"), visit_exprs(p, v.values, {.Add_Comma}))) + rhs = cons_with_nopl( + rhs, + cons_with_nopl( + text(":"), + visit_exprs(p, v.values, {.Add_Comma}), + ), + ) } else { - rhs = cons_with_nopl(rhs, visit_exprs(p, v.values, {.Add_Comma}, .Value_Decl)) + rhs = cons_with_nopl( + rhs, + visit_exprs(p, v.values, {.Add_Comma}, .Value_Decl), + ) } if len(v.values) > 0 { if is_values_nestable_assign(v.values) { - return cons(document, group(nest(cons_with_opl(lhs, group(rhs))))) + return cons( + document, + group(nest(cons_with_opl(lhs, group(rhs)))), + ) } else if is_values_nestable_if_break_assign(v.values) { - assignments := cons(lhs, group(nest(break_with_space()), Document_Group_Options { id = "assignments"})) - assignments = cons(assignments, nest_if_break(group(rhs), "assignments")) + assignments := cons( + lhs, + group( + nest(break_with_space()), + Document_Group_Options{id = "assignments"}, + ), + ) + assignments = cons( + assignments, + nest_if_break(group(rhs), "assignments"), + ) return cons(document, group(assignments)) } else { - return cons(document, group(cons_with_nopl(group(lhs), group(rhs)))) + return cons( + document, + group(cons_with_nopl(group(lhs), group(rhs))), + ) } } else { return cons(document, group(lhs)) @@ -338,7 +428,7 @@ exprs_contain_empty_idents :: proc(list: []^ast.Expr) -> bool { for expr in list { if ident, ok := expr.derived.(^ast.Ident); ok && ident.name == "_" { continue - } + } return false } return true @@ -350,11 +440,11 @@ is_call_expr_nestable :: proc(list: []^ast.Expr) -> bool { return true } - #partial switch v in list[len(list)-1].derived { + #partial switch v in list[len(list) - 1].derived { case ^ast.Comp_Lit, ^ast.Proc_Type, ^ast.Proc_Lit: return false } - + return true } @@ -366,9 +456,8 @@ is_values_nestable_assign :: proc(list: []^ast.Expr) -> bool { for expr in list { #partial switch v in expr.derived { - case ^ast.Ident, ^ast.Binary_Expr, ^ast.Index_Expr, ^ast.Selector_Expr, ^ast.Paren_Expr, - ^ast.Ternary_If_Expr, ^ast.Ternary_When_Expr, ^ast.Or_Else_Expr: - return true + case ^ast.Ident, ^ast.Binary_Expr, ^ast.Index_Expr, ^ast.Selector_Expr, ^ast.Paren_Expr, ^ast.Ternary_If_Expr, ^ast.Ternary_When_Expr, ^ast.Or_Else_Expr: + return true } } return false @@ -388,28 +477,32 @@ is_values_return_stmt_callable :: proc(list: []^ast.Expr) -> bool { } #partial switch v in result.derived { - case ^ast.Call_Expr: - return false + case ^ast.Call_Expr: + return false } } return true } - @(private) is_values_nestable_if_break_assign :: proc(list: []^ast.Expr) -> bool { for expr in list { #partial switch v in expr.derived { - case ^ast.Call_Expr, ^ast.Comp_Lit, ^ast.Or_Return_Expr: - return true + case ^ast.Call_Expr, ^ast.Comp_Lit, ^ast.Or_Return_Expr: + return true } } return false } @(private) -visit_exprs :: proc(p: ^Printer, list: []^ast.Expr, options := List_Options{}, called_from: Expr_Called_Type = .Generic) -> ^Document { +visit_exprs :: proc( + p: ^Printer, + list: []^ast.Expr, + options := List_Options{}, + called_from: Expr_Called_Type = .Generic, +) -> ^Document { if len(list) == 0 { return empty() } @@ -420,19 +513,35 @@ visit_exprs :: proc(p: ^Printer, list: []^ast.Expr, options := List_Options{}, c p.source_position = expr.pos if .Enforce_Newline in options { - document = cons(document, .Group in options ? group(visit_expr(p, expr, called_from, options)) : visit_expr(p, expr, called_from, options)) + document = cons( + document, + .Group in options \ + ? group(visit_expr(p, expr, called_from, options)) \ + : visit_expr(p, expr, called_from, options), + ) } else if .Glue in options { - document = cons_with_nopl(document, .Group in options ? group(visit_expr(p, expr, called_from, options)) : visit_expr(p, expr, called_from, options)) + document = cons_with_nopl( + document, + .Group in options \ + ? group(visit_expr(p, expr, called_from, options)) \ + : visit_expr(p, expr, called_from, options), + ) } else { - document = cons_with_opl(document, .Group in options ? group(visit_expr(p, expr, called_from, options)) : visit_expr(p, expr, called_from, options)) + document = cons_with_opl( + document, + .Group in options \ + ? group(visit_expr(p, expr, called_from, options)) \ + : visit_expr(p, expr, called_from, options), + ) } - if (i != len(list) - 1 || .Trailing in options) && .Add_Comma in options { + if (i != len(list) - 1 || .Trailing in options) && + .Add_Comma in options { document = cons(document, text(",")) } if (i != len(list) - 1 && .Enforce_Newline in options) { - comment, _ := visit_comments(p, list[i+1].pos) + comment, _ := visit_comments(p, list[i + 1].pos) document = cons(document, comment, newline(1)) } else if .Enforce_Newline in options { comment, _ := visit_comments(p, list[i].end) @@ -444,7 +553,11 @@ visit_exprs :: proc(p: ^Printer, list: []^ast.Expr, options := List_Options{}, c } @(private) -visit_enum_exprs :: proc(p: ^Printer, enum_type: ast.Enum_Type, options := List_Options{}) -> ^Document { +visit_enum_exprs :: proc( + p: ^Printer, + enum_type: ast.Enum_Type, + options := List_Options{}, +) -> ^Document { if len(enum_type.fields) == 0 { return empty() } @@ -453,7 +566,7 @@ visit_enum_exprs :: proc(p: ^Printer, enum_type: ast.Enum_Type, options := List_ for expr, i in enum_type.fields { if i == 0 && .Enforce_Newline in options { - comment, _ := visit_comments(p, enum_type.fields[i].pos) + comment, _ := visit_comments(p, enum_type.fields[i].pos) if _, is_nil := comment.(Document_Nil); !is_nil { comment = cons(comment, newline(1)) } @@ -463,21 +576,44 @@ visit_enum_exprs :: proc(p: ^Printer, enum_type: ast.Enum_Type, options := List_ if (.Enforce_Newline in options) { alignment := get_possible_enum_alignment(enum_type.fields) - if value, ok := expr.derived.(^ast.Field_Value); ok && alignment > 0 { - document = cons(document, cons_with_nopl(visit_expr(p, value.field), cons_with_nopl(cons(repeat_space(alignment - get_node_length(value.field)), text_position(p, "=", value.sep)), visit_expr(p, value.value)))) + if value, ok := expr.derived.(^ast.Field_Value); + ok && alignment > 0 { + document = cons( + document, + cons_with_nopl( + visit_expr(p, value.field), + cons_with_nopl( + cons( + repeat_space( + alignment - get_node_length(value.field), + ), + text_position(p, "=", value.sep), + ), + visit_expr(p, value.value), + ), + ), + ) } else { - document = group(cons(document, visit_expr(p, expr, .Generic, options))) + document = group( + cons(document, visit_expr(p, expr, .Generic, options)), + ) } } else { - document = group(cons_with_opl(document, visit_expr(p, expr, .Generic, options))) + document = group( + cons_with_opl( + document, + visit_expr(p, expr, .Generic, options), + ), + ) } - if (i != len(enum_type.fields) - 1 || .Trailing in options) && .Add_Comma in options { + if (i != len(enum_type.fields) - 1 || .Trailing in options) && + .Add_Comma in options { document = cons(document, text(",")) } if (i != len(enum_type.fields) - 1 && .Enforce_Newline in options) { - comment, _ := visit_comments(p, enum_type.fields[i+1].pos) + comment, _ := visit_comments(p, enum_type.fields[i + 1].pos) document = cons(document, comment, newline(1)) } else if .Enforce_Newline in options { comment, _ := visit_comments(p, enum_type.end) @@ -489,7 +625,11 @@ visit_enum_exprs :: proc(p: ^Printer, enum_type: ast.Enum_Type, options := List_ } @(private) -visit_union_exprs :: proc(p: ^Printer, union_type: ast.Union_Type, options := List_Options{}) -> ^Document { +visit_union_exprs :: proc( + p: ^Printer, + union_type: ast.Union_Type, + options := List_Options{}, +) -> ^Document { if len(union_type.variants) == 0 { return empty() } @@ -498,7 +638,7 @@ visit_union_exprs :: proc(p: ^Printer, union_type: ast.Union_Type, options := Li for expr, i in union_type.variants { if i == 0 && .Enforce_Newline in options { - comment, _ := visit_comments(p, union_type.variants[i].pos) + comment, _ := visit_comments(p, union_type.variants[i].pos) if _, is_nil := comment.(Document_Nil); !is_nil { comment = cons(comment, newline(1)) } @@ -508,21 +648,44 @@ visit_union_exprs :: proc(p: ^Printer, union_type: ast.Union_Type, options := Li if (.Enforce_Newline in options) { alignment := get_possible_enum_alignment(union_type.variants) - if value, ok := expr.derived.(^ast.Field_Value); ok && alignment > 0 { - document = cons(document, cons_with_nopl(visit_expr(p, value.field), cons_with_nopl(cons(repeat_space(alignment - get_node_length(value.field)), text_position(p, "=", value.sep)), visit_expr(p, value.value)))) + if value, ok := expr.derived.(^ast.Field_Value); + ok && alignment > 0 { + document = cons( + document, + cons_with_nopl( + visit_expr(p, value.field), + cons_with_nopl( + cons( + repeat_space( + alignment - get_node_length(value.field), + ), + text_position(p, "=", value.sep), + ), + visit_expr(p, value.value), + ), + ), + ) } else { - document = group(cons(document, visit_expr(p, expr, .Generic, options))) + document = group( + cons(document, visit_expr(p, expr, .Generic, options)), + ) } } else { - document = group(cons_with_opl(document, visit_expr(p, expr, .Generic, options))) + document = group( + cons_with_opl( + document, + visit_expr(p, expr, .Generic, options), + ), + ) } - if (i != len(union_type.variants) - 1 || .Trailing in options) && .Add_Comma in options { + if (i != len(union_type.variants) - 1 || .Trailing in options) && + .Add_Comma in options { document = cons(document, text(",")) } if (i != len(union_type.variants) - 1 && .Enforce_Newline in options) { - comment, _ := visit_comments(p, union_type.variants[i+1].pos) + comment, _ := visit_comments(p, union_type.variants[i + 1].pos) document = cons(document, comment, newline(1)) } else if .Enforce_Newline in options { comment, _ := visit_comments(p, union_type.end) @@ -534,7 +697,11 @@ visit_union_exprs :: proc(p: ^Printer, union_type: ast.Union_Type, options := Li } @(private) -visit_comp_lit_exprs :: proc(p: ^Printer, comp_lit: ast.Comp_Lit, options := List_Options{}) -> ^Document { +visit_comp_lit_exprs :: proc( + p: ^Printer, + comp_lit: ast.Comp_Lit, + options := List_Options{}, +) -> ^Document { if len(comp_lit.elems) == 0 { return empty() } @@ -543,7 +710,7 @@ visit_comp_lit_exprs :: proc(p: ^Printer, comp_lit: ast.Comp_Lit, options := Lis for expr, i in comp_lit.elems { if i == 0 && .Enforce_Newline in options { - comment, _ := visit_comments(p, comp_lit.elems[i].pos) + comment, _ := visit_comments(p, comp_lit.elems[i].pos) if _, is_nil := comment.(Document_Nil); !is_nil { comment = cons(comment, newline(1)) } @@ -552,25 +719,45 @@ visit_comp_lit_exprs :: proc(p: ^Printer, comp_lit: ast.Comp_Lit, options := Lis if (.Enforce_Newline in options) { alignment := get_possible_comp_lit_alignment(comp_lit.elems) - if value, ok := expr.derived.(^ast.Field_Value); ok && alignment > 0 { + if value, ok := expr.derived.(^ast.Field_Value); + ok && alignment > 0 { align := empty() if should_align_comp_lit(p, comp_lit) { - align = repeat_space(alignment - get_node_length(value.field)) + align = repeat_space( + alignment - get_node_length(value.field), + ) } - document = cons(document, cons_with_nopl(visit_expr(p, value.field), cons_with_nopl(cons(align, text_position(p, "=", value.sep)), visit_expr(p, value.value)))) + document = cons( + document, + cons_with_nopl( + visit_expr(p, value.field), + cons_with_nopl( + cons(align, text_position(p, "=", value.sep)), + visit_expr(p, value.value), + ), + ), + ) } else { - document = group(cons(document, visit_expr(p, expr, .Generic, options))) + document = group( + cons(document, visit_expr(p, expr, .Generic, options)), + ) } } else { - document = group(cons_with_nopl(document, visit_expr(p, expr, .Generic, options))) + document = group( + cons_with_nopl( + document, + visit_expr(p, expr, .Generic, options), + ), + ) } - if (i != len(comp_lit.elems) - 1 || .Trailing in options) && .Add_Comma in options { + if (i != len(comp_lit.elems) - 1 || .Trailing in options) && + .Add_Comma in options { document = cons(document, text(",")) } if (i != len(comp_lit.elems) - 1 && .Enforce_Newline in options) { - comment, _ := visit_comments(p, comp_lit.elems[i+1].pos) + comment, _ := visit_comments(p, comp_lit.elems[i + 1].pos) document = cons(document, comment, newline(1)) } else if .Enforce_Newline in options { comment, _ := visit_comments(p, comp_lit.end) @@ -582,7 +769,11 @@ visit_comp_lit_exprs :: proc(p: ^Printer, comp_lit: ast.Comp_Lit, options := Lis } @(private) -visit_attributes :: proc(p: ^Printer, attributes: ^[dynamic]^ast.Attribute, pos: tokenizer.Pos) -> ^Document { +visit_attributes :: proc( + p: ^Printer, + attributes: ^[dynamic]^ast.Attribute, + pos: tokenizer.Pos, +) -> ^Document { document := empty() if len(attributes) == 0 { return document @@ -592,7 +783,13 @@ visit_attributes :: proc(p: ^Printer, attributes: ^[dynamic]^ast.Attribute, pos: document = cons(document, move_line(p, attributes[0].pos)) for attribute, i in attributes { - document = cons(document, text("@"), text("("), visit_exprs(p, attribute.elems, {.Add_Comma}), text(")")) + document = cons( + document, + text("@"), + text("("), + visit_exprs(p, attribute.elems, {.Add_Comma}), + text(")"), + ) // document = cons(document, visit_exprs(p, attribute.elems, {.Add_Comma})) // document = cons(document, text(")")) @@ -607,7 +804,10 @@ visit_attributes :: proc(p: ^Printer, attributes: ^[dynamic]^ast.Attribute, pos: } @(private) -visit_state_flags :: proc(p: ^Printer, flags: ast.Node_State_Flags) -> ^Document { +visit_state_flags :: proc( + p: ^Printer, + flags: ast.Node_State_Flags, +) -> ^Document { if .No_Bounds_Check in flags { return cons(text("#no_bounds_check"), break_with_no_newline()) } @@ -622,14 +822,20 @@ enforce_fit_if_do :: proc(stmt: ^ast.Stmt, document: ^Document) -> ^Document { if v, ok := stmt.derived.(^ast.Block_Stmt); ok { if v.uses_do { return enforce_fit(document) - } + } } return document } @(private) -visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Generic, empty_block := false, block_stmt := false) -> ^Document { +visit_stmt :: proc( + p: ^Printer, + stmt: ^ast.Stmt, + block_type: Block_Type = .Generic, + empty_block := false, + block_stmt := false, +) -> ^Document { using ast if stmt == nil { @@ -642,7 +848,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener #partial switch v in stmt.derived { case ^Import_Decl: - return visit_decl(p, cast(^Decl)stmt, true) + return visit_decl(p, cast(^Decl)stmt, true) case ^Value_Decl: return visit_decl(p, cast(^Decl)stmt, true) case ^Foreign_Import_Decl: @@ -656,20 +862,38 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener #partial switch v in stmt.derived { case ^Using_Stmt: - document = cons(document, cons_with_nopl(text("using"), visit_exprs(p, v.list, {.Add_Comma}))) - case ^Block_Stmt: + document = cons( + document, + cons_with_nopl( + text("using"), + visit_exprs(p, v.list, {.Add_Comma}), + ), + ) + case ^Block_Stmt: uses_do := v.uses_do if v.label != nil { - document = cons(document,visit_expr(p, v.label), text(":"), break_with_space()) + document = cons( + document, + visit_expr(p, v.label), + text(":"), + break_with_space(), + ) } if .Bounds_Check in v.state_flags { - document = cons(document, text("#bounds_check"), break_with_space()) + document = cons( + document, + text("#bounds_check"), + break_with_space(), + ) } if !uses_do { - document = cons(document, visit_begin_brace(p, v.pos, block_type, len(v.stmts))) + document = cons( + document, + visit_begin_brace(p, v.pos, block_type, len(v.stmts)), + ) } else { document = cons(document, text("do"), break_with(" ", false)) } @@ -677,7 +901,10 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener set_source_position(p, v.pos) block := visit_block_stmts(p, v.stmts, len(v.stmts) > 1) - comment_end, _ := visit_comments(p, tokenizer.Pos {line = v.end.line, offset = v.end.offset}) + comment_end, _ := visit_comments( + p, + tokenizer.Pos{line = v.end.line, offset = v.end.offset}, + ) if block_type == .Switch_Stmt && !p.config.indent_cases { document = cons(document, block, comment_end) @@ -690,19 +917,33 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener } case ^If_Stmt: if v.label != nil { - document = cons(document, visit_expr(p, v.label), text(":"), break_with_space()) + document = cons( + document, + visit_expr(p, v.label), + text(":"), + break_with_space(), + ) } if_document := text("if") if v.init != nil { - if_document = cons_with_nopl(if_document, cons(group(visit_stmt(p, v.init)), text(";"))) + if_document = cons_with_nopl( + if_document, + cons(group(visit_stmt(p, v.init)), text(";")), + ) } if v.cond != nil && v.init != nil { - if_document = cons(if_document, group(cons(break_with_space(), visit_expr(p, v.cond)))) + if_document = cons( + if_document, + group(cons(break_with_space(), group(visit_expr(p, v.cond)))), + ) } else if v.cond != nil { - if_document = cons_with_nopl(if_document, group(visit_expr(p, v.cond))) + if_document = cons_with_nopl( + if_document, + group(visit_expr(p, v.cond)), + ) } document = cons(document, group(hang(3, if_document))) @@ -714,28 +955,40 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener set_source_position(p, v.body.end) if v.else_stmt != nil { - if p.config.brace_style == .Allman || p.config.brace_style == .Stroustrup { + if p.config.brace_style == .Allman || + p.config.brace_style == .Stroustrup { document = cons(document, newline(1)) } set_source_position(p, v.else_stmt.pos) if _, ok := v.else_stmt.derived.(^ast.If_Stmt); ok { - document = cons_with_opl(document, cons_with_nopl(text("else"), visit_stmt(p, v.else_stmt))) + document = cons_with_opl( + document, + cons_with_nopl(text("else"), visit_stmt(p, v.else_stmt)), + ) } else { - document = cons_with_opl(document, cons_with_nopl(text("else"), visit_stmt(p, v.else_stmt))) + document = cons_with_opl( + document, + cons_with_nopl(text("else"), visit_stmt(p, v.else_stmt)), + ) } } document = enforce_fit_if_do(v.body, document) - case ^Switch_Stmt: - if v.label != nil { - document = cons(document, visit_expr(p, v.label), text(":"), break_with_space()) - } - + case ^Switch_Stmt: if v.partial { document = cons(document, text("#partial"), break_with_space()) } + if v.label != nil { + document = cons( + document, + visit_expr(p, v.label), + text(":"), + break_with_space(), + ) + } + document = cons(document, text("switch")) if v.init != nil { @@ -747,47 +1000,78 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener } document = cons_with_opl(document, visit_expr(p, v.cond)) - document = cons_with_nopl(document, visit_stmt(p, v.body, .Switch_Stmt)) + document = cons_with_nopl( + document, + visit_stmt(p, v.body, .Switch_Stmt), + ) case ^Case_Clause: document = cons(document, text("case")) if v.list != nil { - document = cons_with_nopl(document, visit_exprs(p, v.list, {.Add_Comma})) + document = cons_with_nopl( + document, + visit_exprs(p, v.list, {.Add_Comma}), + ) } document = cons(document, text(v.terminator.text)) if len(v.body) != 0 { set_source_position(p, v.body[0].pos) - document = cons(document, nest(cons(newline(1), visit_block_stmts(p, v.body)))) + document = cons( + document, + nest(cons(newline(1), visit_block_stmts(p, v.body))), + ) } case ^Type_Switch_Stmt: - if v.label != nil { - document = cons(document, visit_expr(p, v.label), text(":"), break_with_space()) - } - if v.partial { document = cons(document, text("#partial"), break_with_space()) } + if v.label != nil { + document = cons( + document, + visit_expr(p, v.label), + text(":"), + break_with_space(), + ) + } + document = cons(document, text("switch")) document = cons_with_nopl(document, visit_stmt(p, v.tag, .Switch_Stmt)) - document = cons_with_nopl(document, visit_stmt(p, v.body, .Switch_Stmt)) + document = cons_with_nopl( + document, + visit_stmt(p, v.body, .Switch_Stmt), + ) case ^Assign_Stmt: assign_document: ^Document //If the switch contains `switch in v` - if exprs_contain_empty_idents(v.lhs) && block_type == .Switch_Stmt { + if exprs_contain_empty_idents(v.lhs) && block_type == .Switch_Stmt { assign_document = cons(document, text(v.op.text)) } else { - assign_document = cons(document, group(cons(visit_exprs(p, v.lhs, {.Add_Comma, .Glue}), cons(text(" "), text(v.op.text))))) + assign_document = cons( + document, + group( + cons( + visit_exprs(p, v.lhs, {.Add_Comma, .Glue}), + cons(text(" "), text(v.op.text)), + ), + ), + ) } rhs := visit_exprs(p, v.rhs, {.Add_Comma}, .Assignment_Stmt) if is_values_nestable_assign(v.rhs) { document = group(nest(cons_with_opl(assign_document, group(rhs)))) } else if is_values_nestable_if_break_assign(v.rhs) { - document = cons(assign_document, group(nest(break_with_space()), Document_Group_Options { id = "assignments"})) + document = cons( + assign_document, + group( + nest(break_with_space()), + Document_Group_Options{id = "assignments"}, + ), + ) document = cons(document, nest_if_break(group(rhs), "assignments")) document = group(document) } else { @@ -797,27 +1081,41 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener document = cons(document, visit_expr(p, v.expr)) case ^For_Stmt: if v.label != nil { - document = cons(document, visit_expr(p, v.label), text(":"), break_with_space()) + document = cons( + document, + visit_expr(p, v.label), + text(":"), + break_with_space(), + ) } for_document := text("for") if v.init != nil { set_source_position(p, v.init.pos) - for_document = cons_with_nopl(for_document, cons(group(visit_stmt(p, v.init)), text(";"))) + for_document = cons_with_nopl( + for_document, + cons(group(visit_stmt(p, v.init)), text(";")), + ) } else if v.post != nil { for_document = cons_with_nopl(for_document, text(";")) } if v.cond != nil { set_source_position(p, v.cond.pos) - for_document = cons_with_opl(for_document, group(visit_expr(p, v.cond))) + for_document = cons_with_opl( + for_document, + group(visit_expr(p, v.cond)), + ) } if v.post != nil { set_source_position(p, v.post.pos) for_document = cons(for_document, text(";")) - for_document = cons_with_opl(for_document, group(visit_stmt(p, v.post))) + for_document = cons_with_opl( + for_document, + group(visit_stmt(p, v.post)), + ) } else if v.post == nil && v.cond != nil && v.init != nil { for_document = cons(for_document, text(";")) } @@ -825,13 +1123,18 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener document = cons(document, group(hang(4, for_document))) set_source_position(p, v.body.pos) - document = cons_with_nopl(document, visit_stmt(p, v.body)) + document = cons_with_nopl(document, visit_stmt(p, v.body)) set_source_position(p, v.body.end) document = enforce_fit_if_do(v.body, document) case ^Inline_Range_Stmt: if v.label != nil { - document = cons(document, visit_expr(p, v.label), text(":"), break_with_space()) + document = cons( + document, + visit_expr(p, v.label), + text(":"), + break_with_space(), + ) } document = cons(document, text("#unroll")) @@ -840,7 +1143,10 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener document = cons_with_nopl(document, visit_expr(p, v.val0)) if v.val1 != nil { - document = cons(document, cons_with_opl(text(","), visit_expr(p, v.val1))) + document = cons( + document, + cons_with_opl(text(","), visit_expr(p, v.val1)), + ) } document = cons_with_nopl(document, text("in")) @@ -848,13 +1154,18 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener document = cons_with_nopl(document, visit_expr(p, v.expr)) set_source_position(p, v.body.pos) - document = cons_with_nopl(document, visit_stmt(p, v.body)) + document = cons_with_nopl(document, visit_stmt(p, v.body)) set_source_position(p, v.body.end) document = enforce_fit_if_do(v.body, document) case ^Range_Stmt: if v.label != nil { - document = cons(document, visit_expr(p, v.label), text(":"), break_with_space()) + document = cons( + document, + visit_expr(p, v.label), + text(":"), + break_with_space(), + ) } document = cons(document, text("for")) @@ -864,15 +1175,18 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener } if len(v.vals) >= 2 { - document = cons(document, cons_with_opl(text(","), visit_expr(p, v.vals[1]))) + document = cons( + document, + cons_with_opl(text(","), visit_expr(p, v.vals[1])), + ) } document = cons_with_opl(document, text("in")) document = cons_with_opl(document, visit_expr(p, v.expr)) - + set_source_position(p, v.body.pos) - document = cons_with_nopl(document, visit_stmt(p, v.body)) + document = cons_with_nopl(document, visit_stmt(p, v.body)) set_source_position(p, v.body.end) document = enforce_fit_if_do(v.body, document) @@ -896,11 +1210,16 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener visit_expr(p, result), ) - document = nest(document) - document = group(cons(document, if_break(" \\"), break_with(""), if_break(")"))) + document = nest(document) + document = group( + cons(document, if_break(" \\"), break_with(""), if_break(")")), + ) } else { document = cons(document, text("return")) - document = cons_with_nopl(document, visit_exprs(p, v.results, {.Add_Comma})) + document = cons_with_nopl( + document, + visit_exprs(p, v.results, {.Add_Comma}), + ) } @@ -908,7 +1227,10 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener document = cons(document, text("defer")) document = cons_with_nopl(document, visit_stmt(p, v.stmt)) case ^When_Stmt: - document = cons(document, cons_with_nopl(text("when"), visit_expr(p, v.cond))) + document = cons( + document, + cons_with_nopl(text("when"), visit_expr(p, v.cond)), + ) document = cons_with_nopl(document, visit_stmt(p, v.body)) @@ -919,7 +1241,10 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener set_source_position(p, v.else_stmt.pos) - document = cons_with_nopl(document, cons_with_nopl(text("else"), visit_stmt(p, v.else_stmt))) + document = cons_with_nopl( + document, + cons_with_nopl(text("else"), visit_stmt(p, v.else_stmt)), + ) } case ^Branch_Stmt: document = cons(document, text(v.tok.text)) @@ -945,12 +1270,12 @@ should_align_comp_lit :: proc(p: ^Printer, comp_lit: ast.Comp_Lit) -> bool { for expr in comp_lit.elems { if field, ok := expr.derived.(^ast.Field_Value); ok { #partial switch v in field.value.derived { - case ^ast.Proc_Type, ^ast.Proc_Lit: - return false + case ^ast.Proc_Type, ^ast.Proc_Lit: + return false } } } - + return true } @@ -966,7 +1291,7 @@ comp_lit_contains_fields :: proc(p: ^Printer, comp_lit: ast.Comp_Lit) -> bool { return true } } - + return false } @@ -979,17 +1304,21 @@ comp_lit_contains_blocks :: proc(p: ^Printer, comp_lit: ast.Comp_Lit) -> bool { for expr in comp_lit.elems { if field, ok := expr.derived.(^ast.Field_Value); ok { #partial switch v in field.value.derived { - case ^ast.Proc_Type, ^ast.Proc_Lit: - return true + case ^ast.Proc_Type, ^ast.Proc_Lit: + return true } } } - + return false } @(private) -contains_comments_in_range :: proc(p: ^Printer, pos: tokenizer.Pos, end: tokenizer.Pos) -> bool { +contains_comments_in_range :: proc( + p: ^Printer, + pos: tokenizer.Pos, + end: tokenizer.Pos, +) -> bool { for i := p.latest_comment_index; i < len(p.comments); i += 1 { for c in p.comments[i].list { if pos.offset <= c.pos.offset && c.pos.offset <= end.offset { @@ -1003,7 +1332,7 @@ contains_comments_in_range :: proc(p: ^Printer, pos: tokenizer.Pos, end: tokeniz @(private) contains_do_in_expression :: proc(p: ^Printer, expr: ^ast.Expr) -> bool { found_do := false - + visit_fn :: proc(visitor: ^ast.Visitor, node: ^ast.Node) -> ^ast.Visitor { if node == nil { return nil @@ -1034,21 +1363,40 @@ push_where_clauses :: proc(p: ^Printer, clauses: []^ast.Expr) -> ^Document { if len(clauses) == 0 { return empty() } - - return group(nest(cons_with_nopl(text("where"), visit_exprs(p, clauses, {.Add_Comma, .Enforce_Newline})))) + + return group( + nest( + cons_with_nopl( + text("where"), + visit_exprs(p, clauses, {.Add_Comma, .Enforce_Newline}), + ), + ), + ) } @(private) -visit_poly_params :: proc(p: ^Printer, poly_params: ^ast.Field_List) -> ^Document { +visit_poly_params :: proc( + p: ^Printer, + poly_params: ^ast.Field_List, +) -> ^Document { if poly_params != nil { - return cons(text("("), visit_signature_list(p, poly_params, true, false), text(")")) + return cons( + text("("), + visit_signature_list(p, poly_params, true, false), + text(")"), + ) } else { return empty() } } @(private) -visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, called_from: Expr_Called_Type = .Generic, options := List_Options{}) -> ^Document { +visit_expr :: proc( + p: ^Printer, + expr: ^ast.Expr, + called_from: Expr_Called_Type = .Generic, + options := List_Options{}, +) -> ^Document { using ast if expr == nil { @@ -1062,25 +1410,25 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, called_from: Expr_Called_Type = } comments, _ := visit_comments(p, expr.pos) - document := empty(); + document := empty() #partial switch v in expr.derived { case ^Inline_Asm_Expr: document = cons( - text_token(p, v.tok), - text("("), - visit_exprs(p, v.param_types, {.Add_Comma}), + text_token(p, v.tok), + text("("), + visit_exprs(p, v.param_types, {.Add_Comma}), text(")"), ) document = cons_with_opl(document, cons(text("-"), text(">"))) document = cons_with_opl(document, visit_expr(p, v.return_type)) document = cons( - document, - text("{"), - visit_expr(p, v.asm_string), - text(","), - visit_expr(p, v.constraints_string), + document, + text("{"), + visit_expr(p, v.asm_string), + text(","), + visit_expr(p, v.constraints_string), text("}"), ) case ^Undef: @@ -1109,7 +1457,7 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, called_from: Expr_Called_Type = break_with_space(), text_token(p, v.op1), break_with_no_newline(), - group(visit_expr(p,v.x)), + group(visit_expr(p, v.x)), if_break(" \\"), break_with_space(), text_token(p, v.op2), @@ -1117,7 +1465,7 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, called_from: Expr_Called_Type = group(visit_expr(p, v.y)), ) } - document = group(document) + document = group(document) case ^Ternary_When_Expr: document = visit_expr(p, v.x) document = cons_with_nopl(document, text_token(p, v.op1)) @@ -1129,10 +1477,13 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, called_from: Expr_Called_Type = document = cons_with_opl(document, text_token(p, v.token)) document = cons_with_opl(document, visit_expr(p, v.y)) case ^Or_Return_Expr: - document = cons_with_nopl(visit_expr(p, v.expr), text_token(p, v.token)) + document = cons_with_nopl( + visit_expr(p, v.expr), + text_token(p, v.token), + ) case ^Selector_Call_Expr: document = cons( - visit_expr(p, v.call.expr), + visit_expr(p, v.call.expr), text("("), visit_exprs(p, v.call.args, {.Add_Comma}), text(")"), @@ -1144,12 +1495,12 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, called_from: Expr_Called_Type = case ^Slice_Expr: document = visit_expr(p, v.expr) document = cons( - visit_expr(p, v.expr), + visit_expr(p, v.expr), text("["), visit_expr(p, v.low), text(v.interval.text), ) - + if v.high != nil { document = cons(document, visit_expr(p, v.high)) } @@ -1160,7 +1511,7 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, called_from: Expr_Called_Type = document = cons(visit_expr(p, v.expr), text_token(p, v.op)) case ^Type_Cast: document = cons( - text_token(p, v.tok), + text_token(p, v.tok), text("("), visit_expr(p, v.type), text(")"), @@ -1169,30 +1520,38 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, called_from: Expr_Called_Type = case ^Basic_Directive: document = cons(text_token(p, v.tok), text_position(p, v.name, v.pos)) case ^Distinct_Type: - document = cons_with_opl(text_position(p, "distinct", v.pos), visit_expr(p, v.type)) + document = cons_with_opl( + text_position(p, "distinct", v.pos), + visit_expr(p, v.type), + ) case ^Dynamic_Array_Type: document = cons( - visit_expr(p, v.tag), - document, text("["), + visit_expr(p, v.tag), + document, + text("["), text("dynamic"), text("]"), visit_expr(p, v.elem), ) case ^Bit_Set_Type: document = cons( - text_position(p, "bit_set", v.pos), - document, text("["), + text_position(p, "bit_set", v.pos), + document, + text("["), visit_expr(p, v.elem), ) if v.underlying != nil { - document = cons(document, cons(text(";"), visit_expr(p, v.underlying))) + document = cons( + document, + cons(text(";"), visit_expr(p, v.underlying)), + ) } document = cons(document, text("]")) case ^Union_Type: document = cons( - text_position(p, "union", v.pos), + text_position(p, "union", v.pos), visit_poly_params(p, v.poly_params), ) @@ -1202,16 +1561,34 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, called_from: Expr_Called_Type = case .shared_nil: document = cons_with_opl(document, text("#shared_nil")) } - - document = cons_with_nopl(document, push_where_clauses(p, v.where_clauses)) + + document = cons_with_nopl( + document, + push_where_clauses(p, v.where_clauses), + ) if len(v.variants) == 0 { document = cons_with_nopl(document, text("{")) document = cons(document, text("}")) } else { - document = cons_with_nopl(document, visit_begin_brace(p, v.pos, .Generic)) + document = cons_with_nopl( + document, + visit_begin_brace(p, v.pos, .Generic), + ) set_source_position(p, v.variants[0].pos) - document = cons(document, nest(cons(newline_position(p, 1, v.pos), visit_union_exprs(p, v^, {.Add_Comma, .Trailing, .Enforce_Newline})))) + document = cons( + document, + nest( + cons( + newline_position(p, 1, v.pos), + visit_union_exprs( + p, + v^, + {.Add_Comma, .Trailing, .Enforce_Newline}, + ), + ), + ), + ) set_source_position(p, v.end) document = cons(document, newline(1), text_position(p, "}", v.end)) @@ -1227,18 +1604,34 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, called_from: Expr_Called_Type = document = cons_with_nopl(document, text("{")) document = cons(document, text("}")) } else { - document = cons(document, break_with_space(), visit_begin_brace(p, v.pos, .Generic)) + document = cons( + document, + break_with_space(), + visit_begin_brace(p, v.pos, .Generic), + ) set_source_position(p, v.fields[0].pos) - document = cons(document, nest(cons(newline_position(p, 1, v.open), visit_enum_exprs(p, v^, {.Add_Comma, .Trailing, .Enforce_Newline})))) + document = cons( + document, + nest( + cons( + newline_position(p, 1, v.open), + visit_enum_exprs( + p, + v^, + {.Add_Comma, .Trailing, .Enforce_Newline}, + ), + ), + ), + ) set_source_position(p, v.end) - + document = cons(document, newline(1), text_position(p, "}", v.end)) } set_source_position(p, v.end) case ^Struct_Type: document = text_position(p, "struct", v.pos) - + document = cons(document, visit_poly_params(p, v.poly_params)) if v.is_packed { @@ -1254,21 +1647,44 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, called_from: Expr_Called_Type = document = cons_with_nopl(document, visit_expr(p, v.align)) } - document = cons_with_nopl(document, push_where_clauses(p, v.where_clauses)) + document = cons_with_nopl( + document, + push_where_clauses(p, v.where_clauses), + ) if v.fields != nil && len(v.fields.list) == 0 { document = cons_with_nopl(document, text("{")) - document = cons(document, visit_struct_field_list(p, v.fields, {.Add_Comma}), text("}")) + document = cons( + document, + visit_struct_field_list(p, v.fields, {.Add_Comma}), + text("}"), + ) } else if v.fields != nil { - document = cons(document, break_with_space(), visit_begin_brace(p, v.pos, .Generic)) - + document = cons( + document, + break_with_space(), + visit_begin_brace(p, v.pos, .Generic), + ) + set_source_position(p, v.fields.pos) - document = cons(document, nest(cons(newline_position(p, 1, v.fields.open), visit_struct_field_list(p, v.fields, {.Add_Comma, .Trailing, .Enforce_Newline})))) + document = cons( + document, + nest( + cons( + newline_position(p, 1, v.fields.open), + visit_struct_field_list( + p, + v.fields, + {.Add_Comma, .Trailing, .Enforce_Newline}, + ), + ), + ), + ) set_source_position(p, v.fields.end) document = cons(document, newline(1), text_position(p, "}", v.end)) } - + set_source_position(p, v.end) case ^Proc_Lit: switch v.inlining { @@ -1279,13 +1695,22 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, called_from: Expr_Called_Type = document = cons(document, text("#force_no_inline")) } - document = cons_with_nopl(document, visit_proc_type(p, v.type^, v.body != nil)) - document = cons_with_nopl(document, push_where_clauses(p, v.where_clauses)) + document = cons_with_nopl( + document, + visit_proc_type(p, v.type^, v.body != nil), + ) + document = cons_with_nopl( + document, + push_where_clauses(p, v.where_clauses), + ) document = cons_with_opl(document, visit_proc_tags(p, v.tags)) if v.body != nil { set_source_position(p, v.body.pos) - document = cons_with_nopl(document, group(visit_stmt(p, v.body, .Proc))) + document = cons_with_nopl( + document, + group(visit_stmt(p, v.body, .Proc)), + ) } else { document = cons_with_nopl(document, text("---")) } @@ -1308,11 +1733,20 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, called_from: Expr_Called_Type = } if is_call_expr_nestable(v.args) { - document = cons(document, nest(cons(break_with(""), visit_call_exprs(p, v)))) + document = cons( + document, + nest(cons(break_with(""), visit_call_exprs(p, v))), + ) } else { - document = cons(document, nest_if_break(cons(break_with(""), visit_call_exprs(p, v)), "call_expr")) + document = cons( + document, + nest_if_break( + cons(break_with(""), visit_call_exprs(p, v)), + "call_expr", + ), + ) } - + document = cons(document, break_with(""), text(")")) //Binary expression are nested on operators, and therefore undo the nesting in the call expression. @@ -1322,25 +1756,41 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, called_from: Expr_Called_Type = //We enforce a break if comments exists inside the call args if contains_comments { - document = enforce_break(document, Document_Group_Options { id = "call_expr" }) - } else if contains_do { + document = enforce_break( + document, + Document_Group_Options{id = "call_expr"}, + ) + } else if contains_do { document = enforce_fit(document) } else { - document = group(document, Document_Group_Options { id = "call_expr" }) + document = group( + document, + Document_Group_Options{id = "call_expr"}, + ) } case ^Typeid_Type: document = text("typeid") if v.specialization != nil { - document = cons(document, text("/"), visit_expr(p, v.specialization)) + document = cons( + document, + text("/"), + visit_expr(p, v.specialization), + ) } case ^Selector_Expr: - document = cons(visit_expr(p, v.expr), text_token(p, v.op), visit_expr(p, v.field)) + document = cons( + visit_expr(p, v.expr), + text_token(p, v.op), + visit_expr(p, v.field), + ) case ^Paren_Expr: - document = group(cons(text("("), nest(visit_expr(p, v.expr)), text(")"))) + document = group( + cons(text("("), nest(visit_expr(p, v.expr)), text(")")), + ) case ^Index_Expr: document = cons( - visit_expr(p, v.expr), + visit_expr(p, v.expr), text("["), nest( cons( @@ -1356,13 +1806,28 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, called_from: Expr_Called_Type = document = text_token(p, v.tok) if len(v.args) != 0 { - document = cons_with_nopl(document, visit_begin_brace(p, v.pos, .Generic)) + document = cons_with_nopl( + document, + visit_begin_brace(p, v.pos, .Generic), + ) set_source_position(p, v.args[0].pos) - document = cons(document, nest(cons(newline_position(p, 1, v.args[0].pos), visit_exprs(p, v.args, {.Add_Comma, .Trailing, .Enforce_Newline})))) + document = cons( + document, + nest( + cons( + newline_position(p, 1, v.args[0].pos), + visit_exprs( + p, + v.args, + {.Add_Comma, .Trailing, .Enforce_Newline}, + ), + ), + ), + ) document = cons(document, visit_end_brace(p, v.end, 1)) } else { document = cons( - document, + document, text("{"), visit_exprs(p, v.args, {.Add_Comma}), text("}"), @@ -1375,37 +1840,78 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, called_from: Expr_Called_Type = if v.type != nil { document = cons_with_nopl(document, visit_expr(p, v.type)) - - if matrix_type, ok := v.type.derived.(^ast.Matrix_Type); ok && len(v.elems) > 0 && is_matrix_type_constant(matrix_type) { - document = cons_with_nopl(document, visit_begin_brace(p, v.pos, .Generic)) + + if matrix_type, ok := v.type.derived.(^ast.Matrix_Type); + ok && len(v.elems) > 0 && is_matrix_type_constant(matrix_type) { + document = cons_with_nopl( + document, + visit_begin_brace(p, v.pos, .Generic), + ) set_source_position(p, v.open) - document = cons(document, nest(cons(newline_position(p, 1, v.elems[0].pos), visit_matrix_comp_lit(p, v, matrix_type)))) + document = cons( + document, + nest( + cons( + newline_position(p, 1, v.elems[0].pos), + visit_matrix_comp_lit(p, v, matrix_type), + ), + ), + ) set_source_position(p, v.end) - document = cons(document, newline(1), text_position(p, "}", v.end)) - + document = cons( + document, + newline(1), + text_position(p, "}", v.end), + ) + break } } - should_newline := comp_lit_contains_fields(p, v^) || contains_comments_in_range(p, v.pos, v.end) - should_newline &= (called_from == .Value_Decl || called_from == .Assignment_Stmt || (called_from == .Call_Expr && comp_lit_contains_blocks(p, v^))) + should_newline := + comp_lit_contains_fields(p, v^) || + contains_comments_in_range(p, v.pos, v.end) + should_newline &= + (called_from == .Value_Decl || + called_from == .Assignment_Stmt || + (called_from == .Call_Expr && comp_lit_contains_blocks(p, v^))) should_newline &= len(v.elems) != 0 - + if should_newline { - document = cons_with_nopl(document, visit_begin_brace(p, v.pos, .Generic)) - + document = cons_with_nopl( + document, + visit_begin_brace(p, v.pos, .Generic), + ) + set_source_position(p, v.open) - document = cons(document, nest(cons(newline_position(p, 1, v.elems[0].pos), visit_comp_lit_exprs(p, v^, {.Add_Comma, .Trailing, .Enforce_Newline})))) + document = cons( + document, + nest( + cons( + newline_position(p, 1, v.elems[0].pos), + visit_comp_lit_exprs( + p, + v^, + {.Add_Comma, .Trailing, .Enforce_Newline}, + ), + ), + ), + ) set_source_position(p, v.end) document = cons(document, newline(1), text_position(p, "}", v.end)) } else { document = cons( - document, + document, text("{"), - nest(cons(break_with(""), visit_exprs(p, v.elems, {.Add_Comma, .Group}))), + nest( + cons( + break_with(""), + visit_exprs(p, v.elems, {.Add_Comma, .Group}), + ), + ), if_break(","), break_with(""), text("}"), @@ -1415,15 +1921,22 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, called_from: Expr_Called_Type = case ^Unary_Expr: document = cons(text_token(p, v.op), visit_expr(p, v.expr)) case ^Field_Value: - document = cons_with_nopl(visit_expr(p, v.field), cons_with_nopl(text_position(p, "=", v.sep), visit_expr(p, v.value))) + document = cons_with_nopl( + visit_expr(p, v.field), + cons_with_nopl( + text_position(p, "=", v.sep), + visit_expr(p, v.value), + ), + ) case ^Type_Assertion: document = visit_expr(p, v.expr) - if unary, ok := v.type.derived.(^Unary_Expr); ok && unary.op.text == "?" { + if unary, ok := v.type.derived.(^Unary_Expr); + ok && unary.op.text == "?" { document = cons(document, text("."), visit_expr(p, v.type)) } else { document = cons( - document, + document, text("."), text("("), visit_expr(p, v.type), @@ -1441,14 +1954,14 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, called_from: Expr_Called_Type = if v.specialization != nil { document = cons( - document, + document, text("/"), visit_expr(p, v.specialization), ) } case ^Array_Type: document = cons( - visit_expr(p, v.tag), + visit_expr(p, v.tag), text("["), visit_expr(p, v.len), text("]"), @@ -1456,7 +1969,7 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, called_from: Expr_Called_Type = ) case ^Map_Type: document = cons( - text("map"), + text("map"), text("["), visit_expr(p, v.key), text("]"), @@ -1469,7 +1982,7 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, called_from: Expr_Called_Type = document = cons_with_nopl(document, visit_expr(p, v.type)) case ^Matrix_Type: document = cons( - text_position(p, "matrix", v.pos), + text_position(p, "matrix", v.pos), text("["), visit_expr(p, v.row_count), text(","), @@ -1479,7 +1992,7 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, called_from: Expr_Called_Type = document = cons(group(document), visit_expr(p, v.elem)) case ^Matrix_Index_Expr: document = cons( - visit_expr(p, v.expr), + visit_expr(p, v.expr), text("["), visit_expr(p, v.row_index), text(","), @@ -1495,12 +2008,14 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr, called_from: Expr_Called_Type = @(private) is_matrix_type_constant :: proc(matrix_type: ^ast.Matrix_Type) -> bool { - if row_count, is_lit := matrix_type.row_count.derived.(^ast.Basic_Lit); is_lit { + if row_count, is_lit := matrix_type.row_count.derived.(^ast.Basic_Lit); + is_lit { _, ok := strconv.parse_int(row_count.tok.text) return ok } - if column_count, is_lit := matrix_type.column_count.derived.(^ast.Basic_Lit); is_lit { + if column_count, is_lit := matrix_type.column_count.derived.(^ast.Basic_Lit); + is_lit { _, ok := strconv.parse_int(column_count.tok.text) return ok } @@ -1509,16 +2024,27 @@ is_matrix_type_constant :: proc(matrix_type: ^ast.Matrix_Type) -> bool { } @(private) -visit_matrix_comp_lit :: proc(p: ^Printer, comp_lit: ^ast.Comp_Lit, matrix_type: ^ast.Matrix_Type) -> ^Document { +visit_matrix_comp_lit :: proc( + p: ^Printer, + comp_lit: ^ast.Comp_Lit, + matrix_type: ^ast.Matrix_Type, +) -> ^Document { document := empty() //these values have already been validated - row_count, _ := strconv.parse_int(matrix_type.row_count.derived.(^ast.Basic_Lit).tok.text) - column_count, _ := strconv.parse_int(matrix_type.column_count.derived.(^ast.Basic_Lit).tok.text) + row_count, _ := strconv.parse_int( + matrix_type.row_count.derived.(^ast.Basic_Lit).tok.text, + ) + column_count, _ := strconv.parse_int( + matrix_type.column_count.derived.(^ast.Basic_Lit).tok.text, + ) for row := 0; row < row_count; row += 1 { for column := 0; column < column_count; column += 1 { - document = cons(document, visit_expr(p, comp_lit.elems[column + row * column_count])) + document = cons( + document, + visit_expr(p, comp_lit.elems[column + row * column_count]), + ) document = cons(document, text(", ")) } @@ -1526,13 +2052,19 @@ visit_matrix_comp_lit :: proc(p: ^Printer, comp_lit: ^ast.Comp_Lit, matrix_type: document = cons(document, newline(1)) } } - + return document } @(private) -visit_begin_brace :: proc(p: ^Printer, begin: tokenizer.Pos, type: Block_Type, count := 0, same_line_spaces_before := 1) -> ^Document { +visit_begin_brace :: proc( + p: ^Printer, + begin: tokenizer.Pos, + type: Block_Type, + count := 0, + same_line_spaces_before := 1, +) -> ^Document { set_source_position(p, begin) set_comment_option(p, begin.line, .Indent) @@ -1550,7 +2082,11 @@ visit_begin_brace :: proc(p: ^Printer, begin: tokenizer.Pos, type: Block_Type, c } @(private) -visit_end_brace :: proc(p: ^Printer, end: tokenizer.Pos, limit := 0) -> ^Document { +visit_end_brace :: proc( + p: ^Printer, + end: tokenizer.Pos, + limit := 0, +) -> ^Document { if limit == 0 { return cons(move_line(p, end), text("}")) } else { @@ -1564,12 +2100,16 @@ visit_end_brace :: proc(p: ^Printer, end: tokenizer.Pos, limit := 0) -> ^Documen } @(private) -visit_block_stmts :: proc(p: ^Printer, stmts: []^ast.Stmt, split := false) -> ^Document { +visit_block_stmts :: proc( + p: ^Printer, + stmts: []^ast.Stmt, + split := false, +) -> ^Document { document := empty() for stmt, i in stmts { - last_index := max(0, i-1) - if stmts[last_index].end.line == stmt.pos.line && i != 0 { + last_index := max(0, i - 1) + if stmts[last_index].end.line == stmt.pos.line && i != 0 { document = cons(document, break_with(";")) } document = cons(document, visit_stmt(p, stmt, .Generic, false, true)) @@ -1589,7 +2129,11 @@ List_Option :: enum u8 { List_Options :: distinct bit_set[List_Option] @(private) -visit_struct_field_list :: proc(p: ^Printer, list: ^ast.Field_List, options := List_Options{}) -> ^Document { +visit_struct_field_list :: proc( + p: ^Printer, + list: ^ast.Field_List, + options := List_Options{}, +) -> ^Document { document := empty() if list.list == nil { return document @@ -1601,7 +2145,7 @@ visit_struct_field_list :: proc(p: ^Printer, list: ^ast.Field_List, options := L p.source_position = field.pos if i == 0 && .Enforce_Newline in options { - comment, ok := visit_comments(p, list.list[i].pos) + comment, ok := visit_comments(p, list.list[i].pos) if _, is_nil := comment.(Document_Nil); !is_nil { comment = cons(comment, newline(1)) } @@ -1613,7 +2157,11 @@ visit_struct_field_list :: proc(p: ^Printer, list: ^ast.Field_List, options := L } if .Subtype in field.flags { - document = cons(document, text("#subtype"), break_with_no_newline()) + document = cons( + document, + text("#subtype"), + break_with_no_newline(), + ) } name_options := List_Options{.Add_Comma} @@ -1633,10 +2181,16 @@ visit_struct_field_list :: proc(p: ^Printer, list: ^ast.Field_List, options := L } } align = repeat_space(alignment - length) - } - document = cons(document, visit_exprs(p, field.names, name_options)) + } + document = cons( + document, + visit_exprs(p, field.names, name_options), + ) } else { - document = cons_with_opl(document, visit_exprs(p, field.names, name_options)) + document = cons_with_opl( + document, + visit_exprs(p, field.names, name_options), + ) } if field.type != nil { @@ -1646,19 +2200,23 @@ visit_struct_field_list :: proc(p: ^Printer, list: ^ast.Field_List, options := L document = cons_with_opl(document, visit_expr(p, field.type)) } else { document = cons(document, text(":"), text("=")) - document = cons_with_opl(document, visit_expr(p, field.default_value)) + document = cons_with_opl( + document, + visit_expr(p, field.default_value), + ) } if field.tag.text != "" { document = cons_with_nopl(document, text_token(p, field.tag)) } - if (i != len(list.list) - 1 || .Trailing in options) && .Add_Comma in options { + if (i != len(list.list) - 1 || .Trailing in options) && + .Add_Comma in options { document = cons(document, text(",")) } if i != len(list.list) - 1 && .Enforce_Newline in options { - comment, _ := visit_comments(p, list.list[i+1].pos) + comment, _ := visit_comments(p, list.list[i + 1].pos) document = cons(document, comment, newline(1)) } else { comment, _ := visit_comments(p, list.end) @@ -1692,7 +2250,11 @@ visit_proc_tags :: proc(p: ^Printer, proc_tags: ast.Proc_Tags) -> ^Document { } @(private) -visit_proc_type :: proc(p: ^Printer, proc_type: ast.Proc_Type, contains_body: bool) -> ^Document { +visit_proc_type :: proc( + p: ^Printer, + proc_type: ast.Proc_Type, + contains_body: bool, +) -> ^Document { document := text("proc") explicit_calling := false @@ -1708,7 +2270,15 @@ visit_proc_type :: proc(p: ^Printer, proc_type: ast.Proc_Type, contains_body: bo document = cons(document, text("(")) } - document = cons(document, nest(cons(break_with(""), visit_signature_list(p, proc_type.params, true, false)))) + document = cons( + document, + nest( + cons( + break_with(""), + visit_signature_list(p, proc_type.params, true, false), + ), + ), + ) document = cons(document, break_with(""), text(")")) if proc_type.results != nil && len(proc_type.results.list) > 0 { @@ -1731,10 +2301,35 @@ visit_proc_type :: proc(p: ^Printer, proc_type: ast.Proc_Type, contains_body: bo if use_parens { document = cons_with_nopl(document, text("(")) - document = cons(document, nest(cons(break_with(""), visit_signature_list(p, proc_type.results, contains_body, true)))) + document = cons( + document, + nest( + cons( + break_with(""), + visit_signature_list( + p, + proc_type.results, + contains_body, + true, + ), + ), + ), + ) document = cons(document, break_with(""), text(")")) } else { - document = cons_with_nopl(document, nest(group(visit_signature_list(p, proc_type.results, contains_body, true)))) + document = cons_with_nopl( + document, + nest( + group( + visit_signature_list( + p, + proc_type.results, + contains_body, + true, + ), + ), + ), + ) } } else if proc_type.diverging { document = cons_with_nopl(document, text("-")) @@ -1747,22 +2342,34 @@ visit_proc_type :: proc(p: ^Printer, proc_type: ast.Proc_Type, contains_body: bo @(private) -visit_binary_expr :: proc(p: ^Printer, binary: ast.Binary_Expr, nested := false) -> ^Document { +visit_binary_expr :: proc( + p: ^Printer, + binary: ast.Binary_Expr, + nested := false, +) -> ^Document { document := empty() nest_expression := false - if binary.left != nil { + if binary.left != nil { if b, ok := binary.left.derived.(^ast.Binary_Expr); ok { pa := parser.Parser { allow_in_expr = true, } - nest_expression = parser.token_precedence(&pa, b.op.kind) != parser.token_precedence(&pa, binary.op.kind) - document = cons(document, visit_binary_expr(p, b^, nest_expression)) + nest_expression = + parser.token_precedence(&pa, b.op.kind) != + parser.token_precedence(&pa, binary.op.kind) + document = cons( + document, + visit_binary_expr(p, b^, nest_expression), + ) } else { - document = cons(document, visit_expr(p, binary.left, nested ? .Binary_Expr : .Generic)) + document = cons( + document, + visit_expr(p, binary.left, nested ? .Binary_Expr : .Generic), + ) } - } + } if nest_expression { document = nest(document) @@ -1773,9 +2380,15 @@ visit_binary_expr :: proc(p: ^Printer, binary: ast.Binary_Expr, nested := false) if binary.right != nil { if b, ok := binary.right.derived.(^ast.Binary_Expr); ok { - document = cons_with_opl(document, group(nest(visit_binary_expr(p, b^, true)))) + document = cons_with_opl( + document, + group(nest(visit_binary_expr(p, b^, true))), + ) } else { - document = cons_with_opl(document, group(nest(visit_expr(p, binary.right, .Binary_Expr)))) + document = cons_with_opl( + document, + group(nest(visit_expr(p, binary.right, .Binary_Expr))), + ) } } @@ -1794,25 +2407,28 @@ visit_call_exprs :: proc(p: ^Printer, call_expr: ^ast.Call_Expr) -> ^Document { } document = cons(document, group(visit_expr(p, expr, .Call_Expr))) - + if i != len(call_expr.args) - 1 { document = cons(document, text(",")) //need to look for comments before we write the comma with break - comments, _ := visit_comments(p, call_expr.args[i+1].pos) + comments, _ := visit_comments(p, call_expr.args[i + 1].pos) document = cons(document, comments, break_with_space()) } else { comments, _ := visit_comments(p, call_expr.close) document = cons(document, if_break(","), comments) - } + } } return document } @(private) -visit_signature_field_flag :: proc(p: ^Printer, flags: ast.Field_Flags) -> ^Document { +visit_signature_field_flag :: proc( + p: ^Printer, + flags: ast.Field_Flags, +) -> ^Document { document := empty() if .Auto_Cast in flags { @@ -1847,24 +2463,39 @@ visit_signature_field_flag :: proc(p: ^Printer, flags: ast.Field_Flags) -> ^Docu } @(private) -visit_signature_list :: proc(p: ^Printer, list: ^ast.Field_List, contains_body: bool, remove_blank: bool) -> ^Document { +visit_signature_list :: proc( + p: ^Printer, + list: ^ast.Field_List, + contains_body: bool, + remove_blank: bool, +) -> ^Document { document := empty() for field, i in list.list { - document = cons(document, visit_signature_field(p, field, remove_blank)) + document = cons( + document, + visit_signature_field(p, field, remove_blank), + ) if i != len(list.list) - 1 { document = cons(document, text(","), break_with_space()) } else { - document = len(list.list) > 1 || contains_body ? cons(document, if_break(",")) : document - } + document = + len(list.list) > 1 || contains_body \ + ? cons(document, if_break(",")) \ + : document + } } return document } @(private) -visit_signature_field :: proc(p: ^Printer, field: ^ast.Field, remove_blank := true) -> ^Document { +visit_signature_field :: proc( + p: ^Printer, + field: ^ast.Field, + remove_blank := true, +) -> ^Document { document := empty() flag := visit_signature_field_flag(p, field.flags) @@ -1883,7 +2514,10 @@ visit_signature_field :: proc(p: ^Printer, field: ^ast.Field, remove_blank := tr } if named { - document = cons(document, cons_with_nopl(flag, visit_exprs(p, field.names, {.Add_Comma}))) + document = cons( + document, + cons_with_nopl(flag, visit_exprs(p, field.names, {.Add_Comma})), + ) if len(field.names) != 0 && field.type != nil { document = cons(document, text(":"), break_with_no_newline()) @@ -1927,8 +2561,12 @@ get_node_length :: proc(node: ^ast.Node) -> int { case ^ast.Paren_Expr: return 1 + get_node_length(v.expr) + 1 case ^ast.Selector_Expr: - return get_node_length(v.expr) + strings.rune_count(v.op.text) + strings.rune_count(v.field.name) - case: + return( + get_node_length(v.expr) + + strings.rune_count(v.op.text) + + strings.rune_count(v.field.name) \ + ) + case: panic(fmt.aprintf("unhandled get_node_length case %v", node.derived)) } } diff --git a/src/server/action.odin b/src/server/action.odin index 44b3458..ba1b367 100644 --- a/src/server/action.odin +++ b/src/server/action.odin @@ -13,4 +13,4 @@ CodeActionClientCapabilities :: struct { CodeActionOptions :: struct { codeActionKinds: []CodeActionKind, resolveProvider: bool, -}
\ No newline at end of file +} diff --git a/src/server/analysis.odin b/src/server/analysis.odin index facc202..6113b63 100644 --- a/src/server/analysis.odin +++ b/src/server/analysis.odin @@ -29,30 +29,30 @@ DocumentPositionContext :: struct { position: common.AbsolutePosition, line: int, function: ^ast.Proc_Lit, //used to help with type resolving in function scope - selector: ^ast.Expr, //used for completion + selector: ^ast.Expr, //used for completion selector_expr: ^ast.Selector_Expr, identifier: ^ast.Node, implicit_context: ^ast.Implicit, tag: ^ast.Node, - field: ^ast.Expr, //used for completion - call: ^ast.Expr, //used for signature help + field: ^ast.Expr, //used for completion + call: ^ast.Expr, //used for signature help returns: ^ast.Return_Stmt, //used for completion - comp_lit: ^ast.Comp_Lit, //used for completion - parent_comp_lit: ^ast.Comp_Lit, //used for completion + comp_lit: ^ast.Comp_Lit, //used for completion + parent_comp_lit: ^ast.Comp_Lit, //used for completion struct_type: ^ast.Struct_Type, union_type: ^ast.Union_Type, bitset_type: ^ast.Bit_Set_Type, enum_type: ^ast.Enum_Type, field_value: ^ast.Field_Value, - implicit: bool, //used for completion + implicit: bool, //used for completion arrow: bool, - binary: ^ast.Binary_Expr, //used for completion - parent_binary: ^ast.Binary_Expr, //used for completion - assign: ^ast.Assign_Stmt, //used for completion - switch_stmt: ^ast.Switch_Stmt, //used for completion + binary: ^ast.Binary_Expr, //used for completion + parent_binary: ^ast.Binary_Expr, //used for completion + assign: ^ast.Assign_Stmt, //used for completion + switch_stmt: ^ast.Switch_Stmt, //used for completion switch_type_stmt: ^ast.Type_Switch_Stmt, //used for completion - case_clause: ^ast.Case_Clause, //used for completion - value_decl: ^ast.Value_Decl, //used for completion + case_clause: ^ast.Case_Clause, //used for completion + value_decl: ^ast.Value_Decl, //used for completion abort_completion: bool, hint: DocumentPositionContextHint, global_lhs_stmt: bool, @@ -61,10 +61,10 @@ DocumentPositionContext :: struct { } DocumentLocal :: struct { - lhs: ^ast.Expr, - rhs: ^ast.Expr, + lhs: ^ast.Expr, + rhs: ^ast.Expr, offset: int, - id: int, //Id that can used to connect the local to something, i.e. for stmt begin offset + id: int, //Id that can used to connect the local to something, i.e. for stmt begin offset } AstContext :: struct { @@ -81,7 +81,7 @@ AstContext :: struct { document_package: string, use_globals: bool, use_locals: bool, - local_id: int, + 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, @@ -91,23 +91,34 @@ AstContext :: struct { recursion_counter: int, //Sometimes the ast is so malformed that it causes infinite recursion. } -make_ast_context :: proc(file: ast.File, imports: []Package, package_name: string, uri: string, fullpath: string, allocator := context.temp_allocator) -> AstContext { +make_ast_context :: proc( + file: ast.File, + imports: []Package, + package_name: string, + uri: string, + fullpath: string, + allocator := context.temp_allocator, +) -> AstContext { ast_context := AstContext { - locals = make(map[int]map[string][dynamic]DocumentLocal, 0, allocator), - globals = make(map[string]common.GlobalExpr, 0, allocator), - variables = make(map[string]bool, 0, allocator), - usings = make([dynamic]string, allocator), - parameters = make(map[string]bool, 0, allocator), - in_package = make(map[string]string, 0, allocator), - file = file, - imports = imports, - use_locals = true, - use_globals = true, + locals = make( + map[int]map[string][dynamic]DocumentLocal, + 0, + allocator, + ), + globals = make(map[string]common.GlobalExpr, 0, allocator), + variables = make(map[string]bool, 0, allocator), + usings = make([dynamic]string, allocator), + parameters = make(map[string]bool, 0, allocator), + in_package = make(map[string]string, 0, allocator), + file = file, + imports = imports, + use_locals = true, + use_globals = true, document_package = package_name, - current_package = package_name, - uri = uri, - fullpath = fullpath, - allocator = allocator, + current_package = package_name, + uri = uri, + fullpath = fullpath, + allocator = allocator, } add_local_group(&ast_context, 0) @@ -128,7 +139,12 @@ resolve_poly_spec :: proc { resolve_poly_spec_dynamic_array, } -resolve_poly_spec_array :: proc(ast_context: ^AstContext, call_array: $A/[]^$T, spec_array: $D/[]^$K, poly_map: ^map[string]^ast.Expr) { +resolve_poly_spec_array :: proc( + ast_context: ^AstContext, + call_array: $A/[]^$T, + spec_array: $D/[]^$K, + poly_map: ^map[string]^ast.Expr, +) { if len(call_array) != len(spec_array) { return } @@ -138,7 +154,12 @@ resolve_poly_spec_array :: proc(ast_context: ^AstContext, call_array: $A/[]^$T, } } -resolve_poly_spec_dynamic_array :: proc(ast_context: ^AstContext, call_array: $A/[dynamic]^$T, spec_array: $D/[dynamic]^$K, poly_map: ^map[string]^ast.Expr) { +resolve_poly_spec_dynamic_array :: proc( + ast_context: ^AstContext, + call_array: $A/[dynamic]^$T, + spec_array: $D/[dynamic]^$K, + poly_map: ^map[string]^ast.Expr, +) { if len(call_array) != len(spec_array) { return } @@ -163,7 +184,12 @@ get_poly_node_to_expr :: proc(node: ^ast.Node) -> ^ast.Expr { return nil } -resolve_poly_spec_node :: proc(ast_context: ^AstContext, call_node: ^ast.Node, spec_node: ^ast.Node, poly_map: ^map[string]^ast.Expr) { +resolve_poly_spec_node :: proc( + ast_context: ^AstContext, + call_node: ^ast.Node, + spec_node: ^ast.Node, + poly_map: ^map[string]^ast.Expr, +) { using ast if call_node == nil || spec_node == nil { @@ -176,7 +202,7 @@ resolve_poly_spec_node :: proc(ast_context: ^AstContext, call_node: ^ast.Node, s case ^Implicit: case ^Undef: case ^Basic_Lit: - case ^Poly_Type: + case ^Poly_Type: if expr := get_poly_node_to_expr(call_node); expr != nil { poly_map[m.type.name] = expr } @@ -236,7 +262,12 @@ resolve_poly_spec_node :: proc(ast_context: ^AstContext, call_node: ^ast.Node, s } case ^Struct_Type: if n, ok := call_node.derived.(^Struct_Type); ok { - resolve_poly_spec(ast_context, n.poly_params, m.poly_params, poly_map) + resolve_poly_spec( + ast_context, + n.poly_params, + m.poly_params, + poly_map, + ) resolve_poly_spec(ast_context, n.align, m.align, poly_map) resolve_poly_spec(ast_context, n.fields, m.fields, poly_map) } @@ -244,7 +275,12 @@ resolve_poly_spec_node :: proc(ast_context: ^AstContext, call_node: ^ast.Node, s if n, ok := call_node.derived.(^Field); ok { resolve_poly_spec(ast_context, n.names, m.names, poly_map) resolve_poly_spec(ast_context, n.type, m.type, poly_map) - resolve_poly_spec(ast_context, n.default_value, m.default_value, poly_map) + resolve_poly_spec( + ast_context, + n.default_value, + m.default_value, + poly_map, + ) } case ^Field_List: if n, ok := call_node.derived.(^Field_List); ok { @@ -257,7 +293,12 @@ resolve_poly_spec_node :: proc(ast_context: ^AstContext, call_node: ^ast.Node, s } case ^Union_Type: if n, ok := call_node.derived.(^Union_Type); ok { - resolve_poly_spec(ast_context, n.poly_params, m.poly_params, poly_map) + resolve_poly_spec( + ast_context, + n.poly_params, + m.poly_params, + poly_map, + ) resolve_poly_spec(ast_context, n.align, m.align, poly_map) resolve_poly_spec(ast_context, n.variants, m.variants, poly_map) } @@ -269,7 +310,12 @@ resolve_poly_spec_node :: proc(ast_context: ^AstContext, call_node: ^ast.Node, s case ^Bit_Set_Type: if n, ok := call_node.derived.(^Bit_Set_Type); ok { resolve_poly_spec(ast_context, n.elem, m.elem, poly_map) - resolve_poly_spec(ast_context, n.underlying, m.underlying, poly_map) + resolve_poly_spec( + ast_context, + n.underlying, + m.underlying, + poly_map, + ) } case ^Map_Type: if n, ok := call_node.derived.(^Map_Type); ok { @@ -283,14 +329,28 @@ resolve_poly_spec_node :: proc(ast_context: ^AstContext, call_node: ^ast.Node, s } case ^Typeid_Type: if n, ok := call_node.derived.(^Typeid_Type); ok { - resolve_poly_spec(ast_context, n.specialization, m.specialization, poly_map) + resolve_poly_spec( + ast_context, + n.specialization, + m.specialization, + poly_map, + ) } case: log.error("Unhandled poly node kind: %T", m) } } -resolve_type_comp_literal :: proc(ast_context: ^AstContext, position_context: ^DocumentPositionContext, current_symbol: Symbol, current_comp_lit: ^ast.Comp_Lit) -> (Symbol, ^ast.Comp_Lit, bool) { +resolve_type_comp_literal :: proc( + ast_context: ^AstContext, + position_context: ^DocumentPositionContext, + current_symbol: Symbol, + current_comp_lit: ^ast.Comp_Lit, +) -> ( + Symbol, + ^ast.Comp_Lit, + bool, +) { if position_context.comp_lit == current_comp_lit { return current_symbol, current_comp_lit, true } else if current_comp_lit == nil { @@ -301,7 +361,7 @@ resolve_type_comp_literal :: proc(ast_context: ^AstContext, position_context: ^D prev_package := ast_context.current_package ast_context.current_package = current_symbol.pkg - + defer ast_context.current_package = prev_package for elem, i in current_comp_lit.elems { @@ -314,35 +374,53 @@ resolve_type_comp_literal :: proc(ast_context: ^AstContext, position_context: ^D if !position_in_node(elem, position_context.position) { continue } - - if field_value, ok := elem.derived.(^ast.Field_Value); ok { //named + + if field_value, ok := elem.derived.(^ast.Field_Value); ok { //named if comp_lit, ok := field_value.value.derived.(^ast.Comp_Lit); ok { if s, ok := current_symbol.value.(SymbolStructValue); ok { for name, i in s.names { - if name == field_value.field.derived.(^ast.Ident).name { - if symbol, ok := resolve_type_expression(ast_context, s.types[i]); ok { + if name == + field_value.field.derived.(^ast.Ident).name { + if symbol, ok := resolve_type_expression( + ast_context, + s.types[i], + ); ok { //Stop at bitset, because we don't want to enter a comp_lit of a bitset - if _, ok := symbol.value.(SymbolBitSetValue); ok { + if _, ok := symbol.value.(SymbolBitSetValue); + ok { return current_symbol, current_comp_lit, true } - return resolve_type_comp_literal(ast_context, position_context, symbol, cast(^ast.Comp_Lit)field_value.value) + return resolve_type_comp_literal( + ast_context, + position_context, + symbol, + cast(^ast.Comp_Lit)field_value.value, + ) } } } } } - } else if comp_value, ok := elem.derived.(^ast.Comp_Lit); ok { //indexed + } else if comp_value, ok := elem.derived.(^ast.Comp_Lit); ok { //indexed if s, ok := current_symbol.value.(SymbolStructValue); ok { if len(s.types) <= element_index { return {}, {}, false } - if symbol, ok := resolve_type_expression(ast_context, s.types[element_index]); ok { + if symbol, ok := resolve_type_expression( + ast_context, + s.types[element_index], + ); ok { //Stop at bitset, because we don't want to enter a comp_lit of a bitset if _, ok := symbol.value.(SymbolBitSetValue); ok { return current_symbol, current_comp_lit, true } - return resolve_type_comp_literal(ast_context, position_context, symbol, comp_value) + return resolve_type_comp_literal( + ast_context, + position_context, + symbol, + comp_value, + ) } } } @@ -356,7 +434,14 @@ resolve_generic_function :: proc { resolve_generic_function_symbol, } -resolve_generic_function_symbol :: proc(ast_context: ^AstContext, params: []^ast.Field, results: []^ast.Field) -> (Symbol, bool) { +resolve_generic_function_symbol :: proc( + ast_context: ^AstContext, + params: []^ast.Field, + results: []^ast.Field, +) -> ( + Symbol, + bool, +) { if params == nil { return {}, false } @@ -372,7 +457,7 @@ resolve_generic_function_symbol :: proc(ast_context: ^AstContext, params: []^ast call_expr := ast_context.call poly_map := make(map[string]^ast.Expr, 0, context.temp_allocator) i := 0 - count_required_params := 0 + count_required_params := 0 for param in params { if param.default_value == nil { @@ -393,18 +478,29 @@ resolve_generic_function_symbol :: proc(ast_context: ^AstContext, params: []^ast } if type_id, ok := param.type.derived.(^ast.Typeid_Type); ok { - if type_id.specialization != nil && !common.node_equal(call_expr.args[i], type_id.specialization) { + if type_id.specialization != nil && + !common.node_equal( + call_expr.args[i], + type_id.specialization, + ) { return {}, false } } - resolve_poly_spec_node(ast_context, call_expr.args[i], param.type, &poly_map) + resolve_poly_spec_node( + ast_context, + call_expr.args[i], + param.type, + &poly_map, + ) i += 1 } } - if count_required_params > len(call_expr.args) || count_required_params == 0 || len(call_expr.args) == 0 { + if count_required_params > len(call_expr.args) || + count_required_params == 0 || + len(call_expr.args) == 0 { return {}, false } @@ -423,8 +519,8 @@ resolve_generic_function_symbol :: proc(ast_context: ^AstContext, params: []^ast symbol := Symbol { range = function_range, - type = .Function, - name = function_name, + type = .Function, + name = function_name, } return_types := make([dynamic]^ast.Field, ast_context.allocator) @@ -439,7 +535,11 @@ resolve_generic_function_symbol :: proc(ast_context: ^AstContext, params: []^ast if ok { if m, ok := poly_map[ident.name]; ok { - field := cast(^ast.Field)clone_node(result, ast_context.allocator, nil) + field := cast(^ast.Field)clone_node( + result, + ast_context.allocator, + nil, + ) field.type = m append(&return_types, field) } else { @@ -456,9 +556,14 @@ resolve_generic_function_symbol :: proc(ast_context: ^AstContext, params: []^ast } //check the name for poly - if poly_type, ok := param.names[0].derived.(^ast.Poly_Type); ok && param.type != nil { + if poly_type, ok := param.names[0].derived.(^ast.Poly_Type); + ok && param.type != nil { if m, ok := poly_map[poly_type.type.name]; ok { - field := cast(^ast.Field)clone_node(param, ast_context.allocator, nil) + field := cast(^ast.Field)clone_node( + param, + ast_context.allocator, + nil, + ) field.type = m append(&argument_types, field) } @@ -469,55 +574,78 @@ resolve_generic_function_symbol :: proc(ast_context: ^AstContext, params: []^ast symbol.value = SymbolProcedureValue { return_types = return_types[:], - arg_types = argument_types[:], + arg_types = argument_types[:], } return symbol, true } -resolve_generic_function_ast :: proc(ast_context: ^AstContext, proc_lit: ast.Proc_Lit) -> (Symbol, bool) { +resolve_generic_function_ast :: proc( + ast_context: ^AstContext, + proc_lit: ast.Proc_Lit, +) -> ( + Symbol, + bool, +) { using ast if proc_lit.type.params == nil { - return Symbol {}, false + return Symbol{}, false } if proc_lit.type.results == nil { - return Symbol {}, false + return Symbol{}, false } if ast_context.call == nil { - return Symbol {}, false + return Symbol{}, false } - return resolve_generic_function_symbol(ast_context, proc_lit.type.params.list, proc_lit.type.results.list) + return resolve_generic_function_symbol( + ast_context, + proc_lit.type.params.list, + proc_lit.type.results.list, + ) } -is_symbol_same_typed :: proc(ast_context: ^AstContext, a, b: Symbol, flags: ast.Field_Flags = {}) -> bool { +is_symbol_same_typed :: proc( + ast_context: ^AstContext, + a, + b: Symbol, + flags: ast.Field_Flags = {}, +) -> bool { //relying on the fact that a is the call argument to avoid checking both sides for untyped. if untyped, ok := a.value.(SymbolUntypedValue); ok { if basic, ok := b.value.(SymbolBasicValue); ok { switch untyped.type { case .Integer: switch basic.ident.name { - case "int", "uint", "u32", "i32", "u8", "i8", "u64", "u16", "i16": return true - case: return false + case "int", "uint", "u32", "i32", "u8", "i8", "u64", "u16", "i16": + return true + case: + return false } case .Bool: switch basic.ident.name { - case "bool", "b32", "b64": return true - case: return false + case "bool", "b32", "b64": + return true + case: + return false } case .String: switch basic.ident.name { - case "string", "cstring": return true - case: return false + case "string", "cstring": + return true + case: + return false } case .Float: switch basic.ident.name { - case "f32", "f64": return true - case: return false + case "f32", "f64": + return true + case: + return false } } } @@ -538,12 +666,12 @@ is_symbol_same_typed :: proc(ast_context: ^AstContext, a, b: Symbol, flags: ast. return false } - if .Distinct in a.flags == .Distinct in b.flags && + if .Distinct in a.flags == .Distinct in b.flags && .Distinct in a.flags && a.name == b.name && a.pkg == b.pkg { return true - } + } #partial switch b_value in b.value { case SymbolBasicValue: @@ -553,9 +681,10 @@ is_symbol_same_typed :: proc(ast_context: ^AstContext, a, b: Symbol, flags: ast. //Temporary - make a function that finds the base type of basic values //This code only works with non distinct ints switch a.name { - case "int", "uint", "u32", "i32", "u8", "i8", "u64", "u16", "i16": return true + case "int", "uint", "u32", "i32", "u8", "i8", "u64", "u16", "i16": + return true } - } + } } #partial switch a_value in a.value { @@ -664,32 +793,47 @@ is_symbol_same_typed :: proc(ast_context: ^AstContext, a, b: Symbol, flags: ast. return false } - a_value_symbol, ok = resolve_type_expression(ast_context, a_value.value) + a_value_symbol, ok = resolve_type_expression( + ast_context, + a_value.value, + ) if !ok { return false } - b_value_symbol, ok = resolve_type_expression(ast_context, b_value.value) + b_value_symbol, ok = resolve_type_expression( + ast_context, + b_value.value, + ) if !ok { return false } - return is_symbol_same_typed(ast_context, a_key_symbol, b_key_symbol) && is_symbol_same_typed(ast_context, a_value_symbol, b_value_symbol) + return( + is_symbol_same_typed(ast_context, a_key_symbol, b_key_symbol) && + is_symbol_same_typed(ast_context, a_value_symbol, b_value_symbol) \ + ) } - + return false } -get_field_list_name_index :: proc(name: string, field_list: []^ast.Field) -> (int, bool) { +get_field_list_name_index :: proc( + name: string, + field_list: []^ast.Field, +) -> ( + int, + bool, +) { for field, i in field_list { for field_name in field.names { if ident, ok := field_name.derived.(^ast.Ident); ok { if name == ident.name { return i, true } - } + } } } @@ -699,7 +843,13 @@ get_field_list_name_index :: proc(name: string, field_list: []^ast.Field) -> (in /* Figure out which function the call expression is using out of the list from proc group */ -resolve_function_overload :: proc(ast_context: ^AstContext, group: ast.Proc_Group) -> (Symbol, bool) { +resolve_function_overload :: proc( + ast_context: ^AstContext, + group: ast.Proc_Group, +) -> ( + Symbol, + bool, +) { using ast call_expr := ast_context.call @@ -707,7 +857,8 @@ resolve_function_overload :: proc(ast_context: ^AstContext, group: ast.Proc_Grou 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 := resolve_type_expression(ast_context, arg_expr); + ok { if call_expr == nil || len(call_expr.args) == 0 { append(&candidates, f) break next_fn @@ -730,8 +881,8 @@ resolve_function_overload :: proc(ast_context: ^AstContext, group: ast.Proc_Grou ast_context.use_locals = true call_symbol: Symbol - arg_symbol: Symbol - ok: bool + arg_symbol: Symbol + ok: bool i := i if _, ok = arg.derived.(^ast.Bad_Expr); ok { @@ -739,22 +890,33 @@ resolve_function_overload :: proc(ast_context: ^AstContext, group: ast.Proc_Grou } //named parameter - if field, is_field := arg.derived.(^ast.Field_Value); is_field { - call_symbol, ok = resolve_type_expression(ast_context, field.value) + if field, is_field := arg.derived.(^ast.Field_Value); + is_field { + call_symbol, ok = resolve_type_expression( + ast_context, + field.value, + ) if !ok { break next_fn } - if ident, is_ident := field.field.derived.(^ast.Ident); is_ident { - i, ok = get_field_list_name_index(field.field.derived.(^ast.Ident).name, procedure.arg_types) + if ident, is_ident := field.field.derived.(^ast.Ident); + is_ident { + i, ok = get_field_list_name_index( + field.field.derived.(^ast.Ident).name, + procedure.arg_types, + ) } else { break next_fn } } else { - call_symbol, ok = resolve_type_expression(ast_context, arg) + call_symbol, ok = resolve_type_expression( + ast_context, + arg, + ) } - if !ok { + if !ok { break next_fn } @@ -762,48 +924,66 @@ resolve_function_overload :: proc(ast_context: ^AstContext, group: ast.Proc_Grou if len(p.return_types) != 1 { break next_fn } - if s, ok := resolve_type_expression(ast_context, p.return_types[0].type); ok { + if s, ok := resolve_type_expression( + ast_context, + p.return_types[0].type, + ); ok { call_symbol = s } } if procedure.arg_types[i].type != nil { - arg_symbol, ok = resolve_type_expression(ast_context, procedure.arg_types[i].type) - } else { - arg_symbol, ok = resolve_type_expression(ast_context, procedure.arg_types[i].default_value) + arg_symbol, ok = resolve_type_expression( + ast_context, + procedure.arg_types[i].type, + ) + } else { + arg_symbol, ok = resolve_type_expression( + ast_context, + procedure.arg_types[i].default_value, + ) } - if !ok { + if !ok { break next_fn } - if !is_symbol_same_typed(ast_context, call_symbol, arg_symbol, procedure.arg_types[i].flags) { + if !is_symbol_same_typed( + ast_context, + call_symbol, + arg_symbol, + procedure.arg_types[i].flags, + ) { break next_fn - } + } } - + append(&candidates, f) } } } if len(candidates) > 1 { - return Symbol { + return Symbol{ type = candidates[0].type, name = candidates[0].name, pkg = candidates[0].pkg, - value = SymbolAggregateValue { - symbols = candidates[:], - }, + value = SymbolAggregateValue{symbols = candidates[:]}, }, true } else if len(candidates) == 1 { return candidates[0], true } - return Symbol {}, false + return Symbol{}, false } -resolve_basic_lit :: proc(ast_context: ^AstContext, basic_lit: ast.Basic_Lit) -> (Symbol, bool) { +resolve_basic_lit :: proc( + ast_context: ^AstContext, + basic_lit: ast.Basic_Lit, +) -> ( + Symbol, + bool, +) { symbol := Symbol { type = .Constant, } @@ -826,10 +1006,22 @@ resolve_basic_lit :: proc(ast_context: ^AstContext, basic_lit: ast.Basic_Lit) -> return symbol, true } -resolve_basic_directive :: proc(ast_context: ^AstContext, directive: ast.Basic_Directive, a := #caller_location) -> (Symbol, bool) { +resolve_basic_directive :: proc( + ast_context: ^AstContext, + directive: ast.Basic_Directive, + a := #caller_location, +) -> ( + Symbol, + bool, +) { switch directive.name { case "caller_location": - ident := new_type(ast.Ident, directive.pos, directive.end, ast_context.allocator) + ident := new_type( + ast.Ident, + directive.pos, + directive.end, + ast_context.allocator, + ) ident.name = "Source_Code_Location" ast_context.current_package = ast_context.document_package return resolve_type_identifier(ast_context, ident^) @@ -839,7 +1031,13 @@ resolve_basic_directive :: proc(ast_context: ^AstContext, directive: ast.Basic_D } -resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (Symbol, bool) { +resolve_type_expression :: proc( + ast_context: ^AstContext, + node: ^ast.Expr, +) -> ( + Symbol, + bool, +) { if node == nil { return {}, false } @@ -865,33 +1063,74 @@ resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (S #partial switch v in node.derived { case ^Union_Type: - return make_symbol_union_from_ast(ast_context, v^, ast_context.field_name, true), true + return make_symbol_union_from_ast( + ast_context, + v^, + ast_context.field_name, + true, + ), true case ^Enum_Type: - return make_symbol_enum_from_ast(ast_context, v^, ast_context.field_name, true), true + return make_symbol_enum_from_ast( + ast_context, + v^, + ast_context.field_name, + true, + ), true case ^Struct_Type: - return make_symbol_struct_from_ast(ast_context, v^, ast_context.field_name, true), true + return make_symbol_struct_from_ast( + ast_context, + v^, + ast_context.field_name, + true, + ), true case ^Bit_Set_Type: - return make_symbol_bitset_from_ast(ast_context, v^, ast_context.field_name, true), true + return make_symbol_bitset_from_ast( + ast_context, + v^, + ast_context.field_name, + true, + ), true case ^Array_Type: - return make_symbol_array_from_ast(ast_context, v^, ast_context.field_name), true + return make_symbol_array_from_ast( + ast_context, + v^, + ast_context.field_name, + ), true case ^Dynamic_Array_Type: - return make_symbol_dynamic_array_from_ast(ast_context, v^, ast_context.field_name), true + return make_symbol_dynamic_array_from_ast( + ast_context, + v^, + ast_context.field_name, + ), true case ^Multi_Pointer_Type: - return make_symbol_multi_pointer_from_ast(ast_context, v^, ast_context.field_name), true + return make_symbol_multi_pointer_from_ast( + ast_context, + v^, + ast_context.field_name, + ), true case ^Map_Type: - return make_symbol_map_from_ast(ast_context, v^, ast_context.field_name), true + return make_symbol_map_from_ast( + ast_context, + v^, + ast_context.field_name, + ), true case ^Proc_Type: - return make_symbol_procedure_from_ast(ast_context, node, v^, ast_context.field_name), true + return make_symbol_procedure_from_ast( + ast_context, + node, + v^, + ast_context.field_name, + ), true 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_first_symbol_from_binary_expression(ast_context, v) case ^Ident: return 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 resolve_type_expression(ast_context, v.type) case ^Auto_Cast: return resolve_type_expression(ast_context, v.expr) case ^Comp_Lit: @@ -925,22 +1164,29 @@ resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (S 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 := 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(ast_context, union_value.types[0]) + return resolve_type_expression( + ast_context, + union_value.types[0], + ) } } } } else { return 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(ast_context, v.type.results.list[0].type) + return resolve_type_expression( + ast_context, + v.type.results.list[0].type, + ) } } case ^Pointer_Type: @@ -976,7 +1222,7 @@ resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (S ast_context.call = cast(^Call_Expr)node return resolve_type_expression(ast_context, v.expr) case ^Implicit_Selector_Expr: - return Symbol {}, false + return Symbol{}, false case ^Selector_Call_Expr: return resolve_type_expression(ast_context, v.expr) case ^Selector_Expr: @@ -987,8 +1233,14 @@ resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (S case SymbolFixedArrayValue: components_count := 0 for c in v.field.name { - if c == 'x' || c == 'y' || c == 'z' || c == 'w' || - c == 'r' || c == 'g' || c == 'b' || c == 'a' { + if c == 'x' || + c == 'y' || + c == 'z' || + c == 'w' || + c == 'r' || + c == 'g' || + c == 'b' || + c == 'a' { components_count += 1 } } @@ -1001,7 +1253,8 @@ resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (S if selector.pkg != "" { ast_context.current_package = selector.pkg } else { - ast_context.current_package = ast_context.document_package + ast_context.current_package = + ast_context.document_package } symbol, ok := resolve_type_expression(ast_context, s.expr) symbol.type = .Variable @@ -1009,7 +1262,10 @@ resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (S } else { value := SymbolFixedArrayValue { expr = s.expr, - len = make_int_basic_value(ast_context, components_count), + len = make_int_basic_value( + ast_context, + components_count, + ), } selector.value = value selector.type = .Variable @@ -1017,7 +1273,12 @@ resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (S } case SymbolProcedureValue: if len(s.return_types) == 1 { - selector_expr := new_type(ast.Selector_Expr, s.return_types[0].node.pos, s.return_types[0].node.end, ast_context.allocator) + selector_expr := new_type( + ast.Selector_Expr, + s.return_types[0].node.pos, + s.return_types[0].node.end, + ast_context.allocator, + ) selector_expr.expr = s.return_types[0].type selector_expr.field = v.field return resolve_type_expression(ast_context, selector_expr) @@ -1032,7 +1293,10 @@ resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (S 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(ast_context, s.types[i]) + symbol, ok := resolve_type_expression( + ast_context, + s.types[i], + ) symbol.type = .Variable return symbol, ok } @@ -1043,13 +1307,16 @@ resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (S try_build_package(ast_context.current_package) if v.field != nil { - return resolve_symbol_return(ast_context, lookup(v.field.name, selector.pkg)) + return resolve_symbol_return( + ast_context, + lookup(v.field.name, selector.pkg), + ) } else { - return Symbol {}, false + return Symbol{}, false } } } else { - return Symbol {}, false + return Symbol{}, false } case: log.warnf("default node kind, resolve_type_expression: %T", v) @@ -1058,10 +1325,17 @@ resolve_type_expression :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (S } } - return Symbol {}, false + return Symbol{}, false } -store_local :: proc(ast_context: ^AstContext, lhs: ^ast.Expr, rhs: ^ast.Expr, offset: int, name: string, id := 0) { +store_local :: proc( + ast_context: ^AstContext, + lhs: ^ast.Expr, + rhs: ^ast.Expr, + offset: int, + name: string, + id := 0, +) { local_stack := &ast_context.locals[id][name] if local_stack == nil { @@ -1070,18 +1344,32 @@ store_local :: proc(ast_context: ^AstContext, lhs: ^ast.Expr, rhs: ^ast.Expr, of local_stack = &locals[name] } - append(local_stack, DocumentLocal {lhs = lhs, rhs = rhs, offset = offset, id = id}) + append( + local_stack, + DocumentLocal{lhs = lhs, rhs = rhs, offset = offset, id = id}, + ) } add_local_group :: proc(ast_context: ^AstContext, id: int) { - ast_context.locals[id] = make(map[string][dynamic]DocumentLocal, 100, ast_context.allocator) + ast_context.locals[id] = make( + map[string][dynamic]DocumentLocal, + 100, + ast_context.allocator, + ) } clear_local_group :: proc(ast_context: ^AstContext, id: int) { ast_context.locals[id] = {} } -get_local_lhs_and_rhs :: proc(ast_context: ^AstContext, offset: int, name: string) -> (^ast.Expr, ^ast.Expr) { +get_local_lhs_and_rhs :: proc( + ast_context: ^AstContext, + offset: int, + name: string, +) -> ( + ^ast.Expr, + ^ast.Expr, +) { previous := 0 //is the local we are getting being declared? @@ -1104,31 +1392,43 @@ get_local_lhs_and_rhs :: proc(ast_context: ^AstContext, offset: int, name: strin return nil, nil } else { ret := local_stack[i - previous].rhs - if ident, ok := ret.derived.(^ast.Ident); ok && ident.name == name { + if ident, ok := ret.derived.(^ast.Ident); + ok && ident.name == name { if i - previous - 1 < 0 { return nil, nil } - if _, ok := ast_context.parameters[ident.name]; ok { - return local_stack[i - previous].lhs, local_stack[i - previous].rhs + if _, ok := ast_context.parameters[ident.name]; + ok { + return local_stack[i - + previous].lhs, local_stack[i - previous].rhs } } - return local_stack[i - previous].lhs, local_stack[i - previous].rhs; - } + return local_stack[i - + previous].lhs, local_stack[i - previous].rhs + } } } } } - + return nil, nil } -get_local :: proc(ast_context: ^AstContext, offset: int, name: string) -> ^ast.Expr { +get_local :: proc( + ast_context: ^AstContext, + offset: int, + name: string, +) -> ^ast.Expr { lhs, rhs := get_local_lhs_and_rhs(ast_context, offset, name) return rhs } -get_local_offset :: proc(ast_context: ^AstContext, offset: int, name: string) -> int { +get_local_offset :: proc( + ast_context: ^AstContext, + offset: int, + name: string, +) -> int { for _, locals in &ast_context.locals { if local_stack, ok := locals[name]; ok { for i := len(local_stack) - 1; i >= 0; i -= 1 { @@ -1137,7 +1437,7 @@ get_local_offset :: proc(ast_context: ^AstContext, offset: int, name: string) -> return -1 } else { return local_stack[i].offset - } + } } } } @@ -1146,7 +1446,13 @@ get_local_offset :: proc(ast_context: ^AstContext, offset: int, name: string) -> return -1 } -resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (Symbol, bool) { +resolve_type_identifier :: proc( + ast_context: ^AstContext, + node: ast.Ident, +) -> ( + Symbol, + bool, +) { using ast if ast_context.recursion_counter > 200 { @@ -1183,9 +1489,7 @@ resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (S type = .Keyword, signature = node.name, pkg = ast_context.current_package, - value = SymbolUntypedValue { - type = .Bool, - }, + value = SymbolUntypedValue{type = .Bool}, } case: symbol = Symbol { @@ -1193,9 +1497,7 @@ resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (S signature = node.name, name = ident.name, pkg = ast_context.current_package, - value = SymbolBasicValue { - ident = ident, - }, + value = SymbolBasicValue{ident = ident}, } } @@ -1206,20 +1508,21 @@ resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (S symbol := Symbol { type = .Package, pkg = imp.name, - value = SymbolPackageValue {}, + value = SymbolPackageValue{}, } return symbol, true } } - } - - if local := get_local(ast_context, node.pos.offset, node.name); local != nil && ast_context.use_locals { + } + + if local := get_local(ast_context, node.pos.offset, node.name); + local != nil && ast_context.use_locals { is_distinct := false if dist, ok := local.derived.(^ast.Distinct_Type); ok { if dist.type != nil { - local = dist.type + local = dist.type is_distinct = true } } @@ -1231,37 +1534,62 @@ resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (S case ^Ident: return_symbol, ok = resolve_type_identifier(ast_context, v^) case ^Union_Type: - return_symbol, ok = make_symbol_union_from_ast(ast_context, v^, node), true + return_symbol, ok = + make_symbol_union_from_ast(ast_context, v^, node), true return_symbol.name = node.name case ^Enum_Type: - return_symbol, ok = make_symbol_enum_from_ast(ast_context, v^, node), true + return_symbol, ok = + make_symbol_enum_from_ast(ast_context, v^, node), true return_symbol.name = node.name case ^Struct_Type: - return_symbol, ok = make_symbol_struct_from_ast(ast_context, v^, node), true + return_symbol, ok = + make_symbol_struct_from_ast(ast_context, v^, node), true return_symbol.name = node.name case ^Bit_Set_Type: - return_symbol, ok = make_symbol_bitset_from_ast(ast_context, v^, node), true + return_symbol, ok = + make_symbol_bitset_from_ast(ast_context, v^, node), true return_symbol.name = node.name case ^Proc_Lit: if !v.type.generic { - return_symbol, ok = make_symbol_procedure_from_ast(ast_context, local, v.type^, node), true + return_symbol, ok = + make_symbol_procedure_from_ast( + ast_context, + local, + v.type^, + node, + ), + true } else { - if return_symbol, ok = resolve_generic_function(ast_context, v^); !ok { - return_symbol, ok = make_symbol_procedure_from_ast(ast_context, local, v.type^, node), true + if return_symbol, ok = resolve_generic_function( + ast_context, + v^, + ); !ok { + return_symbol, ok = + make_symbol_procedure_from_ast( + ast_context, + local, + v.type^, + node, + ), + true } } case ^Proc_Group: return_symbol, ok = resolve_function_overload(ast_context, v^) case ^Array_Type: - return_symbol, ok = make_symbol_array_from_ast(ast_context, v^, node), true + return_symbol, ok = + make_symbol_array_from_ast(ast_context, v^, node), true case ^Dynamic_Array_Type: - return_symbol, ok = make_symbol_dynamic_array_from_ast(ast_context, v^, node), true + return_symbol, ok = + make_symbol_dynamic_array_from_ast(ast_context, v^, node), true case ^Map_Type: - return_symbol, ok = make_symbol_map_from_ast(ast_context, v^, node), true + return_symbol, ok = + make_symbol_map_from_ast(ast_context, v^, node), true case ^Basic_Lit: return_symbol, ok = resolve_basic_lit(ast_context, v^) return_symbol.name = node.name - return_symbol.type = ast_context.variables[node.name] ? .Variable : .Constant + return_symbol.type = + ast_context.variables[node.name] ? .Variable : .Constant case: return_symbol, ok = resolve_type_expression(ast_context, local) } @@ -1271,7 +1599,8 @@ resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (S return_symbol.flags |= {.Distinct} } - if is_variable, ok := ast_context.variables[node.name]; ok && is_variable { + if is_variable, ok := ast_context.variables[node.name]; + ok && is_variable { //return_symbol.name = node.name return_symbol.type = .Variable } @@ -1280,7 +1609,8 @@ resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (S return return_symbol, ok - } else if global, ok := ast_context.globals[node.name]; ast_context.use_globals && ok { + } else if global, ok := ast_context.globals[node.name]; + ast_context.use_globals && ok { is_distinct := false if dist, ok := global.expr.derived.(^ast.Distinct_Type); ok { @@ -1297,39 +1627,66 @@ resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (S case ^Ident: return_symbol, ok = resolve_type_identifier(ast_context, v^) case ^Struct_Type: - return_symbol, ok = make_symbol_struct_from_ast(ast_context, v^, node), true + return_symbol, ok = + make_symbol_struct_from_ast(ast_context, v^, node), true return_symbol.name = node.name case ^Bit_Set_Type: - return_symbol, ok = make_symbol_bitset_from_ast(ast_context, v^, node), true + return_symbol, ok = + make_symbol_bitset_from_ast(ast_context, v^, node), true return_symbol.name = node.name case ^Union_Type: - return_symbol, ok = make_symbol_union_from_ast(ast_context, v^, node), true + return_symbol, ok = + make_symbol_union_from_ast(ast_context, v^, node), true return_symbol.name = node.name case ^Enum_Type: - return_symbol, ok = make_symbol_enum_from_ast(ast_context, v^, node), true + return_symbol, ok = + make_symbol_enum_from_ast(ast_context, v^, node), true return_symbol.name = node.name case ^Proc_Lit: if !v.type.generic { - return_symbol, ok = make_symbol_procedure_from_ast(ast_context, global.expr, v.type^, node), true + return_symbol, ok = + make_symbol_procedure_from_ast( + ast_context, + global.expr, + v.type^, + node, + ), + true } else { - if return_symbol, ok = resolve_generic_function(ast_context, v^); !ok { - return_symbol, ok = make_symbol_procedure_from_ast(ast_context, global.expr, v.type^, node), true + if return_symbol, ok = resolve_generic_function( + ast_context, + v^, + ); !ok { + return_symbol, ok = + make_symbol_procedure_from_ast( + ast_context, + global.expr, + v.type^, + node, + ), + true } } case ^Proc_Group: return_symbol, ok = resolve_function_overload(ast_context, v^) case ^Array_Type: - return_symbol, ok = make_symbol_array_from_ast(ast_context, v^, node), true + return_symbol, ok = + make_symbol_array_from_ast(ast_context, v^, node), true case ^Dynamic_Array_Type: - return_symbol, ok = make_symbol_dynamic_array_from_ast(ast_context, v^, node), true + return_symbol, ok = + make_symbol_dynamic_array_from_ast(ast_context, v^, node), true case ^Map_Type: - return_symbol, ok = make_symbol_map_from_ast(ast_context, v^, node), true + return_symbol, ok = + make_symbol_map_from_ast(ast_context, v^, node), true case ^Basic_Lit: return_symbol, ok = resolve_basic_lit(ast_context, v^) return_symbol.name = node.name return_symbol.type = global.mutable ? .Variable : .Constant case: - return_symbol, ok = resolve_type_expression(ast_context, global.expr) + return_symbol, ok = resolve_type_expression( + ast_context, + global.expr, + ) } if is_distinct { @@ -1337,7 +1694,8 @@ resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (S return_symbol.flags |= {.Distinct} } - if is_variable, ok := ast_context.variables[node.name]; ok && is_variable { + if is_variable, ok := ast_context.variables[node.name]; + ok && is_variable { return_symbol.type = .Variable } @@ -1357,13 +1715,13 @@ resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (S symbol := Symbol { type = .Package, pkg = node.name, - value = SymbolPackageValue {}, + value = SymbolPackageValue{}, } try_build_package(symbol.pkg) return symbol, true - } + } //last option is to check the index if symbol, ok := lookup(node.name, ast_context.current_package); ok { @@ -1375,7 +1733,7 @@ resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (S symbol := Symbol { type = .Package, pkg = imp.name, - value = SymbolPackageValue {}, + value = SymbolPackageValue{}, } try_build_package(symbol.pkg) @@ -1408,10 +1766,14 @@ resolve_type_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (S } } - return Symbol {}, false + return Symbol{}, false } -expand_struct_usings :: proc(ast_context: ^AstContext, symbol: Symbol, value: SymbolStructValue) -> SymbolStructValue { +expand_struct_usings :: proc( + ast_context: ^AstContext, + symbol: Symbol, + value: SymbolStructValue, +) -> SymbolStructValue { names := slice.to_dynamic(value.names, ast_context.allocator) types := slice.to_dynamic(value.types, ast_context.allocator) ranges := slice.to_dynamic(value.ranges, ast_context.allocator) @@ -1444,19 +1806,22 @@ expand_struct_usings :: proc(ast_context: ^AstContext, symbol: Symbol, value: Sy for range in struct_value.ranges { append(&ranges, range) - } + } } } } - return { - names = names[:], - types = types[:], - ranges = ranges[:], - } + return {names = names[:], types = types[:], ranges = ranges[:]} } -resolve_symbol_return :: proc(ast_context: ^AstContext, symbol: Symbol, ok := true) -> (Symbol, bool) { +resolve_symbol_return :: proc( + ast_context: ^AstContext, + symbol: Symbol, + ok := true, +) -> ( + Symbol, + bool, +) { if !ok { return symbol, ok } @@ -1468,17 +1833,24 @@ resolve_symbol_return :: proc(ast_context: ^AstContext, symbol: Symbol, ok := tr return {}, false } } - + #partial switch v in &symbol.value { case SymbolProcedureGroupValue: - if symbol, ok := resolve_function_overload(ast_context, v.group.derived.(^ast.Proc_Group)^); ok { + if symbol, ok := resolve_function_overload( + ast_context, + v.group.derived.(^ast.Proc_Group)^, + ); ok { return symbol, true } else { return symbol, false } case SymbolProcedureValue: if v.generic { - if resolved_symbol, ok := resolve_generic_function(ast_context, v.arg_types, v.return_types); ok { + if resolved_symbol, ok := resolve_generic_function( + ast_context, + v.arg_types, + v.return_types, + ); ok { return resolved_symbol, ok } else { return symbol, true @@ -1512,7 +1884,7 @@ resolve_symbol_return :: proc(ast_context: ^AstContext, symbol: Symbol, ok := tr expanded.value = expand_struct_usings(ast_context, symbol, v) return expanded, true } else { - return symbol, true + return symbol, true } case SymbolGenericValue: ret, ok := resolve_type_expression(ast_context, v.expr) @@ -1525,7 +1897,10 @@ resolve_symbol_return :: proc(ast_context: ^AstContext, symbol: Symbol, ok := tr return symbol, true } -resolve_unresolved_symbol :: proc(ast_context: ^AstContext, symbol: ^Symbol) -> bool { +resolve_unresolved_symbol :: proc( + ast_context: ^AstContext, + symbol: ^Symbol, +) -> bool { if symbol.type != .Unresolved { return true } @@ -1533,15 +1908,15 @@ resolve_unresolved_symbol :: proc(ast_context: ^AstContext, symbol: ^Symbol) -> #partial switch v in symbol.value { case SymbolStructValue: symbol.type = .Struct - case SymbolPackageValue: + case SymbolPackageValue: symbol.type = .Package - case SymbolProcedureValue, SymbolProcedureGroupValue: + case SymbolProcedureValue, SymbolProcedureGroupValue: symbol.type = .Function - case SymbolUnionValue: + case SymbolUnionValue: symbol.type = .Enum - case SymbolEnumValue: + case SymbolEnumValue: symbol.type = .Enum - case SymbolBitSetValue: + case SymbolBitSetValue: symbol.type = .Enum case SymbolGenericValue: ast_context.current_package = symbol.pkg @@ -1556,17 +1931,30 @@ resolve_unresolved_symbol :: proc(ast_context: ^AstContext, symbol: ^Symbol) -> return true } -resolve_location_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) -> (Symbol, bool) { +resolve_location_identifier :: proc( + ast_context: ^AstContext, + node: ast.Ident, +) -> ( + Symbol, + bool, +) { symbol: Symbol - if local, _ := get_local_lhs_and_rhs(ast_context, node.pos.offset, node.name); local != nil { + if local, _ := get_local_lhs_and_rhs( + ast_context, + node.pos.offset, + node.name, + ); local != nil { symbol.range = common.get_token_range(local, ast_context.file.src) uri := common.create_uri(local.pos.file, ast_context.allocator) symbol.pkg = ast_context.document_package symbol.uri = uri.uri return symbol, true } else if global, ok := ast_context.globals[node.name]; ok { - symbol.range = common.get_token_range(global.expr, ast_context.file.src) + symbol.range = common.get_token_range( + global.expr, + ast_context.file.src, + ) uri := common.create_uri(global.expr.pos.file, ast_context.allocator) symbol.pkg = ast_context.document_package symbol.uri = uri.uri @@ -1588,7 +1976,13 @@ resolve_location_identifier :: proc(ast_context: ^AstContext, node: ast.Ident) - return {}, false } -resolve_location_selector :: proc(ast_context: ^AstContext, selector: ^ast.Selector_Expr) -> (Symbol, bool) { +resolve_location_selector :: proc( + ast_context: ^AstContext, + selector: ^ast.Selector_Expr, +) -> ( + Symbol, + bool, +) { ast_context.use_locals = true ast_context.use_globals = true ast_context.current_package = ast_context.document_package @@ -1628,7 +2022,13 @@ resolve_location_selector :: proc(ast_context: ^AstContext, selector: ^ast.Selec } -resolve_first_symbol_from_binary_expression :: proc(ast_context: ^AstContext, binary: ^ast.Binary_Expr) -> (Symbol, bool) { +resolve_first_symbol_from_binary_expression :: proc( + ast_context: ^AstContext, + binary: ^ast.Binary_Expr, +) -> ( + Symbol, + bool, +) { //Fairly simple function to find the earliest identifier symbol in binary expression. if binary.left != nil { @@ -1638,7 +2038,10 @@ resolve_first_symbol_from_binary_expression :: proc(ast_context: ^AstContext, bi return s, ok } } else if _, ok := binary.left.derived.(^ast.Binary_Expr); ok { - if s, ok := resolve_first_symbol_from_binary_expression(ast_context, cast(^ast.Binary_Expr)binary.left); ok { + if s, ok := resolve_first_symbol_from_binary_expression( + ast_context, + cast(^ast.Binary_Expr)binary.left, + ); ok { return s, ok } } @@ -1650,7 +2053,10 @@ resolve_first_symbol_from_binary_expression :: proc(ast_context: ^AstContext, bi return s, ok } } else if _, ok := binary.right.derived.(^ast.Binary_Expr); ok { - if s, ok := resolve_first_symbol_from_binary_expression(ast_context, cast(^ast.Binary_Expr)binary.right); ok { + if s, ok := resolve_first_symbol_from_binary_expression( + ast_context, + cast(^ast.Binary_Expr)binary.right, + ); ok { return s, ok } } @@ -1659,7 +2065,13 @@ resolve_first_symbol_from_binary_expression :: proc(ast_context: ^AstContext, bi return {}, false } -find_position_in_call_param :: proc(ast_context: ^AstContext, call: ast.Call_Expr) -> (int, bool) { +find_position_in_call_param :: proc( + ast_context: ^AstContext, + call: ast.Call_Expr, +) -> ( + int, + bool, +) { if call.args == nil { return 0, false } @@ -1673,8 +2085,16 @@ find_position_in_call_param :: proc(ast_context: ^AstContext, call: ast.Call_Exp return len(call.args) - 1, true } -make_pointer_ast :: proc(ast_context: ^AstContext, elem: ^ast.Expr) -> ^ast.Pointer_Type { - pointer := new_type(ast.Pointer_Type, elem.pos, elem.end, ast_context.allocator) +make_pointer_ast :: proc( + ast_context: ^AstContext, + elem: ^ast.Expr, +) -> ^ast.Pointer_Type { + pointer := new_type( + ast.Pointer_Type, + elem.pos, + elem.end, + ast_context.allocator, + ) pointer.elem = elem return pointer } @@ -1691,10 +2111,13 @@ make_int_ast :: proc(ast_context: ^AstContext) -> ^ast.Ident { return ident } -make_int_basic_value :: proc(ast_context: ^AstContext, n: int) -> ^ast.Basic_Lit { +make_int_basic_value :: proc( + ast_context: ^AstContext, + n: int, +) -> ^ast.Basic_Lit { basic := new_type(ast.Basic_Lit, {}, {}, ast_context.allocator) basic.tok.text = fmt.tprintf("%v", n) - return basic + return basic } get_package_from_node :: proc(node: ast.Node) -> string { @@ -1722,16 +2145,21 @@ get_using_packages :: proc(ast_context: ^AstContext) -> []string { return usings } -make_symbol_procedure_from_ast :: proc(ast_context: ^AstContext, n: ^ast.Node, v: ast.Proc_Type, name: ast.Ident) -> Symbol { +make_symbol_procedure_from_ast :: proc( + ast_context: ^AstContext, + n: ^ast.Node, + v: ast.Proc_Type, + name: ast.Ident, +) -> Symbol { symbol := Symbol { range = common.get_token_range(n^, ast_context.file.src), - type = .Function, - pkg = get_package_from_node(n^), - name = name.name, + type = .Function, + pkg = get_package_from_node(n^), + name = name.name, } return_types := make([dynamic]^ast.Field, ast_context.allocator) - arg_types := make([dynamic]^ast.Field, ast_context.allocator) + arg_types := make([dynamic]^ast.Field, ast_context.allocator) if v.results != nil { for ret in v.results.list { @@ -1753,25 +2181,29 @@ make_symbol_procedure_from_ast :: proc(ast_context: ^AstContext, n: ^ast.Node, v symbol.value = SymbolProcedureValue { return_types = return_types[:], - arg_types = arg_types[:], - generic = v.generic, + arg_types = arg_types[:], + generic = v.generic, } return symbol } -make_symbol_array_from_ast :: proc(ast_context: ^AstContext, v: ast.Array_Type, name: ast.Ident) -> Symbol { +make_symbol_array_from_ast :: proc( + ast_context: ^AstContext, + v: ast.Array_Type, + name: ast.Ident, +) -> Symbol { symbol := Symbol { range = common.get_token_range(v.node, ast_context.file.src), - type = .Variable, - pkg = get_package_from_node(v.node), - name = name.name, + type = .Variable, + pkg = get_package_from_node(v.node), + name = name.name, } if v.len != nil { symbol.value = SymbolFixedArrayValue { expr = v.elem, - len = v.len, + len = v.len, } } else { symbol.value = SymbolSliceValue { @@ -1782,12 +2214,16 @@ make_symbol_array_from_ast :: proc(ast_context: ^AstContext, v: ast.Array_Type, return symbol } -make_symbol_dynamic_array_from_ast :: proc(ast_context: ^AstContext, v: ast.Dynamic_Array_Type, name: ast.Ident) -> Symbol { +make_symbol_dynamic_array_from_ast :: proc( + ast_context: ^AstContext, + v: ast.Dynamic_Array_Type, + name: ast.Ident, +) -> Symbol { symbol := Symbol { range = common.get_token_range(v.node, ast_context.file.src), - type = .Variable, - pkg = get_package_from_node(v.node), - name = name.name, + type = .Variable, + pkg = get_package_from_node(v.node), + name = name.name, } symbol.value = SymbolDynamicArrayValue { @@ -1797,12 +2233,16 @@ make_symbol_dynamic_array_from_ast :: proc(ast_context: ^AstContext, v: ast.Dyna return symbol } -make_symbol_multi_pointer_from_ast :: proc(ast_context: ^AstContext, v: ast.Multi_Pointer_Type, name: ast.Ident) -> Symbol { +make_symbol_multi_pointer_from_ast :: proc( + ast_context: ^AstContext, + v: ast.Multi_Pointer_Type, + name: ast.Ident, +) -> Symbol { symbol := Symbol { range = common.get_token_range(v.node, ast_context.file.src), - type = .Variable, - pkg = get_package_from_node(v.node), - name = name.name, + type = .Variable, + pkg = get_package_from_node(v.node), + name = name.name, } symbol.value = SymbolMultiPointer { @@ -1812,27 +2252,35 @@ make_symbol_multi_pointer_from_ast :: proc(ast_context: ^AstContext, v: ast.Mult return symbol } -make_symbol_map_from_ast :: proc(ast_context: ^AstContext, v: ast.Map_Type, name: ast.Ident) -> Symbol { +make_symbol_map_from_ast :: proc( + ast_context: ^AstContext, + v: ast.Map_Type, + name: ast.Ident, +) -> Symbol { symbol := Symbol { range = common.get_token_range(v.node, ast_context.file.src), - type = .Variable, - pkg = get_package_from_node(v.node), - name = name.name, + type = .Variable, + pkg = get_package_from_node(v.node), + name = name.name, } symbol.value = SymbolMapValue { - key = v.key, + key = v.key, value = v.value, } return symbol } -make_symbol_basic_type_from_ast :: proc(ast_context: ^AstContext, n: ^ast.Node, v: ^ast.Ident) -> Symbol { +make_symbol_basic_type_from_ast :: proc( + ast_context: ^AstContext, + n: ^ast.Node, + v: ^ast.Ident, +) -> Symbol { symbol := Symbol { range = common.get_token_range(n^, ast_context.file.src), - type = .Variable, - pkg = get_package_from_node(n^), + type = .Variable, + pkg = get_package_from_node(n^), } symbol.value = SymbolBasicValue { @@ -1842,12 +2290,17 @@ make_symbol_basic_type_from_ast :: proc(ast_context: ^AstContext, n: ^ast.Node, return symbol } -make_symbol_union_from_ast :: proc(ast_context: ^AstContext, v: ast.Union_Type, ident: ast.Ident, inlined := false) -> Symbol { +make_symbol_union_from_ast :: proc( + ast_context: ^AstContext, + v: ast.Union_Type, + ident: ast.Ident, + inlined := false, +) -> Symbol { symbol := Symbol { range = common.get_token_range(v, ast_context.file.src), - type = .Union, - pkg = get_package_from_node(v.node), - name = ident.name, + type = .Union, + pkg = get_package_from_node(v.node), + name = ident.name, } if inlined { @@ -1855,7 +2308,7 @@ make_symbol_union_from_ast :: proc(ast_context: ^AstContext, v: ast.Union_Type, symbol.name = "union" } - types := make([dynamic]^ast.Expr, ast_context.allocator) + types := make([dynamic]^ast.Expr, ast_context.allocator) for variant in v.variants { if v.poly_params != nil { @@ -1876,12 +2329,17 @@ make_symbol_union_from_ast :: proc(ast_context: ^AstContext, v: ast.Union_Type, return symbol } -make_symbol_enum_from_ast :: proc(ast_context: ^AstContext, v: ast.Enum_Type, ident: ast.Ident, inlined := false) -> Symbol { +make_symbol_enum_from_ast :: proc( + ast_context: ^AstContext, + v: ast.Enum_Type, + ident: ast.Ident, + inlined := false, +) -> Symbol { symbol := Symbol { range = common.get_token_range(v, ast_context.file.src), - type = .Enum, - name = ident.name, - pkg = get_package_from_node(v.node), + type = .Enum, + name = ident.name, + pkg = get_package_from_node(v.node), } if inlined { @@ -1898,9 +2356,10 @@ make_symbol_enum_from_ast :: proc(ast_context: ^AstContext, v: ast.Enum_Type, id } else if field, ok := n.derived.(^ast.Field_Value); ok { if ident, ok := field.field.derived.(^ast.Ident); ok { append(&names, ident.name) - } else if binary, ok := field.field.derived.(^ast.Binary_Expr); ok { + } else if binary, ok := field.field.derived.(^ast.Binary_Expr); + ok { append(&names, binary.left.derived.(^ast.Ident).name) - } + } } } @@ -1911,12 +2370,17 @@ make_symbol_enum_from_ast :: proc(ast_context: ^AstContext, v: ast.Enum_Type, id return symbol } -make_symbol_bitset_from_ast :: proc(ast_context: ^AstContext, v: ast.Bit_Set_Type, ident: ast.Ident, inlined := false) -> Symbol { +make_symbol_bitset_from_ast :: proc( + ast_context: ^AstContext, + v: ast.Bit_Set_Type, + ident: ast.Ident, + inlined := false, +) -> Symbol { symbol := Symbol { range = common.get_token_range(v, ast_context.file.src), - type = .Enum, - name = ident.name, - pkg = get_package_from_node(v.node), + type = .Enum, + name = ident.name, + pkg = get_package_from_node(v.node), } if inlined { @@ -1931,12 +2395,17 @@ make_symbol_bitset_from_ast :: proc(ast_context: ^AstContext, v: ast.Bit_Set_Typ return symbol } -make_symbol_struct_from_ast :: proc(ast_context: ^AstContext, v: ast.Struct_Type, ident: ast.Ident, inlined := false) -> Symbol { +make_symbol_struct_from_ast :: proc( + ast_context: ^AstContext, + v: ast.Struct_Type, + ident: ast.Ident, + inlined := false, +) -> Symbol { symbol := Symbol { range = common.get_token_range(v, ast_context.file.src), - type = .Struct, - pkg = get_package_from_node(v.node), - name = ident.name, + type = .Struct, + pkg = get_package_from_node(v.node), + name = ident.name, } if inlined { @@ -1951,13 +2420,17 @@ make_symbol_struct_from_ast :: proc(ast_context: ^AstContext, v: ast.Struct_Type for field in v.fields.list { for n in field.names { - if identifier, ok := n.derived.(^ast.Ident); ok && field.type != nil { + if identifier, ok := n.derived.(^ast.Ident); + ok && field.type != nil { if identifier.name == "_" { continue } append(&names, identifier.name) if v.poly_params != nil { - append(&types, clone_type(field.type, ast_context.allocator, nil)) + append( + &types, + clone_type(field.type, ast_context.allocator, nil), + ) } else { append(&types, field.type) } @@ -1965,14 +2438,17 @@ make_symbol_struct_from_ast :: proc(ast_context: ^AstContext, v: ast.Struct_Type usings[identifier.name] = true } - append(&ranges, common.get_token_range(n, ast_context.file.src)) + append( + &ranges, + common.get_token_range(n, ast_context.file.src), + ) } } } symbol.value = SymbolStructValue { - names = names[:], - types = types[:], + names = names[:], + types = types[:], ranges = ranges[:], usings = usings, } @@ -1983,13 +2459,21 @@ make_symbol_struct_from_ast :: proc(ast_context: ^AstContext, v: ast.Struct_Type //TODO change the expand to not double copy the array, but just pass the dynamic arrays if len(usings) > 0 { - symbol.value = expand_struct_usings(ast_context, symbol, symbol.value.(SymbolStructValue)) + symbol.value = expand_struct_usings( + ast_context, + symbol, + symbol.value.(SymbolStructValue), + ) } return symbol } -resolve_poly_union :: proc(ast_context: ^AstContext, poly_params: ^ast.Field_List, symbol: ^Symbol) { +resolve_poly_union :: proc( + ast_context: ^AstContext, + poly_params: ^ast.Field_List, + symbol: ^Symbol, +) { if ast_context.call == nil { return } @@ -2013,11 +2497,11 @@ resolve_poly_union :: proc(ast_context: ^AstContext, poly_params: ^ast.Field_Lis if param.type == nil { continue } - + if poly, ok := param.type.derived.(^ast.Typeid_Type); ok { if ident, ok := name.derived.(^ast.Ident); ok { poly_map[ident.name] = ast_context.call.args[i] - } else if poly, ok := name.derived.(^ast.Poly_Type); ok { + } else if poly, ok := name.derived.(^ast.Poly_Type); ok { if poly.type != nil { poly_map[poly.type.name] = ast_context.call.args[i] } @@ -2027,7 +2511,7 @@ resolve_poly_union :: proc(ast_context: ^AstContext, poly_params: ^ast.Field_Lis i += 1 } } - + for type, i in symbol_value.types { if ident, ok := type.derived.(^ast.Ident); ok { if expr, ok := poly_map[ident.name]; ok { @@ -2049,7 +2533,11 @@ resolve_poly_union :: proc(ast_context: ^AstContext, poly_params: ^ast.Field_Lis } } -resolve_poly_struct :: proc(ast_context: ^AstContext, poly_params: ^ast.Field_List, symbol: ^Symbol) { +resolve_poly_struct :: proc( + ast_context: ^AstContext, + poly_params: ^ast.Field_List, + symbol: ^Symbol, +) { if ast_context.call == nil { return } @@ -2073,11 +2561,11 @@ resolve_poly_struct :: proc(ast_context: ^AstContext, poly_params: ^ast.Field_Li if param.type == nil { continue } - + if poly, ok := param.type.derived.(^ast.Typeid_Type); ok { if ident, ok := name.derived.(^ast.Ident); ok { poly_map[ident.name] = ast_context.call.args[i] - } else if poly, ok := name.derived.(^ast.Poly_Type); ok { + } else if poly, ok := name.derived.(^ast.Poly_Type); ok { if poly.type != nil { poly_map[poly.type.name] = ast_context.call.args[i] } @@ -2087,7 +2575,7 @@ resolve_poly_struct :: proc(ast_context: ^AstContext, poly_params: ^ast.Field_Li i += 1 } } - + for type, i in symbol_value.types { if ident, ok := type.derived.(^ast.Ident); ok { if expr, ok := poly_map[ident.name]; ok { @@ -2120,7 +2608,12 @@ get_globals :: proc(file: ast.File, ast_context: ^AstContext) { } } -get_generic_assignment :: proc(file: ast.File, value: ^ast.Expr, ast_context: ^AstContext, results: ^[dynamic]^ast.Expr) { +get_generic_assignment :: proc( + file: ast.File, + value: ^ast.Expr, + ast_context: ^AstContext, + results: ^[dynamic]^ast.Expr, +) { using ast ast_context.use_locals = true @@ -2131,7 +2624,7 @@ get_generic_assignment :: proc(file: ast.File, value: ^ast.Expr, ast_context: ^A get_generic_assignment(file, v.expr, ast_context, results) case ^Call_Expr: ast_context.call = cast(^ast.Call_Expr)value - + if symbol, ok := resolve_type_expression(ast_context, v.expr); ok { if procedure, ok := symbol.value.(SymbolProcedureValue); ok { for ret in procedure.return_types { @@ -2157,7 +2650,8 @@ get_generic_assignment :: proc(file: ast.File, value: ^ast.Expr, ast_context: ^A } case ^Type_Assertion: if v.type != nil { - if unary, ok := v.type.derived.(^ast.Unary_Expr); ok && unary.op.kind == .Question { + if unary, ok := v.type.derived.(^ast.Unary_Expr); + ok && unary.op.kind == .Question { append(results, cast(^ast.Expr)&v.node) } else { append(results, v.type) @@ -2173,7 +2667,11 @@ get_generic_assignment :: proc(file: ast.File, value: ^ast.Expr, ast_context: ^A } } -get_locals_value_decl :: proc(file: ast.File, value_decl: ast.Value_Decl, ast_context: ^AstContext) { +get_locals_value_decl :: proc( + file: ast.File, + value_decl: ast.Value_Decl, + ast_context: ^AstContext, +) { using ast if len(value_decl.names) <= 0 { @@ -2184,7 +2682,14 @@ get_locals_value_decl :: proc(file: ast.File, value_decl: ast.Value_Decl, ast_co for name, i in value_decl.names { str := common.get_ast_node_string(value_decl.names[i], file.src) ast_context.variables[str] = value_decl.is_mutable - store_local(ast_context, name, value_decl.type, value_decl.end.offset, str, ast_context.local_id) + store_local( + ast_context, + name, + value_decl.type, + value_decl.end.offset, + str, + ast_context.local_id, + ) } return } @@ -2200,15 +2705,28 @@ get_locals_value_decl :: proc(file: ast.File, value_decl: ast.Value_Decl, ast_co } for name, i in value_decl.names { - result_i := min(len(results)-1, i) + result_i := min(len(results) - 1, i) str := common.get_ast_node_string(name, file.src) ast_context.in_package[str] = get_package_from_node(results[result_i]^) - store_local(ast_context, name, results[result_i], value_decl.end.offset, str, ast_context.local_id) + store_local( + ast_context, + name, + results[result_i], + value_decl.end.offset, + str, + ast_context.local_id, + ) ast_context.variables[str] = value_decl.is_mutable } } -get_locals_stmt :: proc(file: ast.File, stmt: ^ast.Stmt, ast_context: ^AstContext, document_position: ^DocumentPositionContext, save_assign := false) { +get_locals_stmt :: proc( + file: ast.File, + stmt: ^ast.Stmt, + ast_context: ^AstContext, + document_position: ^DocumentPositionContext, + save_assign := false, +) { ast_context.use_locals = true ast_context.use_globals = true ast_context.current_package = ast_context.document_package @@ -2256,12 +2774,18 @@ get_locals_stmt :: proc(file: ast.File, stmt: ^ast.Stmt, ast_context: ^AstContex get_locals_stmt(file, stmt, ast_context, document_position) } case: - //log.debugf("default node local stmt %v", v); + //log.debugf("default node local stmt %v", v); } } -get_locals_block_stmt :: proc(file: ast.File, block: ast.Block_Stmt, ast_context: ^AstContext, document_position: ^DocumentPositionContext) { - if !(block.pos.offset <= document_position.position && document_position.position <= block.end.offset) { +get_locals_block_stmt :: proc( + file: ast.File, + block: ast.Block_Stmt, + ast_context: ^AstContext, + document_position: ^DocumentPositionContext, +) { + if !(block.pos.offset <= document_position.position && + document_position.position <= block.end.offset) { return } @@ -2280,11 +2804,28 @@ get_locals_using_stmt :: proc(stmt: ast.Using_Stmt, ast_context: ^AstContext) { } case SymbolStructValue: for name, i in v.names { - selector := new_type(ast.Selector_Expr, v.types[i].pos, v.types[i].end, ast_context.allocator) + selector := new_type( + ast.Selector_Expr, + v.types[i].pos, + v.types[i].end, + ast_context.allocator, + ) selector.expr = u - selector.field = new_type(ast.Ident, v.types[i].pos, v.types[i].end, ast_context.allocator) + selector.field = new_type( + ast.Ident, + v.types[i].pos, + v.types[i].end, + ast_context.allocator, + ) selector.field.name = name - store_local(ast_context, u, selector, 0, name, ast_context.local_id) + store_local( + ast_context, + u, + selector, + 0, + name, + ast_context.local_id, + ) ast_context.variables[name] = true } } @@ -2292,7 +2833,11 @@ get_locals_using_stmt :: proc(stmt: ast.Using_Stmt, ast_context: ^AstContext) { } } -get_locals_assign_stmt :: proc(file: ast.File, stmt: ast.Assign_Stmt, ast_context: ^AstContext) { +get_locals_assign_stmt :: proc( + file: ast.File, + stmt: ast.Assign_Stmt, + ast_context: ^AstContext, +) { using ast if stmt.lhs == nil || stmt.rhs == nil { @@ -2311,14 +2856,27 @@ get_locals_assign_stmt :: proc(file: ast.File, stmt: ast.Assign_Stmt, ast_contex for lhs, i in stmt.lhs { if ident, ok := lhs.derived.(^ast.Ident); ok { - store_local(ast_context, lhs, results[i], ident.pos.offset, ident.name, ast_context.local_id) + store_local( + ast_context, + lhs, + results[i], + ident.pos.offset, + ident.name, + ast_context.local_id, + ) ast_context.variables[ident.name] = true } } } -get_locals_if_stmt :: proc(file: ast.File, stmt: ast.If_Stmt, ast_context: ^AstContext, document_position: ^DocumentPositionContext) { - if !(stmt.pos.offset <= document_position.position && document_position.position <= stmt.end.offset) { +get_locals_if_stmt :: proc( + file: ast.File, + stmt: ast.If_Stmt, + ast_context: ^AstContext, + document_position: ^DocumentPositionContext, +) { + if !(stmt.pos.offset <= document_position.position && + document_position.position <= stmt.end.offset) { return } @@ -2327,10 +2885,16 @@ get_locals_if_stmt :: proc(file: ast.File, stmt: ast.If_Stmt, ast_context: ^AstC get_locals_stmt(file, stmt.else_stmt, ast_context, document_position) } -get_locals_for_range_stmt :: proc(file: ast.File, stmt: ast.Range_Stmt, ast_context: ^AstContext, document_position: ^DocumentPositionContext) { +get_locals_for_range_stmt :: proc( + file: ast.File, + stmt: ast.Range_Stmt, + ast_context: ^AstContext, + document_position: ^DocumentPositionContext, +) { using ast - if !(stmt.body.pos.offset <= document_position.position && document_position.position <= stmt.body.end.offset) { + if !(stmt.body.pos.offset <= document_position.position && + document_position.position <= stmt.body.end.offset) { return } @@ -2344,7 +2908,14 @@ get_locals_for_range_stmt :: proc(file: ast.File, stmt: ast.Range_Stmt, ast_cont if binary.op.kind == .Range_Half { if len(stmt.vals) >= 1 { if ident, ok := stmt.vals[0].derived.(^Ident); ok { - store_local(ast_context, ident, make_int_ast(ast_context), ident.pos.offset, ident.name, ast_context.local_id) + store_local( + ast_context, + ident, + make_int_ast(ast_context), + ident.pos.offset, + ident.name, + ast_context.local_id, + ) ast_context.variables[ident.name] = true } } @@ -2356,14 +2927,28 @@ get_locals_for_range_stmt :: proc(file: ast.File, stmt: ast.Range_Stmt, ast_cont case SymbolMapValue: if len(stmt.vals) >= 1 { if ident, ok := stmt.vals[0].derived.(^Ident); ok { - store_local(ast_context, ident, v.key, ident.pos.offset, ident.name, ast_context.local_id) + store_local( + ast_context, + ident, + v.key, + ident.pos.offset, + ident.name, + ast_context.local_id, + ) ast_context.variables[ident.name] = true ast_context.in_package[ident.name] = symbol.pkg } } if len(stmt.vals) >= 2 { if ident, ok := stmt.vals[1].derived.(^Ident); ok { - store_local(ast_context, ident, v.value, ident.pos.offset, ident.name, ast_context.local_id) + store_local( + ast_context, + ident, + v.value, + ident.pos.offset, + ident.name, + ast_context.local_id, + ) ast_context.variables[ident.name] = true ast_context.in_package[ident.name] = symbol.pkg } @@ -2371,14 +2956,28 @@ get_locals_for_range_stmt :: proc(file: ast.File, stmt: ast.Range_Stmt, ast_cont case SymbolDynamicArrayValue: if len(stmt.vals) >= 1 { if ident, ok := stmt.vals[0].derived.(^Ident); ok { - store_local(ast_context, ident, v.expr, ident.pos.offset, ident.name, ast_context.local_id) + store_local( + ast_context, + ident, + v.expr, + ident.pos.offset, + ident.name, + ast_context.local_id, + ) ast_context.variables[ident.name] = true ast_context.in_package[ident.name] = symbol.pkg } } if len(stmt.vals) >= 2 { if ident, ok := stmt.vals[1].derived.(^Ident); ok { - store_local(ast_context, ident, make_int_ast(ast_context), ident.pos.offset, ident.name, ast_context.local_id) + store_local( + ast_context, + ident, + make_int_ast(ast_context), + ident.pos.offset, + ident.name, + ast_context.local_id, + ) ast_context.variables[ident.name] = true ast_context.in_package[ident.name] = symbol.pkg } @@ -2386,7 +2985,14 @@ get_locals_for_range_stmt :: proc(file: ast.File, stmt: ast.Range_Stmt, ast_cont case SymbolFixedArrayValue: if len(stmt.vals) >= 1 { if ident, ok := stmt.vals[0].derived.(^Ident); ok { - store_local(ast_context, ident, v.expr, ident.pos.offset, ident.name, ast_context.local_id) + store_local( + ast_context, + ident, + v.expr, + ident.pos.offset, + ident.name, + ast_context.local_id, + ) ast_context.variables[ident.name] = true ast_context.in_package[ident.name] = symbol.pkg } @@ -2394,7 +3000,14 @@ get_locals_for_range_stmt :: proc(file: ast.File, stmt: ast.Range_Stmt, ast_cont if len(stmt.vals) >= 2 { if ident, ok := stmt.vals[1].derived.(^Ident); ok { - store_local(ast_context, ident, make_int_ast(ast_context), ident.pos.offset, ident.name, ast_context.local_id) + store_local( + ast_context, + ident, + make_int_ast(ast_context), + ident.pos.offset, + ident.name, + ast_context.local_id, + ) ast_context.variables[ident.name] = true ast_context.in_package[ident.name] = symbol.pkg } @@ -2402,26 +3015,46 @@ get_locals_for_range_stmt :: proc(file: ast.File, stmt: ast.Range_Stmt, ast_cont case SymbolSliceValue: if len(stmt.vals) >= 1 { if ident, ok := stmt.vals[0].derived.(^Ident); ok { - store_local(ast_context, ident, v.expr, ident.pos.offset, ident.name, ast_context.local_id) + store_local( + ast_context, + ident, + v.expr, + ident.pos.offset, + ident.name, + ast_context.local_id, + ) ast_context.variables[ident.name] = true ast_context.in_package[ident.name] = symbol.pkg } } if len(stmt.vals) >= 2 { if ident, ok := stmt.vals[1].derived.(^Ident); ok { - store_local(ast_context, ident, make_int_ast(ast_context), ident.pos.offset, ident.name, ast_context.local_id) + store_local( + ast_context, + ident, + make_int_ast(ast_context), + ident.pos.offset, + ident.name, + ast_context.local_id, + ) ast_context.variables[ident.name] = true ast_context.in_package[ident.name] = symbol.pkg } } } } - + get_locals_stmt(file, stmt.body, ast_context, document_position) } -get_locals_for_stmt :: proc(file: ast.File, stmt: ast.For_Stmt, ast_context: ^AstContext, document_position: ^DocumentPositionContext) { - if !(stmt.pos.offset <= document_position.position && document_position.position <= stmt.end.offset) { +get_locals_for_stmt :: proc( + file: ast.File, + stmt: ast.For_Stmt, + ast_context: ^AstContext, + document_position: ^DocumentPositionContext, +) { + if !(stmt.pos.offset <= document_position.position && + document_position.position <= stmt.end.offset) { return } @@ -2429,18 +3062,30 @@ get_locals_for_stmt :: proc(file: ast.File, stmt: ast.For_Stmt, ast_context: ^As get_locals_stmt(file, stmt.body, ast_context, document_position) } -get_locals_switch_stmt :: proc(file: ast.File, stmt: ast.Switch_Stmt, ast_context: ^AstContext, document_position: ^DocumentPositionContext) { - if !(stmt.pos.offset <= document_position.position && document_position.position <= stmt.end.offset) { +get_locals_switch_stmt :: proc( + file: ast.File, + stmt: ast.Switch_Stmt, + ast_context: ^AstContext, + document_position: ^DocumentPositionContext, +) { + if !(stmt.pos.offset <= document_position.position && + document_position.position <= stmt.end.offset) { return } get_locals_stmt(file, stmt.body, ast_context, document_position) } -get_locals_type_switch_stmt :: proc(file: ast.File, stmt: ast.Type_Switch_Stmt, ast_context: ^AstContext, document_position: ^DocumentPositionContext) { +get_locals_type_switch_stmt :: proc( + file: ast.File, + stmt: ast.Type_Switch_Stmt, + ast_context: ^AstContext, + document_position: ^DocumentPositionContext, +) { using ast - if !(stmt.pos.offset <= document_position.position && document_position.position <= stmt.end.offset) { + if !(stmt.pos.offset <= document_position.position && + document_position.position <= stmt.end.offset) { return } @@ -2450,12 +3095,22 @@ get_locals_type_switch_stmt :: proc(file: ast.File, stmt: ast.Type_Switch_Stmt, if block, ok := stmt.body.derived.(^Block_Stmt); ok { for block_stmt in block.stmts { - if cause, ok := block_stmt.derived.(^Case_Clause); ok && cause.pos.offset <= document_position.position && document_position.position <= cause.end.offset { + if cause, ok := block_stmt.derived.(^Case_Clause); + ok && + cause.pos.offset <= document_position.position && + document_position.position <= cause.end.offset { tag := stmt.tag.derived.(^Assign_Stmt) if len(tag.lhs) == 1 && len(cause.list) == 1 { ident := tag.lhs[0].derived.(^Ident) - store_local(ast_context, ident, cause.list[0], ident.pos.offset, ident.name, ast_context.local_id) + store_local( + ast_context, + ident, + cause.list[0], + ident.pos.offset, + ident.name, + ast_context.local_id, + ) ast_context.variables[ident.name] = true } @@ -2467,7 +3122,12 @@ get_locals_type_switch_stmt :: proc(file: ast.File, stmt: ast.Type_Switch_Stmt, } } -get_locals_proc_param_and_results :: proc(file: ast.File, function: ast.Proc_Lit, ast_context: ^AstContext, document_position: ^DocumentPositionContext) { +get_locals_proc_param_and_results :: proc( + file: ast.File, + function: ast.Proc_Lit, + ast_context: ^AstContext, + document_position: ^DocumentPositionContext, +) { proc_lit, ok := function.derived.(^ast.Proc_Lit) if !ok || proc_lit.body == nil { @@ -2479,19 +3139,37 @@ get_locals_proc_param_and_results :: proc(file: ast.File, function: ast.Proc_Lit for name in arg.names { if arg.type != nil { str := common.get_ast_node_string(name, file.src) - store_local(ast_context, name, arg.type, name.pos.offset, str, ast_context.local_id) + store_local( + ast_context, + name, + arg.type, + name.pos.offset, + str, + ast_context.local_id, + ) ast_context.variables[str] = true ast_context.parameters[str] = true if .Using in arg.flags { using_stmt: ast.Using_Stmt - using_stmt.list = make([]^ast.Expr, 1, context.temp_allocator) + using_stmt.list = make( + []^ast.Expr, + 1, + context.temp_allocator, + ) using_stmt.list[0] = arg.type get_locals_using_stmt(using_stmt, ast_context) } } else { str := common.get_ast_node_string(name, file.src) - store_local(ast_context, name, arg.default_value, name.pos.offset, str, ast_context.local_id) + store_local( + ast_context, + name, + arg.default_value, + name.pos.offset, + str, + ast_context.local_id, + ) ast_context.variables[str] = true ast_context.parameters[str] = true } @@ -2504,7 +3182,14 @@ get_locals_proc_param_and_results :: proc(file: ast.File, function: ast.Proc_Lit for name in result.names { if result.type != nil { str := common.get_ast_node_string(name, file.src) - store_local(ast_context, name, result.type, name.pos.offset, str, ast_context.local_id) + store_local( + ast_context, + name, + result.type, + name.pos.offset, + str, + ast_context.local_id, + ) ast_context.variables[str] = true ast_context.parameters[str] = true } @@ -2513,14 +3198,24 @@ get_locals_proc_param_and_results :: proc(file: ast.File, function: ast.Proc_Lit } } -get_locals :: proc(file: ast.File, function: ^ast.Node, ast_context: ^AstContext, document_position: ^DocumentPositionContext) { +get_locals :: proc( + file: ast.File, + function: ^ast.Node, + ast_context: ^AstContext, + document_position: ^DocumentPositionContext, +) { proc_lit, ok := function.derived.(^ast.Proc_Lit) if !ok || proc_lit.body == nil { return } - get_locals_proc_param_and_results(file, proc_lit^, ast_context, document_position) + get_locals_proc_param_and_results( + file, + proc_lit^, + ast_context, + document_position, + ) block: ^ast.Block_Stmt block, ok = proc_lit.body.derived.(^ast.Block_Stmt) @@ -2549,8 +3244,20 @@ ResolveReferenceFlag :: enum { StructElement, } -resolve_entire_file :: proc(document: ^Document, reference := "", flag := ResolveReferenceFlag.None, allocator := context.allocator) -> map[uintptr]SymbolAndNode { - ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri, document.fullpath, allocator) +resolve_entire_file :: proc( + document: ^Document, + reference := "", + flag := ResolveReferenceFlag.None, + allocator := context.allocator, +) -> map[uintptr]SymbolAndNode { + ast_context := make_ast_context( + document.ast, + document.imports, + document.package_name, + document.uri.uri, + document.fullpath, + allocator, + ) get_globals(document.ast, &ast_context) @@ -2559,37 +3266,53 @@ resolve_entire_file :: proc(document: ^Document, reference := "", flag := Resolv symbols := make(map[uintptr]SymbolAndNode, 10000, allocator) for decl in document.ast.decls { - resolve_entire_decl(&ast_context, document, decl, &symbols, reference, flag, allocator) + resolve_entire_decl( + &ast_context, + document, + decl, + &symbols, + reference, + flag, + allocator, + ) clear(&ast_context.locals) } return symbols } -resolve_entire_decl :: proc(ast_context: ^AstContext, document: ^Document, decl: ^ast.Node, symbols: ^map[uintptr]SymbolAndNode, reference := "", flag := ResolveReferenceFlag.None, allocator := context.allocator) { +resolve_entire_decl :: proc( + ast_context: ^AstContext, + document: ^Document, + decl: ^ast.Node, + symbols: ^map[uintptr]SymbolAndNode, + reference := "", + flag := ResolveReferenceFlag.None, + allocator := context.allocator, +) { Scope :: struct { offset: int, id: int, } - + Visit_Data :: struct { - ast_context: ^AstContext, - symbols: ^map[uintptr]SymbolAndNode, - scopes: [dynamic]Scope, - id_counter: int, - last_visit: ^ast.Node, + ast_context: ^AstContext, + symbols: ^map[uintptr]SymbolAndNode, + scopes: [dynamic]Scope, + id_counter: int, + last_visit: ^ast.Node, resolve_flag: ResolveReferenceFlag, - reference: string, - document: ^Document, + reference: string, + document: ^Document, } data := Visit_Data { - ast_context = ast_context, - symbols = symbols, - scopes = make([dynamic]Scope, allocator), + ast_context = ast_context, + symbols = symbols, + scopes = make([dynamic]Scope, allocator), resolve_flag = flag, - reference = reference, - document = document, + reference = reference, + document = document, } visit :: proc(visitor: ^ast.Visitor, node: ^ast.Node) -> ^ast.Visitor { @@ -2601,11 +3324,11 @@ resolve_entire_decl :: proc(ast_context: ^AstContext, document: ^Document, decl: ast_context.use_locals = true ast_context.use_globals = true - data.last_visit = node; + data.last_visit = node //It's somewhat silly to check the scope everytime, but the alternative is to implement my own walker function. if len(data.scopes) > 0 { - current_scope := data.scopes[len(data.scopes)-1] + current_scope := data.scopes[len(data.scopes) - 1] if current_scope.offset < node.end.offset { clear_local_group(ast_context, current_scope.id) @@ -2613,12 +3336,12 @@ resolve_entire_decl :: proc(ast_context: ^AstContext, document: ^Document, decl: pop(&data.scopes) if len(data.scopes) > 0 { - current_scope = data.scopes[len(data.scopes)-1] + current_scope = data.scopes[len(data.scopes) - 1] ast_context.local_id = current_scope.id } else { ast_context.local_id = 0 } - } + } } #partial switch v in node.derived { @@ -2639,8 +3362,18 @@ resolve_entire_decl :: proc(ast_context: ^AstContext, document: ^Document, decl: position_context: DocumentPositionContext position_context.position = node.end.offset - get_locals_proc_param_and_results(ast_context.file, v^, ast_context, &position_context) - get_locals_stmt(ast_context.file, cast(^ast.Stmt)node, ast_context, &position_context) + get_locals_proc_param_and_results( + ast_context.file, + v^, + ast_context, + &position_context, + ) + get_locals_stmt( + ast_context.file, + cast(^ast.Stmt)node, + ast_context, + &position_context, + ) case ^ast.If_Stmt, ^ast.For_Stmt, ^ast.Range_Stmt, ^ast.Inline_Range_Stmt: scope: Scope scope.id = data.id_counter @@ -2653,73 +3386,92 @@ resolve_entire_decl :: proc(ast_context: ^AstContext, document: ^Document, decl: position_context: DocumentPositionContext position_context.position = node.end.offset - get_locals_stmt(ast_context.file, cast(^ast.Stmt)node, ast_context, &position_context) + get_locals_stmt( + ast_context.file, + cast(^ast.Stmt)node, + ast_context, + &position_context, + ) } if data.resolve_flag == .None { - #partial switch v in node.derived { - case ^ast.Ident: + #partial switch v in node.derived { + case ^ast.Ident: if symbol, ok := resolve_type_identifier(ast_context, v^); ok { data.symbols[cast(uintptr)node] = SymbolAndNode { - node = v, + node = v, symbol = symbol, } - } + } case ^ast.Selector_Expr: - if symbol, ok := resolve_type_expression(ast_context, &v.node); ok { + if symbol, ok := resolve_type_expression(ast_context, &v.node); + ok { data.symbols[cast(uintptr)node] = SymbolAndNode { - node = v, + node = v, symbol = symbol, } } case ^ast.Call_Expr: - if symbol, ok := resolve_type_expression(ast_context, &v.node); ok { + if symbol, ok := resolve_type_expression(ast_context, &v.node); + ok { data.symbols[cast(uintptr)node] = SymbolAndNode { - node = v, + node = v, symbol = symbol, } - } + } } } else { - #partial done: switch v in node.derived { + #partial done: switch v in node.derived { case ^ast.Selector_Expr: - document : ^Document = data.document + document: ^Document = data.document position_context := DocumentPositionContext { position = v.pos.offset, } - get_document_position_decls(document.ast.decls[:], &position_context) + get_document_position_decls( + document.ast.decls[:], + &position_context, + ) - if symbol, ok := resolve_location_selector(ast_context, v); ok { + if symbol, ok := resolve_location_selector(ast_context, v); + ok { data.symbols[cast(uintptr)node] = SymbolAndNode { - node = v, + node = v, symbol = symbol, } - } - case ^ast.Ident: + } + case ^ast.Ident: if data.resolve_flag == .Variable && v.name != data.reference { break done } - document : ^Document = data.document + document: ^Document = data.document position_context := DocumentPositionContext { position = v.pos.offset, } - get_document_position_decls(document.ast.decls[:], &position_context) + get_document_position_decls( + document.ast.decls[:], + &position_context, + ) - if position_context.field_value != nil && position_in_node(position_context.field_value.field, v.pos.offset) { + if position_context.field_value != nil && + position_in_node( + position_context.field_value.field, + v.pos.offset, + ) { break done } - if symbol, ok := resolve_location_identifier(ast_context, v^); ok { + if symbol, ok := resolve_location_identifier(ast_context, v^); + ok { data.symbols[cast(uintptr)node] = SymbolAndNode { - node = v, + node = v, symbol = symbol, } - } + } } } @@ -2727,7 +3479,7 @@ resolve_entire_decl :: proc(ast_context: ^AstContext, document: ^Document, decl: } visitor := ast.Visitor { - data = &data, + data = &data, visit = visit, } @@ -2739,11 +3491,29 @@ concatenate_symbol_information :: proc { concatenate_raw_string_information, } -concatenate_raw_symbol_information :: proc(ast_context: ^AstContext, symbol: Symbol, is_completion: bool) -> string { - return concatenate_raw_string_information(ast_context, symbol.pkg, symbol.name, symbol.signature, symbol.type, is_completion) +concatenate_raw_symbol_information :: proc( + ast_context: ^AstContext, + symbol: Symbol, + is_completion: bool, +) -> string { + return concatenate_raw_string_information( + ast_context, + symbol.pkg, + symbol.name, + symbol.signature, + symbol.type, + is_completion, + ) } -concatenate_raw_string_information :: proc(ast_context: ^AstContext, pkg: string, name: string, signature: string, type: SymbolType, is_completion: bool) -> string { +concatenate_raw_string_information :: proc( + ast_context: ^AstContext, + pkg: string, + name: string, + signature: string, + type: SymbolType, + is_completion: bool, +) -> string { pkg := path.base(pkg, false, context.temp_allocator) if type == .Package { @@ -2759,7 +3529,13 @@ concatenate_raw_string_information :: proc(ast_context: ^AstContext, pkg: string } } -unwrap_enum :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (SymbolEnumValue, bool) { +unwrap_enum :: proc( + ast_context: ^AstContext, + node: ^ast.Expr, +) -> ( + SymbolEnumValue, + bool, +) { if node == nil { return {}, false } @@ -2773,7 +3549,13 @@ unwrap_enum :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (SymbolEnumVal return {}, false } -unwrap_union :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (SymbolUnionValue, bool) { +unwrap_union :: proc( + ast_context: ^AstContext, + node: ^ast.Expr, +) -> ( + SymbolUnionValue, + bool, +) { if union_symbol, ok := resolve_type_expression(ast_context, node); ok { if union_value, ok := union_symbol.value.(SymbolUnionValue); ok { return union_value, true @@ -2783,9 +3565,18 @@ unwrap_union :: proc(ast_context: ^AstContext, node: ^ast.Expr) -> (SymbolUnionV return {}, false } -unwrap_bitset :: proc(ast_context: ^AstContext, bitset_symbol: Symbol) -> (SymbolEnumValue, bool) { +unwrap_bitset :: proc( + ast_context: ^AstContext, + bitset_symbol: Symbol, +) -> ( + SymbolEnumValue, + bool, +) { if bitset_value, ok := bitset_symbol.value.(SymbolBitSetValue); ok { - if enum_symbol, ok := resolve_type_expression(ast_context, bitset_value.expr); ok { + if enum_symbol, ok := resolve_type_expression( + ast_context, + bitset_value.expr, + ); ok { if enum_value, ok := enum_symbol.value.(SymbolEnumValue); ok { return enum_value, true } @@ -2795,7 +3586,12 @@ unwrap_bitset :: proc(ast_context: ^AstContext, bitset_symbol: Symbol) -> (Symbo return {}, false } -get_signature :: proc(ast_context: ^AstContext, ident: ast.Ident, symbol: Symbol, was_variable := false) -> string { +get_signature :: proc( + ast_context: ^AstContext, + ident: ast.Ident, + symbol: Symbol, + was_variable := false, +) -> string { if symbol.type == .Function { return symbol.signature } @@ -2814,51 +3610,79 @@ get_signature :: proc(ast_context: ^AstContext, ident: ast.Ident, symbol: Symbol case SymbolEnumValue: if is_variable { return symbol.name - } - else { + } else { return "enum" } case SymbolMapValue: - return strings.concatenate(a = {"map[", common.node_to_string(v.key), "]", common.node_to_string(v.value)}, allocator = ast_context.allocator) + return strings.concatenate( + a = { + "map[", + common.node_to_string(v.key), + "]", + common.node_to_string(v.value), + }, + allocator = ast_context.allocator, + ) case SymbolProcedureValue: return "proc" case SymbolStructValue: if is_variable { return symbol.name - } - else { + } else { return "struct" } case SymbolUnionValue: if is_variable { return symbol.name - } - else { + } else { return "union" } case SymbolMultiPointer: - return strings.concatenate(a = {"[^]", common.node_to_string(v.expr)}, allocator = ast_context.allocator) + return strings.concatenate( + a = {"[^]", common.node_to_string(v.expr)}, + allocator = ast_context.allocator, + ) case SymbolDynamicArrayValue: - return strings.concatenate(a = {"[dynamic]", common.node_to_string(v.expr)}, allocator = ast_context.allocator) + return strings.concatenate( + a = {"[dynamic]", common.node_to_string(v.expr)}, + allocator = ast_context.allocator, + ) case SymbolSliceValue: - return strings.concatenate(a = {"[]", common.node_to_string(v.expr)}, allocator = ast_context.allocator) + return strings.concatenate( + a = {"[]", common.node_to_string(v.expr)}, + allocator = ast_context.allocator, + ) case SymbolFixedArrayValue: - return strings.concatenate(a = {"[", common.node_to_string(v.len), "]", common.node_to_string(v.expr)}, allocator = ast_context.allocator) + return strings.concatenate( + a = { + "[", + common.node_to_string(v.len), + "]", + common.node_to_string(v.expr), + }, + allocator = ast_context.allocator, + ) case SymbolPackageValue: return "package" case SymbolUntypedValue: switch v.type { - case .Float: return "float" - case .String: return "string" - case .Bool: return "bool" - case .Integer: return "int" + case .Float: + return "float" + case .String: + return "string" + case .Bool: + return "bool" + case .Integer: + return "int" } } - + return "" } -position_in_proc_decl :: proc(position_context: ^DocumentPositionContext) -> bool { +position_in_proc_decl :: proc( + position_context: ^DocumentPositionContext, +) -> bool { if position_context.value_decl == nil { return false } @@ -2867,12 +3691,16 @@ position_in_proc_decl :: proc(position_context: ^DocumentPositionContext) -> boo return false } - if _, ok := position_context.value_decl.values[0].derived.(^ast.Proc_Type); ok { + if _, ok := position_context.value_decl.values[0].derived.(^ast.Proc_Type); + ok { return true } - if proc_lit, ok := position_context.value_decl.values[0].derived.(^ast.Proc_Lit); ok { - if proc_lit.type != nil && position_in_node(proc_lit.type, position_context.position) { + if proc_lit, ok := position_context.value_decl.values[ + 0 \ + ].derived.(^ast.Proc_Lit); ok { + if proc_lit.type != nil && + position_in_node(proc_lit.type, position_context.position) { return true } } @@ -2906,7 +3734,10 @@ is_lhs_comp_lit :: proc(position_context: ^DocumentPositionContext) -> bool { return true } -field_exists_in_comp_lit :: proc(comp_lit: ^ast.Comp_Lit, name: string) -> bool { +field_exists_in_comp_lit :: proc( + comp_lit: ^ast.Comp_Lit, + name: string, +) -> bool { for elem in comp_lit.elems { if field, ok := elem.derived.(^ast.Field_Value); ok { if field.field != nil { @@ -2925,7 +3756,10 @@ field_exists_in_comp_lit :: proc(comp_lit: ^ast.Comp_Lit, name: string) -> bool /* Parser gives ranges of expression, but not actually where the commas are placed. */ -get_call_commas :: proc(position_context: ^DocumentPositionContext, document: ^Document) { +get_call_commas :: proc( + position_context: ^DocumentPositionContext, + document: ^Document, +) { if position_context.call == nil { return } @@ -2942,12 +3776,18 @@ get_call_commas :: proc(position_context: ^DocumentPositionContext, document: ^D } for i := call.open.offset; i < call.close.offset; i += 1 { switch document.text[i] { - case '[': paren_count += 1 - case ']': paren_count -= 1 - case '{': brace_count += 1 - case '}': brace_count -= 1 - case '(': paren_count += 1 - case ')': paren_count -= 1 + case '[': + paren_count += 1 + case ']': + paren_count -= 1 + case '{': + brace_count += 1 + case '}': + brace_count -= 1 + case '(': + paren_count += 1 + case ')': + paren_count -= 1 case ',': if paren_count == 0 && brace_count == 0 && bracket_count == 0 { append(&commas, i) @@ -2966,10 +3806,13 @@ type_to_string :: proc(ast_context: ^AstContext, expr: ^ast.Expr) -> string { } } - return common.node_to_string(expr) + return common.node_to_string(expr) } -get_document_position_decls :: proc(decls: []^ast.Stmt, position_context: ^DocumentPositionContext) -> bool { +get_document_position_decls :: proc( + decls: []^ast.Stmt, + position_context: ^DocumentPositionContext, +) -> bool { exists_in_decl := false for decl in decls { if position_in_node(decl, position_context.position) { @@ -2988,14 +3831,24 @@ get_document_position_decls :: proc(decls: []^ast.Stmt, position_context: ^Docum /* Figure out what exactly is at the given position and whether it is in a function, struct, etc. */ -get_document_position_context :: proc(document: ^Document, position: common.Position, hint: DocumentPositionContextHint) -> (DocumentPositionContext, bool) { +get_document_position_context :: proc( + document: ^Document, + position: common.Position, + hint: DocumentPositionContextHint, +) -> ( + DocumentPositionContext, + bool, +) { position_context: DocumentPositionContext position_context.hint = hint position_context.file = document.ast position_context.line = position.line - absolute_position, ok := common.get_absolute_position(position, document.text) + absolute_position, ok := common.get_absolute_position( + position, + document.text, + ) if !ok { log.error("failed to get absolute position") @@ -3004,7 +3857,10 @@ get_document_position_context :: proc(document: ^Document, position: common.Posi position_context.position = absolute_position - exists_in_decl := get_document_position_decls(document.ast.decls[:], &position_context) + exists_in_decl := get_document_position_decls( + document.ast.decls[:], + &position_context, + ) for import_stmt in document.ast.imports { if position_in_node(import_stmt, position_context.position) { @@ -3017,11 +3873,17 @@ get_document_position_context :: proc(document: ^Document, position: common.Posi position_context.abort_completion = true } - if !position_in_node(position_context.comp_lit, position_context.position) { + if !position_in_node( + position_context.comp_lit, + position_context.position, + ) { position_context.comp_lit = nil } - if !position_in_node(position_context.parent_comp_lit, position_context.position) { + if !position_in_node( + position_context.parent_comp_lit, + position_context.position, + ) { position_context.parent_comp_lit = nil } @@ -3033,16 +3895,30 @@ get_document_position_context :: proc(document: ^Document, position: common.Posi position_context.binary = nil } - if !position_in_node(position_context.parent_binary, position_context.position) { + if !position_in_node( + position_context.parent_binary, + position_context.position, + ) { position_context.parent_binary = nil } - if hint == .Completion && position_context.selector == nil && position_context.field == nil { - fallback_position_context_completion(document, position, &position_context) + if hint == .Completion && + position_context.selector == nil && + position_context.field == nil { + fallback_position_context_completion( + document, + position, + &position_context, + ) } - if (hint == .SignatureHelp || hint == .Completion) && position_context.call == nil { - fallback_position_context_signature(document, position, &position_context) + if (hint == .SignatureHelp || hint == .Completion) && + position_context.call == nil { + fallback_position_context_signature( + document, + position, + &position_context, + ) } if hint == .SignatureHelp { @@ -3053,16 +3929,20 @@ get_document_position_context :: proc(document: ^Document, position: common.Posi } //terrible fallback code -fallback_position_context_completion :: proc(document: ^Document, position: common.Position, position_context: ^DocumentPositionContext) { - paren_count: int +fallback_position_context_completion :: proc( + document: ^Document, + position: common.Position, + position_context: ^DocumentPositionContext, +) { + paren_count: int bracket_count: int - end: int - start: int - empty_dot: bool - empty_arrow: bool - last_dot: bool - last_arrow: bool - dots_seen: int + end: int + start: int + empty_dot: bool + empty_arrow: bool + last_dot: bool + last_arrow: bool + dots_seen: int partial_arrow: bool i := position_context.position - 1 @@ -3110,11 +3990,21 @@ fallback_position_context_completion :: proc(document: ^Document, position: comm } //yeah.. - if c == ' ' || c == '{' || c == ',' || - c == '}' || c == '^' || c == ':' || - c == '\n' || c == '\r' || c == '=' || - c == '<' || c == '-' || c == '!' || - c == '+' || c == '&'|| c == '|' { + if c == ' ' || + c == '{' || + c == ',' || + c == '}' || + c == '^' || + c == ':' || + c == '\n' || + c == '\r' || + c == '=' || + c == '<' || + c == '-' || + c == '!' || + c == '+' || + c == '&' || + c == '|' { start = i + 1 break } else if c == '>' { @@ -3130,14 +4020,16 @@ fallback_position_context_completion :: proc(document: ^Document, position: comm if i >= 0 && position_context.file.src[end] == '.' { empty_dot = true end -= 1 - } else if i >= 0 && position_context.file.src[max(0, end - 1)] == '-' && position_context.file.src[end] == '>' { + } else if i >= 0 && + position_context.file.src[max(0, end - 1)] == '-' && + position_context.file.src[end] == '>' { empty_arrow = true end -= 2 position_context.arrow = true } begin_offset := max(0, start) - end_offset := max(start, end + 1) + end_offset := max(start, end + 1) line_offset := begin_offset if line_offset < len(position_context.file.src) { @@ -3176,17 +4068,22 @@ fallback_position_context_completion :: proc(document: ^Document, position: comm } p := parser.Parser { - err = common.parser_warning_handler, //empty + err = common.parser_warning_handler, //empty warn = common.parser_warning_handler, //empty flags = {.Optional_Semicolons}, file = &position_context.file, } - tokenizer.init(&p.tok, str, position_context.file.fullpath, common.parser_warning_handler) + tokenizer.init( + &p.tok, + str, + position_context.file.fullpath, + common.parser_warning_handler, + ) p.tok.ch = ' ' p.tok.line_count = position.line + 1 - p.tok.line_offset = line_offset + p.tok.line_offset = line_offset p.tok.offset = begin_offset p.tok.read_offset = begin_offset @@ -3215,18 +4112,28 @@ fallback_position_context_completion :: proc(document: ^Document, position: comm //this is most likely because of use of 'in', 'context', etc. //try to go back one dot. - src_with_dot := string(position_context.file.src[0:min(len(position_context.file.src), end_offset + 1)]) - last_dot := strings.last_index(src_with_dot, ".") + src_with_dot := string( + position_context.file.src[0:min( + len(position_context.file.src), + end_offset + 1, + )], + ) + last_dot := strings.last_index(src_with_dot, ".") if last_dot == -1 { return } - tokenizer.init(&p.tok, position_context.file.src[0:last_dot], position_context.file.fullpath, common.parser_warning_handler) + tokenizer.init( + &p.tok, + position_context.file.src[0:last_dot], + position_context.file.fullpath, + common.parser_warning_handler, + ) p.tok.ch = ' ' p.tok.line_count = position.line + 1 - p.tok.line_offset = line_offset + p.tok.line_offset = line_offset p.tok.offset = begin_offset p.tok.read_offset = begin_offset @@ -3261,8 +4168,12 @@ fallback_position_context_completion :: proc(document: ^Document, position: comm } } -fallback_position_context_signature :: proc(document: ^Document, position: common.Position, position_context: ^DocumentPositionContext) { - end: int +fallback_position_context_signature :: proc( + document: ^Document, + position: common.Position, + position_context: ^DocumentPositionContext, +) { + end: int start: int i := position_context.position - 1 end = i @@ -3290,7 +4201,7 @@ fallback_position_context_signature :: proc(document: ^Document, position: commo end -= 1 begin_offset := max(0, start) - end_offset := max(start, end + 1) + end_offset := max(start, end + 1) if end_offset - begin_offset <= 1 { return @@ -3299,12 +4210,17 @@ fallback_position_context_signature :: proc(document: ^Document, position: commo str := position_context.file.src[0:end_offset] p := parser.Parser { - err = common.parser_warning_handler, //empty + err = common.parser_warning_handler, //empty warn = common.parser_warning_handler, //empty file = &position_context.file, } - tokenizer.init(&p.tok, str, position_context.file.fullpath, common.parser_warning_handler) + tokenizer.init( + &p.tok, + str, + position_context.file.fullpath, + common.parser_warning_handler, + ) p.tok.ch = ' ' p.tok.line_count = position.line @@ -3326,7 +4242,7 @@ fallback_position_context_signature :: proc(document: ^Document, position: commo if _, ok := position_context.call.derived.(^ast.Proc_Type); ok { position_context.call = nil } - + //log.error(string(position_context.file.src[begin_offset:end_offset])); } @@ -3334,29 +4250,45 @@ fallback_position_context_signature :: proc(document: ^Document, position: commo All these fallback functions are not perfect and should be fixed. A lot of weird use of the odin tokenizer and parser. */ -get_document_position ::proc { +get_document_position :: proc { get_document_position_array, get_document_position_dynamic_array, get_document_position_node, } -get_document_position_array :: proc(array: $A/[]^$T, position_context: ^DocumentPositionContext) { +get_document_position_array :: proc( + array: $A/[]^$T, + position_context: ^DocumentPositionContext, +) { for elem, i in array { get_document_position(elem, position_context) } } -get_document_position_dynamic_array :: proc(array: $A/[dynamic]^$T, position_context: ^DocumentPositionContext) { +get_document_position_dynamic_array :: proc( + array: $A/[dynamic]^$T, + position_context: ^DocumentPositionContext, +) { for elem, i in array { get_document_position(elem, position_context) } } -position_in_node :: proc(node: ^ast.Node, position: common.AbsolutePosition) -> bool { - return node != nil && node.pos.offset <= position && position <= node.end.offset +position_in_node :: proc( + node: ^ast.Node, + position: common.AbsolutePosition, +) -> bool { + return( + node != nil && + node.pos.offset <= position && + position <= node.end.offset \ + ) } -get_document_position_node :: proc(node: ^ast.Node, position_context: ^DocumentPositionContext) { +get_document_position_node :: proc( + node: ^ast.Node, + position_context: ^DocumentPositionContext, +) { using ast if node == nil { @@ -3385,7 +4317,7 @@ get_document_position_node :: proc(node: ^ast.Node, position_context: ^DocumentP if position_in_node(n.body, position_context.position) { position_context.function = cast(^Proc_Lit)node get_document_position(n.body, position_context) - } + } case ^Comp_Lit: //only set this for the parent comp literal, since we will need to walk through it to infer types. if position_context.parent_comp_lit == nil { @@ -3410,19 +4342,23 @@ get_document_position_node :: proc(node: ^ast.Node, position_context: ^DocumentP case ^Paren_Expr: get_document_position(n.expr, position_context) case ^Call_Expr: - if position_context.hint == .SignatureHelp || position_context.hint == .Completion { + if position_context.hint == .SignatureHelp || + position_context.hint == .Completion { position_context.call = cast(^Expr)node } get_document_position(n.expr, position_context) get_document_position(n.args, position_context) case ^Selector_Expr: if position_context.hint == .Completion { - if n.field != nil && n.field.pos.line - 1 == position_context.line { + if n.field != nil && + n.field.pos.line - 1 == position_context.line { //The parser is not fault tolerant enough, relying on the fallback as the main completion parsing for now //position_context.selector = n.expr; //position_context.field = n.field; } - } else if (position_context.hint == .Definition || position_context.hint == .Hover) && n.field != nil { + } else if (position_context.hint == .Definition || + position_context.hint == .Hover) && + n.field != nil { position_context.selector = n.expr position_context.field = n.field position_context.selector_expr = cast(^Selector_Expr)node @@ -3533,7 +4469,8 @@ get_document_position_node :: proc(node: ^ast.Node, position_context: ^DocumentP get_document_position(n.attributes, position_context) for name in n.names { - if position_in_node(name, position_context.position) && n.end.line - 1 == position_context.line { + if position_in_node(name, position_context.position) && + n.end.line - 1 == position_context.line { position_context.abort_completion = true break } diff --git a/src/server/build.odin b/src/server/build.odin index 7abe95c..4f97dfd 100644 --- a/src/server/build.odin +++ b/src/server/build.odin @@ -17,22 +17,22 @@ import "shared:common" platform_os: map[string]bool = { "windows" = true, - "linux" = true, + "linux" = true, "essence" = true, - "js" = true, + "js" = true, "freebsd" = true, - "darwin" = true, - "wasm32" = true, + "darwin" = true, + "wasm32" = true, } os_enum_to_string: map[runtime.Odin_OS_Type]string = { - .Windows = "windows", - .Darwin = "darwin", - .Linux = "linux", - .Essence = "essence", - .FreeBSD = "freebsd", - .WASI = "wasi", - .JS = "js", + .Windows = "windows", + .Darwin = "darwin", + .Linux = "linux", + .Essence = "essence", + .FreeBSD = "freebsd", + .WASI = "wasi", + .JS = "js", .Freestanding = "freestanding", } @@ -41,7 +41,10 @@ try_build_package :: proc(pkg_name: string) { return } - matches, err := filepath.glob(fmt.tprintf("%v/*.odin", pkg_name), context.temp_allocator) + matches, err := filepath.glob( + fmt.tprintf("%v/*.odin", pkg_name), + context.temp_allocator, + ) if err != .None { log.errorf("Failed to glob %v for indexing package", pkg_name) @@ -49,9 +52,12 @@ try_build_package :: proc(pkg_name: string) { temp_arena: mem.Arena - mem.arena_init(&temp_arena, make([]byte, mem.Megabyte*25, runtime.default_allocator())) + mem.arena_init( + &temp_arena, + make([]byte, mem.Megabyte * 25, runtime.default_allocator()), + ) defer delete(temp_arena.data) - + { context.allocator = mem.arena_allocator(&temp_arena) @@ -59,7 +65,10 @@ try_build_package :: proc(pkg_name: string) { data, ok := os.read_entire_file(fullpath, context.allocator) if !ok { - log.errorf("failed to read entire file for indexing %v", fullpath) + log.errorf( + "failed to read entire file for indexing %v", + fullpath, + ) continue } @@ -82,8 +91,8 @@ try_build_package :: proc(pkg_name: string) { file := ast.File { fullpath = fullpath, - src = string(data), - pkg = pkg, + src = string(data), + pkg = pkg, } ok = parser.parse_file(&p, &file) @@ -101,18 +110,27 @@ try_build_package :: proc(pkg_name: string) { } } - build_cache.loaded_pkgs[strings.clone(pkg_name, indexer.index.collection.allocator)] = PackageCacheInfo { + build_cache.loaded_pkgs[ + strings.clone(pkg_name, indexer.index.collection.allocator) \ + ] = PackageCacheInfo { timestamp = time.now(), - } + } } setup_index :: proc() { - build_cache.loaded_pkgs = make(map[string]PackageCacheInfo, 50, context.allocator) - symbol_collection := make_symbol_collection(context.allocator, &common.config) + build_cache.loaded_pkgs = make( + map[string]PackageCacheInfo, + 50, + context.allocator, + ) + symbol_collection := make_symbol_collection( + context.allocator, + &common.config, + ) indexer.index = make_memory_index(symbol_collection) dir_exe := path.dir(os.args[0]) - + try_build_package(path.join({dir_exe, "builtin"})) } diff --git a/src/server/caches.odin b/src/server/caches.odin index 80128f4..55091fd 100644 --- a/src/server/caches.odin +++ b/src/server/caches.odin @@ -17,7 +17,9 @@ FileResolveCache :: struct { file_resolve_cache: FileResolveCache -resolve_entire_file_cached :: proc(document: ^Document) -> map[uintptr]SymbolAndNode{ +resolve_entire_file_cached :: proc( + document: ^Document, +) -> map[uintptr]SymbolAndNode { if document.uri.uri not_in file_resolve_cache.files { file_resolve_cache.files[document.uri.uri] = FileResolve { symbols = resolve_entire_file( @@ -27,9 +29,9 @@ resolve_entire_file_cached :: proc(document: ^Document) -> map[uintptr]SymbolAnd common.scratch_allocator(document.allocator), ), } - } + } - return file_resolve_cache.files[document.uri.uri].symbols; + return file_resolve_cache.files[document.uri.uri].symbols } BuildCache :: struct { @@ -40,4 +42,4 @@ PackageCacheInfo :: struct { timestamp: time.Time, } -build_cache: BuildCache
\ No newline at end of file +build_cache: BuildCache diff --git a/src/server/check.odin b/src/server/check.odin index 6d57b95..056783a 100644 --- a/src/server/check.odin +++ b/src/server/check.odin @@ -19,11 +19,11 @@ import "core:text/scanner" import "shared:common" is_package :: proc(file: string, pkg: string) { - + } check :: proc(uri: common.Uri, writer: ^Writer, config: ^common.Config) { - data := make([]byte, mem.Kilobyte*10, context.temp_allocator) + data := make([]byte, mem.Kilobyte * 10, context.temp_allocator) buffer: []byte code: u32 @@ -35,7 +35,10 @@ check :: proc(uri: common.Uri, writer: ^Writer, config: ^common.Config) { if k == "" || k == "core" || k == "vendor" { continue } - strings.write_string(&collection_builder, fmt.aprintf("-collection:%v=%v ", k, v)) + strings.write_string( + &collection_builder, + fmt.aprintf("-collection:%v=%v ", k, v), + ) } command: string @@ -47,32 +50,37 @@ check :: proc(uri: common.Uri, writer: ^Writer, config: ^common.Config) { } if code, ok, buffer = common.run_executable( - fmt.tprintf("%v check %s %s -no-entry-point %s %s", - command, - path.dir(uri.path, context.temp_allocator), - strings.to_string(collection_builder), - config.checker_args, - ODIN_OS == .Linux || ODIN_OS == .Darwin ? "2>&1" : "", - ), - &data - ); !ok { - log.errorf("Odin check failed with code %v for file %v", code, uri.path) + fmt.tprintf( + "%v check %s %s -no-entry-point %s %s", + command, + path.dir(uri.path, context.temp_allocator), + strings.to_string(collection_builder), + config.checker_args, + ODIN_OS == .Linux || ODIN_OS == .Darwin ? "2>&1" : "", + ), + &data, + ); !ok { + log.errorf( + "Odin check failed with code %v for file %v", + code, + uri.path, + ) return - } + } s: scanner.Scanner scanner.init(&s, string(buffer)) - s.whitespace = {'\t', ' '} + s.whitespace = {'\t', ' '} current: rune ErrorSeperator :: struct { message: string, - line: int, - column: int, - uri: string, + line: int, + column: int, + uri: string, } error_seperators := make([dynamic]ErrorSeperator, context.temp_allocator) @@ -93,10 +101,10 @@ check :: proc(uri: common.Uri, writer: ^Writer, config: ^common.Config) { if n == scanner.EOF { break loop - } + } } - error.uri = string(buffer[source_pos:s.src_pos-1]) + error.uri = string(buffer[source_pos:s.src_pos - 1]) left_paren := scanner.scan(&s) @@ -123,7 +131,7 @@ check :: proc(uri: common.Uri, writer: ^Writer, config: ^common.Config) { if seperator != ':' { break loop - } + } rhs_digit := scanner.scan(&s) @@ -157,7 +165,7 @@ check :: proc(uri: common.Uri, writer: ^Writer, config: ^common.Config) { continue } - error.message = string(buffer[source_pos:s.src_pos-1]) + error.message = string(buffer[source_pos:s.src_pos - 1]) error.column = column error.line = line @@ -169,32 +177,34 @@ check :: proc(uri: common.Uri, writer: ^Writer, config: ^common.Config) { for error in error_seperators { if error.uri not_in errors { - errors[error.uri] = make([dynamic]Diagnostic, context.temp_allocator) - } - - append(&errors[error.uri], Diagnostic { - code = "checker", - severity = .Error, - range = { - start = { - character = 0, - line = error.line - 1, - }, - end = { - character = 0, - line = error.line, + errors[error.uri] = make( + [dynamic]Diagnostic, + context.temp_allocator, + ) + } + + append( + &errors[error.uri], + Diagnostic{ + code = "checker", + severity = .Error, + range = { + start = {character = 0, line = error.line - 1}, + end = {character = 0, line = error.line}, }, + message = error.message, }, - message = error.message, - }) + ) } - matches, err := filepath.glob(fmt.tprintf("%v/*.odin", path.dir(uri.path, context.temp_allocator))) + matches, err := filepath.glob( + fmt.tprintf("%v/*.odin", path.dir(uri.path, context.temp_allocator)), + ) if err == .None { for match in matches { uri := common.create_uri(match, context.temp_allocator) - + params := NotificationPublishDiagnosticsParams { uri = uri.uri, diagnostics = {}, @@ -202,8 +212,8 @@ check :: proc(uri: common.Uri, writer: ^Writer, config: ^common.Config) { notifaction := Notification { jsonrpc = "2.0", - method = "textDocument/publishDiagnostics", - params = params, + method = "textDocument/publishDiagnostics", + params = params, } if writer != nil { @@ -216,14 +226,14 @@ check :: proc(uri: common.Uri, writer: ^Writer, config: ^common.Config) { uri := common.create_uri(k, context.temp_allocator) params := NotificationPublishDiagnosticsParams { - uri = uri.uri, + uri = uri.uri, diagnostics = v[:], } notifaction := Notification { jsonrpc = "2.0", - method = "textDocument/publishDiagnostics", - params = params, + method = "textDocument/publishDiagnostics", + params = params, } if writer != nil { diff --git a/src/server/clone.odin b/src/server/clone.odin index 9a4af46..9db9ecb 100644 --- a/src/server/clone.odin +++ b/src/server/clone.odin @@ -10,7 +10,12 @@ import "core:intrinsics" import "core:reflect" _ :: intrinsics -new_type :: proc($T: typeid, pos, end: tokenizer.Pos, allocator: mem.Allocator) -> ^T { +new_type :: proc( + $T: typeid, + pos, + end: tokenizer.Pos, + allocator: mem.Allocator, +) -> ^T { n, _ := mem.new(T, allocator) n.pos = pos n.end = end @@ -33,7 +38,11 @@ clone_type :: proc { clone_dynamic_array, } -clone_array :: proc(array: $A/[]^$T, allocator: mem.Allocator, unique_strings: ^map[string]string) -> A { +clone_array :: proc( + array: $A/[]^$T, + allocator: mem.Allocator, + unique_strings: ^map[string]string, +) -> A { if len(array) == 0 { return nil } @@ -44,7 +53,11 @@ clone_array :: proc(array: $A/[]^$T, allocator: mem.Allocator, unique_strings: ^ return res } -clone_dynamic_array :: proc(array: $A/[dynamic]^$T, allocator: mem.Allocator, unique_strings: ^map[string]string) -> A { +clone_dynamic_array :: proc( + array: $A/[dynamic]^$T, + allocator: mem.Allocator, + unique_strings: ^map[string]string, +) -> A { if len(array) == 0 { return nil } @@ -52,25 +65,33 @@ clone_dynamic_array :: proc(array: $A/[dynamic]^$T, allocator: mem.Allocator, un for elem, i in array { res[i] = auto_cast clone_type(elem, allocator, unique_strings) } - return res + return res } -clone_expr :: proc(node: ^ast.Expr, allocator: mem.Allocator, unique_strings: ^map[string]string) -> ^ast.Expr { +clone_expr :: proc( + node: ^ast.Expr, + allocator: mem.Allocator, + unique_strings: ^map[string]string, +) -> ^ast.Expr { return cast(^ast.Expr)clone_node(node, allocator, unique_strings) } -clone_node :: proc(node: ^ast.Node, allocator: mem.Allocator, unique_strings: ^map[string]string) -> ^ast.Node { +clone_node :: proc( + node: ^ast.Node, + allocator: mem.Allocator, + unique_strings: ^map[string]string, +) -> ^ast.Node { using ast if node == nil { return nil } - size := size_of(Node) + size := size_of(Node) align := align_of(Node) ti := reflect.union_variant_type_info(node.derived) if ti != nil { elem := ti.variant.(reflect.Type_Info_Pointer).elem - size = elem.size + size = elem.size align = elem.align } @@ -90,13 +111,21 @@ clone_node :: proc(node: ^ast.Node, allocator: mem.Allocator, unique_strings: ^m res_ptr_any.id = ti.id if unique_strings != nil && node.pos.file != "" { - res.pos.file = get_index_unique_string(unique_strings, allocator, node.pos.file) + res.pos.file = get_index_unique_string( + unique_strings, + allocator, + node.pos.file, + ) } else { res.pos.file = node.pos.file } if unique_strings != nil && node.end.file != "" { - res.end.file = get_index_unique_string(unique_strings, allocator, node.end.file) + res.end.file = get_index_unique_string( + unique_strings, + allocator, + node.end.file, + ) } else { res.end.file = node.end.file } @@ -105,149 +134,197 @@ clone_node :: proc(node: ^ast.Node, allocator: mem.Allocator, unique_strings: ^m res_ptr := reflect.deref(res_ptr_any) - if de := reflect.struct_field_value_by_name(res_ptr, "derived_expr", true); de != nil { + if de := reflect.struct_field_value_by_name(res_ptr, "derived_expr", true); + de != nil { reflect.set_union_value(de, res_ptr_any) } - if ds := reflect.struct_field_value_by_name(res_ptr, "derived_stmt", true); ds != nil { + if ds := reflect.struct_field_value_by_name(res_ptr, "derived_stmt", true); + ds != nil { reflect.set_union_value(ds, res_ptr_any) } if res.derived != nil do #partial switch r in res.derived { - case ^Ident: - n := node.derived.(^Ident) + case ^Ident: + n := node.derived.(^Ident) - if unique_strings == nil { - r.name = strings.clone(n.name, allocator) - } else { - r.name = get_index_unique_string(unique_strings, allocator, n.name) - } - case ^Implicit: - n := node.derived.(^Implicit) - if unique_strings == nil { - r.tok.text = strings.clone(n.tok.text, allocator) - } else { - r.tok.text = get_index_unique_string(unique_strings, allocator, n.tok.text) - } - case ^Undef: - case ^Basic_Lit: - n := node.derived.(^Basic_Lit) - if unique_strings == nil { - r.tok.text = strings.clone(n.tok.text, allocator) - } else { - r.tok.text = get_index_unique_string(unique_strings, allocator, n.tok.text) - } - case ^Basic_Directive: - n := node.derived.(^Basic_Directive) - if unique_strings == nil { - r.name = strings.clone(n.name, allocator) - } else { - r.name = get_index_unique_string(unique_strings, allocator, n.name) - } - case ^Ellipsis: - r.expr = clone_type(r.expr, allocator, unique_strings) - case ^Tag_Expr: - r.expr = clone_type(r.expr, allocator, unique_strings) - case ^Unary_Expr: - r.expr = clone_type(r.expr, allocator, unique_strings) - case ^Binary_Expr: - r.left = clone_type(r.left, allocator, unique_strings) - r.right = clone_type(r.right, allocator, unique_strings) - case ^Paren_Expr: - r.expr = clone_type(r.expr, allocator, unique_strings) - case ^Selector_Expr: - r.expr = clone_type(r.expr, allocator, unique_strings) - r.field = auto_cast clone_type(r.field, allocator, unique_strings) - case ^Implicit_Selector_Expr: - r.field = auto_cast clone_type(r.field, allocator, unique_strings) - case ^Slice_Expr: - r.expr = clone_type(r.expr, allocator, unique_strings) - r.low = clone_type(r.low, allocator, unique_strings) - r.high = clone_type(r.high, allocator, unique_strings) - case ^Attribute: - r.elems = clone_type(r.elems, allocator, unique_strings) - case ^Distinct_Type: - r.type = clone_type(r.type, allocator, unique_strings) - case ^Proc_Type: - r.params = auto_cast clone_type(r.params, allocator, unique_strings) - r.results = auto_cast clone_type(r.results, allocator, unique_strings) - case ^Pointer_Type: - r.elem = clone_type(r.elem, allocator, unique_strings) - case ^Array_Type: - r.len = clone_type(r.len, allocator, unique_strings) - r.elem = clone_type(r.elem, allocator, unique_strings) - r.tag = clone_type(r.tag, allocator, unique_strings) - case ^Dynamic_Array_Type: - r.elem = clone_type(r.elem, allocator, unique_strings) - r.tag = clone_type(r.tag, allocator, unique_strings) - case ^Struct_Type: - r.poly_params = auto_cast clone_type(r.poly_params, allocator, unique_strings) - r.align = clone_type(r.align, allocator, unique_strings) - r.fields = auto_cast clone_type(r.fields, allocator, unique_strings) - r.where_clauses = clone_type(r.where_clauses, allocator, unique_strings) - case ^Field: - r.names = clone_type(r.names, allocator, unique_strings) - r.type = clone_type(r.type, allocator, unique_strings) - r.default_value = clone_type(r.default_value, allocator, unique_strings) - case ^Field_List: - r.list = clone_type(r.list, allocator, unique_strings) - case ^Field_Value: - r.field = clone_type(r.field, allocator, unique_strings) - r.value = clone_type(r.value, allocator, unique_strings) - case ^Union_Type: - r.poly_params = auto_cast clone_type(r.poly_params, allocator, unique_strings) - r.align = clone_type(r.align, allocator, unique_strings) - r.variants = clone_type(r.variants, allocator, unique_strings) - r.where_clauses = clone_type(r.where_clauses, allocator, unique_strings) - case ^Enum_Type: - r.base_type = clone_type(r.base_type, allocator, unique_strings) - r.fields = clone_type(r.fields, allocator, unique_strings) - case ^Bit_Set_Type: - r.elem = clone_type(r.elem, allocator, unique_strings) - r.underlying = clone_type(r.underlying, allocator, unique_strings) - case ^Map_Type: - r.key = clone_type(r.key, allocator, unique_strings) - r.value = clone_type(r.value, allocator, unique_strings) - case ^Call_Expr: - r.expr = clone_type(r.expr, allocator, unique_strings) - r.args = clone_type(r.args, allocator, unique_strings) - case ^Typeid_Type: - r.specialization = clone_type(r.specialization, allocator, unique_strings) - case ^Ternary_When_Expr: - r.x = clone_type(r.x, allocator, unique_strings) - r.cond = clone_type(r.cond, allocator, unique_strings) - r.y = clone_type(r.y, allocator, unique_strings) - case ^Poly_Type: - r.type = auto_cast clone_type(r.type, allocator, unique_strings) - r.specialization = clone_type(r.specialization, allocator, unique_strings) - case ^Proc_Group: - r.args = clone_type(r.args, allocator, unique_strings) - case ^Comp_Lit: - r.type = clone_type(r.type, allocator, unique_strings) - r.elems = clone_type(r.elems, allocator, unique_strings) - case ^Proc_Lit: - r.type = cast(^Proc_Type)clone_type(cast(^Node)r.type, allocator, unique_strings) - r.body = nil - r.where_clauses = nil - case ^Helper_Type: - r.type = clone_type(r.type, allocator, unique_strings) - case ^Type_Cast: - r.type = clone_type(r.type, allocator, unique_strings) - r.expr = clone_type(r.expr, allocator, unique_strings) - case ^Deref_Expr: - r.expr = clone_type(r.expr, allocator, unique_strings) - case ^Index_Expr: - r.expr = clone_type(r.expr, allocator, unique_strings) - r.index = clone_type(r.index, allocator, unique_strings) - case ^Multi_Pointer_Type: - r.elem = clone_type(r.elem, allocator, unique_strings) - case ^Matrix_Type: - r.elem = clone_type(r.elem, allocator, unique_strings) - case ^Type_Assertion: - r.expr = clone_type(r.expr, allocator, unique_strings) - r.type = clone_type(r.type, allocator, unique_strings) - case: + if unique_strings == nil { + r.name = strings.clone(n.name, allocator) + } else { + r.name = get_index_unique_string( + unique_strings, + allocator, + n.name, + ) + } + case ^Implicit: + n := node.derived.(^Implicit) + if unique_strings == nil { + r.tok.text = strings.clone(n.tok.text, allocator) + } else { + r.tok.text = get_index_unique_string( + unique_strings, + allocator, + n.tok.text, + ) + } + case ^Undef: + case ^Basic_Lit: + n := node.derived.(^Basic_Lit) + if unique_strings == nil { + r.tok.text = strings.clone(n.tok.text, allocator) + } else { + r.tok.text = get_index_unique_string( + unique_strings, + allocator, + n.tok.text, + ) + } + case ^Basic_Directive: + n := node.derived.(^Basic_Directive) + if unique_strings == nil { + r.name = strings.clone(n.name, allocator) + } else { + r.name = get_index_unique_string( + unique_strings, + allocator, + n.name, + ) + } + case ^Ellipsis: + r.expr = clone_type(r.expr, allocator, unique_strings) + case ^Tag_Expr: + r.expr = clone_type(r.expr, allocator, unique_strings) + case ^Unary_Expr: + r.expr = clone_type(r.expr, allocator, unique_strings) + case ^Binary_Expr: + r.left = clone_type(r.left, allocator, unique_strings) + r.right = clone_type(r.right, allocator, unique_strings) + case ^Paren_Expr: + r.expr = clone_type(r.expr, allocator, unique_strings) + case ^Selector_Expr: + r.expr = clone_type(r.expr, allocator, unique_strings) + r.field = auto_cast clone_type(r.field, allocator, unique_strings) + case ^Implicit_Selector_Expr: + r.field = auto_cast clone_type(r.field, allocator, unique_strings) + case ^Slice_Expr: + r.expr = clone_type(r.expr, allocator, unique_strings) + r.low = clone_type(r.low, allocator, unique_strings) + r.high = clone_type(r.high, allocator, unique_strings) + case ^Attribute: + r.elems = clone_type(r.elems, allocator, unique_strings) + case ^Distinct_Type: + r.type = clone_type(r.type, allocator, unique_strings) + case ^Proc_Type: + r.params = + auto_cast clone_type(r.params, allocator, unique_strings) + r.results = + auto_cast clone_type(r.results, allocator, unique_strings) + case ^Pointer_Type: + r.elem = clone_type(r.elem, allocator, unique_strings) + case ^Array_Type: + r.len = clone_type(r.len, allocator, unique_strings) + r.elem = clone_type(r.elem, allocator, unique_strings) + r.tag = clone_type(r.tag, allocator, unique_strings) + case ^Dynamic_Array_Type: + r.elem = clone_type(r.elem, allocator, unique_strings) + r.tag = clone_type(r.tag, allocator, unique_strings) + case ^Struct_Type: + r.poly_params = + auto_cast clone_type(r.poly_params, allocator, unique_strings) + r.align = clone_type(r.align, allocator, unique_strings) + r.fields = + auto_cast clone_type(r.fields, allocator, unique_strings) + r.where_clauses = clone_type( + r.where_clauses, + allocator, + unique_strings, + ) + case ^Field: + r.names = clone_type(r.names, allocator, unique_strings) + r.type = clone_type(r.type, allocator, unique_strings) + r.default_value = clone_type( + r.default_value, + allocator, + unique_strings, + ) + case ^Field_List: + r.list = clone_type(r.list, allocator, unique_strings) + case ^Field_Value: + r.field = clone_type(r.field, allocator, unique_strings) + r.value = clone_type(r.value, allocator, unique_strings) + case ^Union_Type: + r.poly_params = + auto_cast clone_type(r.poly_params, allocator, unique_strings) + r.align = clone_type(r.align, allocator, unique_strings) + r.variants = clone_type(r.variants, allocator, unique_strings) + r.where_clauses = clone_type( + r.where_clauses, + allocator, + unique_strings, + ) + case ^Enum_Type: + r.base_type = clone_type(r.base_type, allocator, unique_strings) + r.fields = clone_type(r.fields, allocator, unique_strings) + case ^Bit_Set_Type: + r.elem = clone_type(r.elem, allocator, unique_strings) + r.underlying = clone_type(r.underlying, allocator, unique_strings) + case ^Map_Type: + r.key = clone_type(r.key, allocator, unique_strings) + r.value = clone_type(r.value, allocator, unique_strings) + case ^Call_Expr: + r.expr = clone_type(r.expr, allocator, unique_strings) + r.args = clone_type(r.args, allocator, unique_strings) + case ^Typeid_Type: + r.specialization = clone_type( + r.specialization, + allocator, + unique_strings, + ) + case ^Ternary_When_Expr: + r.x = clone_type(r.x, allocator, unique_strings) + r.cond = clone_type(r.cond, allocator, unique_strings) + r.y = clone_type(r.y, allocator, unique_strings) + case ^Poly_Type: + r.type = auto_cast clone_type(r.type, allocator, unique_strings) + r.specialization = clone_type( + r.specialization, + allocator, + unique_strings, + ) + case ^Proc_Group: + r.args = clone_type(r.args, allocator, unique_strings) + case ^Comp_Lit: + r.type = clone_type(r.type, allocator, unique_strings) + r.elems = clone_type(r.elems, allocator, unique_strings) + case ^Proc_Lit: + r.type = + cast(^Proc_Type)clone_type( + cast(^Node)r.type, + allocator, + unique_strings, + ) + r.body = nil + r.where_clauses = nil + case ^Helper_Type: + r.type = clone_type(r.type, allocator, unique_strings) + case ^Type_Cast: + r.type = clone_type(r.type, allocator, unique_strings) + r.expr = clone_type(r.expr, allocator, unique_strings) + case ^Deref_Expr: + r.expr = clone_type(r.expr, allocator, unique_strings) + case ^Index_Expr: + r.expr = clone_type(r.expr, allocator, unique_strings) + r.index = clone_type(r.index, allocator, unique_strings) + case ^Multi_Pointer_Type: + r.elem = clone_type(r.elem, allocator, unique_strings) + case ^Matrix_Type: + r.elem = clone_type(r.elem, allocator, unique_strings) + case ^Type_Assertion: + r.expr = clone_type(r.expr, allocator, unique_strings) + r.type = clone_type(r.type, allocator, unique_strings) + case: //fmt.logf("Unhandled node kind: %T", r) - } + } return res } diff --git a/src/server/collector.odin b/src/server/collector.odin index 464b22f..5cea81f 100644 --- a/src/server/collector.odin +++ b/src/server/collector.odin @@ -24,33 +24,49 @@ get_index_unique_string :: proc { get_index_unique_string_collection_raw, } -get_index_unique_string_collection :: proc(collection: ^SymbolCollection, s: string) -> string { - return get_index_unique_string_collection_raw(&collection.unique_strings, collection.allocator, s) +get_index_unique_string_collection :: proc( + collection: ^SymbolCollection, + s: string, +) -> string { + return get_index_unique_string_collection_raw( + &collection.unique_strings, + collection.allocator, + s, + ) } -get_index_unique_string_collection_raw :: proc(unique_strings: ^map[string]string, allocator: mem.Allocator, s: string) -> string { +get_index_unique_string_collection_raw :: proc( + unique_strings: ^map[string]string, + allocator: mem.Allocator, + s: string, +) -> string { if _, ok := unique_strings[s]; !ok { str := strings.clone(s, allocator) - unique_strings[str] = str + unique_strings[str] = str } return unique_strings[s] } -make_symbol_collection :: proc(allocator := context.allocator, config: ^common.Config) -> SymbolCollection { - return SymbolCollection { - allocator = allocator, - config = config, - packages = make(map[string]map[string]Symbol, 16, allocator), - unique_strings = make(map[string]string, 16, allocator), - } +make_symbol_collection :: proc( + allocator := context.allocator, + config: ^common.Config, +) -> SymbolCollection { + return( + SymbolCollection{ + allocator = allocator, + config = config, + packages = make(map[string]map[string]Symbol, 16, allocator), + unique_strings = make(map[string]string, 16, allocator), + } \ + ) } delete_symbol_collection :: proc(collection: SymbolCollection) { for k, v in collection.packages { for k2, v2 in v { free_symbol(v2, collection.allocator) - } + } } for k, v in collection.unique_strings { @@ -65,13 +81,23 @@ delete_symbol_collection :: proc(collection: SymbolCollection) { delete(collection.unique_strings) } -collect_procedure_fields :: proc(collection: ^SymbolCollection, proc_type: ^ast.Proc_Type, arg_list: ^ast.Field_List, return_list: ^ast.Field_List, package_map: map[string]string) -> SymbolProcedureValue { +collect_procedure_fields :: proc( + collection: ^SymbolCollection, + proc_type: ^ast.Proc_Type, + arg_list: ^ast.Field_List, + return_list: ^ast.Field_List, + package_map: map[string]string, +) -> SymbolProcedureValue { returns := make([dynamic]^ast.Field, 0, collection.allocator) args := make([dynamic]^ast.Field, 0, collection.allocator) if return_list != nil { for ret in return_list.list { - cloned := cast(^ast.Field)clone_type(ret, collection.allocator, &collection.unique_strings) + cloned := cast(^ast.Field)clone_type( + ret, + collection.allocator, + &collection.unique_strings, + ) replace_package_alias(cloned, package_map, collection) append(&returns, cloned) } @@ -79,7 +105,11 @@ collect_procedure_fields :: proc(collection: ^SymbolCollection, proc_type: ^ast. if arg_list != nil { for arg in arg_list.list { - cloned := cast(^ast.Field)clone_type(arg, collection.allocator, &collection.unique_strings) + cloned := cast(^ast.Field)clone_type( + arg, + collection.allocator, + &collection.unique_strings, + ) replace_package_alias(cloned, package_map, collection) append(&args, cloned) } @@ -87,13 +117,18 @@ collect_procedure_fields :: proc(collection: ^SymbolCollection, proc_type: ^ast. value := SymbolProcedureValue { return_types = returns[:], - arg_types = args[:], - generic = proc_type.generic, + arg_types = args[:], + generic = proc_type.generic, } return value } -collect_struct_fields :: proc(collection: ^SymbolCollection, struct_type: ast.Struct_Type, package_map: map[string]string, file: ast.File) -> SymbolStructValue { +collect_struct_fields :: proc( + collection: ^SymbolCollection, + struct_type: ast.Struct_Type, + package_map: map[string]string, + file: ast.File, +) -> SymbolStructValue { names := make([dynamic]string, 0, collection.allocator) types := make([dynamic]^ast.Expr, 0, collection.allocator) usings := make(map[string]bool, 0, collection.allocator) @@ -104,7 +139,11 @@ collect_struct_fields :: proc(collection: ^SymbolCollection, struct_type: ast.St ident := n.derived.(^ast.Ident) append(&names, get_index_unique_string(collection, ident.name)) - cloned := clone_type(field.type, collection.allocator, &collection.unique_strings) + cloned := clone_type( + field.type, + collection.allocator, + &collection.unique_strings, + ) replace_package_alias(cloned, package_map, collection) append(&types, cloned) @@ -117,17 +156,25 @@ collect_struct_fields :: proc(collection: ^SymbolCollection, struct_type: ast.St } value := SymbolStructValue { - names = names[:], - types = types[:], + names = names[:], + types = types[:], ranges = ranges[:], usings = usings, - poly = cast(^ast.Field_List)clone_type(struct_type.poly_params, collection.allocator, &collection.unique_strings), + poly = cast(^ast.Field_List)clone_type( + struct_type.poly_params, + collection.allocator, + &collection.unique_strings, + ), } return value } -collect_enum_fields :: proc(collection: ^SymbolCollection, fields: []^ast.Expr, package_map: map[string]string) -> SymbolEnumValue { +collect_enum_fields :: proc( + collection: ^SymbolCollection, + fields: []^ast.Expr, + package_map: map[string]string, +) -> SymbolEnumValue { names := make([dynamic]string, 0, collection.allocator) //ERROR no hover on n in the for, but elsewhere is fine @@ -137,9 +184,16 @@ collect_enum_fields :: proc(collection: ^SymbolCollection, fields: []^ast.Expr, } else if field, ok := n.derived.(^ast.Field_Value); ok { if ident, ok := field.field.derived.(^ast.Ident); ok { append(&names, get_index_unique_string(collection, ident.name)) - } else if binary, ok := field.field.derived.(^ast.Binary_Expr); ok { - append(&names, get_index_unique_string(collection, binary.left.derived.(^ast.Ident).name)) - } + } else if binary, ok := field.field.derived.(^ast.Binary_Expr); + ok { + append( + &names, + get_index_unique_string( + collection, + binary.left.derived.(^ast.Ident).name, + ), + ) + } } } @@ -150,95 +204,155 @@ collect_enum_fields :: proc(collection: ^SymbolCollection, fields: []^ast.Expr, return value } -collect_union_fields :: proc(collection: ^SymbolCollection, union_type: ast.Union_Type, package_map: map[string]string) -> SymbolUnionValue { +collect_union_fields :: proc( + collection: ^SymbolCollection, + union_type: ast.Union_Type, + package_map: map[string]string, +) -> SymbolUnionValue { types := make([dynamic]^ast.Expr, 0, collection.allocator) for variant in union_type.variants { - cloned := clone_type(variant, collection.allocator, &collection.unique_strings) + cloned := clone_type( + variant, + collection.allocator, + &collection.unique_strings, + ) replace_package_alias(cloned, package_map, collection) append(&types, cloned) } value := SymbolUnionValue { types = types[:], - poly = cast(^ast.Field_List)clone_type(union_type.poly_params, collection.allocator, &collection.unique_strings), + poly = cast(^ast.Field_List)clone_type( + union_type.poly_params, + collection.allocator, + &collection.unique_strings, + ), } return value } -collect_bitset_field :: proc(collection: ^SymbolCollection, bitset_type: ast.Bit_Set_Type, package_map: map[string]string) -> SymbolBitSetValue { - cloned := clone_type(bitset_type.elem, collection.allocator, &collection.unique_strings) +collect_bitset_field :: proc( + collection: ^SymbolCollection, + bitset_type: ast.Bit_Set_Type, + package_map: map[string]string, +) -> SymbolBitSetValue { + cloned := clone_type( + bitset_type.elem, + collection.allocator, + &collection.unique_strings, + ) replace_package_alias(cloned, package_map, collection) - return SymbolBitSetValue { - expr = cloned, - } + return SymbolBitSetValue{expr = cloned} } -collect_slice :: proc(collection: ^SymbolCollection, array: ast.Array_Type, package_map: map[string]string) -> SymbolFixedArrayValue { - elem := clone_type(array.elem, collection.allocator, &collection.unique_strings) - len := clone_type(array.len, collection.allocator, &collection.unique_strings) +collect_slice :: proc( + collection: ^SymbolCollection, + array: ast.Array_Type, + package_map: map[string]string, +) -> SymbolFixedArrayValue { + elem := clone_type( + array.elem, + collection.allocator, + &collection.unique_strings, + ) + len := clone_type( + array.len, + collection.allocator, + &collection.unique_strings, + ) replace_package_alias(elem, package_map, collection) replace_package_alias(len, package_map, collection) - return SymbolFixedArrayValue { - expr = elem, - len = len, - } + return SymbolFixedArrayValue{expr = elem, len = len} } -collect_array :: proc(collection: ^SymbolCollection, array: ast.Array_Type, package_map: map[string]string) -> SymbolSliceValue { - elem := clone_type(array.elem, collection.allocator, &collection.unique_strings) +collect_array :: proc( + collection: ^SymbolCollection, + array: ast.Array_Type, + package_map: map[string]string, +) -> SymbolSliceValue { + elem := clone_type( + array.elem, + collection.allocator, + &collection.unique_strings, + ) replace_package_alias(elem, package_map, collection) - return SymbolSliceValue { - expr = elem, - } + return SymbolSliceValue{expr = elem} } -collect_map :: proc(collection: ^SymbolCollection, m: ast.Map_Type, package_map: map[string]string) -> SymbolMapValue { - key := clone_type(m.key, collection.allocator, &collection.unique_strings) - value := clone_type(m.value, collection.allocator, &collection.unique_strings) +collect_map :: proc( + collection: ^SymbolCollection, + m: ast.Map_Type, + package_map: map[string]string, +) -> SymbolMapValue { + key := clone_type(m.key, collection.allocator, &collection.unique_strings) + value := clone_type( + m.value, + collection.allocator, + &collection.unique_strings, + ) replace_package_alias(key, package_map, collection) replace_package_alias(value, package_map, collection) - return SymbolMapValue { - key = key, - value = value, - } + return SymbolMapValue{key = key, value = value} } -collect_dynamic_array :: proc(collection: ^SymbolCollection, array: ast.Dynamic_Array_Type, package_map: map[string]string) -> SymbolDynamicArrayValue { - elem := clone_type(array.elem, collection.allocator, &collection.unique_strings) +collect_dynamic_array :: proc( + collection: ^SymbolCollection, + array: ast.Dynamic_Array_Type, + package_map: map[string]string, +) -> SymbolDynamicArrayValue { + elem := clone_type( + array.elem, + collection.allocator, + &collection.unique_strings, + ) replace_package_alias(elem, package_map, collection) - return SymbolDynamicArrayValue { - expr = elem, - } + return SymbolDynamicArrayValue{expr = elem} } -collect_multi_pointer :: proc(collection: ^SymbolCollection, array: ast.Multi_Pointer_Type, package_map: map[string]string) -> SymbolMultiPointer { - elem := clone_type(array.elem, collection.allocator, &collection.unique_strings) +collect_multi_pointer :: proc( + collection: ^SymbolCollection, + array: ast.Multi_Pointer_Type, + package_map: map[string]string, +) -> SymbolMultiPointer { + elem := clone_type( + array.elem, + collection.allocator, + &collection.unique_strings, + ) replace_package_alias(elem, package_map, collection) - return SymbolMultiPointer { - expr = elem, - } + return SymbolMultiPointer{expr = elem} } -collect_generic :: proc(collection: ^SymbolCollection, expr: ^ast.Expr, package_map: map[string]string, uri: string) -> SymbolGenericValue { +collect_generic :: proc( + collection: ^SymbolCollection, + expr: ^ast.Expr, + package_map: map[string]string, + uri: string, +) -> SymbolGenericValue { //Bit hacky right now, but it's hopefully a temporary solution. //In the c package code it uses a documentation package(builtin). if selector, ok := expr.derived.(^ast.Selector_Expr); ok { if ident, ok := selector.expr.derived.(^ast.Ident); ok { - if ident.name == "builtin" && strings.contains(uri, "Odin/core/c/c.odin") { - cloned := clone_type(selector.field, collection.allocator, &collection.unique_strings) + if ident.name == "builtin" && + strings.contains(uri, "Odin/core/c/c.odin") { + cloned := clone_type( + selector.field, + collection.allocator, + &collection.unique_strings, + ) replace_package_alias(cloned, package_map, collection) value := SymbolGenericValue { expr = cloned, @@ -248,7 +362,11 @@ collect_generic :: proc(collection: ^SymbolCollection, expr: ^ast.Expr, package_ } } - cloned := clone_type(expr, collection.allocator, &collection.unique_strings) + cloned := clone_type( + expr, + collection.allocator, + &collection.unique_strings, + ) replace_package_alias(cloned, package_map, collection) value := SymbolGenericValue { @@ -258,7 +376,11 @@ collect_generic :: proc(collection: ^SymbolCollection, expr: ^ast.Expr, package_ return value } -collect_symbols :: proc(collection: ^SymbolCollection, file: ast.File, uri: string) -> common.Error { +collect_symbols :: proc( + collection: ^SymbolCollection, + file: ast.File, + uri: string, +) -> common.Error { forward, _ := filepath.to_slash(file.fullpath, context.temp_allocator) directory := path.dir(forward, context.temp_allocator) package_map := get_package_mapping(file, collection.config, directory) @@ -293,27 +415,52 @@ collect_symbols :: proc(collection: ^SymbolCollection, file: ast.File, uri: stri token_type = .Function if v.type != nil { - symbol.value = collect_procedure_fields(collection, v.type, v.type.params, v.type.results, package_map) + symbol.value = collect_procedure_fields( + collection, + v.type, + v.type.params, + v.type.results, + package_map, + ) } case ^ast.Proc_Type: token = v^ token_type = .Function - symbol.value = collect_procedure_fields(collection, cast(^ast.Proc_Type)col_expr, v.params, v.results, package_map) + symbol.value = collect_procedure_fields( + collection, + cast(^ast.Proc_Type)col_expr, + v.params, + v.results, + package_map, + ) case ^ast.Proc_Group: token = v^ token_type = .Function symbol.value = SymbolProcedureGroupValue { - group = clone_type(col_expr, collection.allocator, &collection.unique_strings), + group = clone_type( + col_expr, + collection.allocator, + &collection.unique_strings, + ), } case ^ast.Struct_Type: token = v^ token_type = .Struct - symbol.value = collect_struct_fields(collection, v^, package_map, file) + symbol.value = collect_struct_fields( + collection, + v^, + package_map, + file, + ) symbol.signature = "struct" case ^ast.Enum_Type: token = v^ token_type = .Enum - symbol.value = collect_enum_fields(collection, v.fields, package_map) + symbol.value = collect_enum_fields( + collection, + v.fields, + package_map, + ) symbol.signature = "enum" case ^ast.Union_Type: token = v^ @@ -347,7 +494,12 @@ collect_symbols :: proc(collection: ^SymbolCollection, file: ast.File, uri: stri symbol.value = collect_multi_pointer(collection, v^, package_map) case ^ast.Basic_Lit: token = v^ - symbol.value = collect_generic(collection, col_expr, package_map, uri) + symbol.value = collect_generic( + collection, + col_expr, + package_map, + uri, + ) if expr.mutable { token_type = .Variable } else { @@ -355,14 +507,25 @@ collect_symbols :: proc(collection: ^SymbolCollection, file: ast.File, uri: stri } case ^ast.Ident: token = v^ - symbol.value = collect_generic(collection, col_expr, package_map, uri) + symbol.value = collect_generic( + collection, + col_expr, + package_map, + uri, + ) if expr.mutable { token_type = .Variable } else { token_type = .Unresolved } - case: // default - symbol.value = collect_generic(collection, col_expr, package_map, uri) + case: + // default + symbol.value = collect_generic( + collection, + col_expr, + package_map, + uri, + ) if expr.mutable { token_type = .Variable } else { @@ -375,7 +538,7 @@ collect_symbols :: proc(collection: ^SymbolCollection, file: ast.File, uri: stri symbol.name = get_index_unique_string(collection, name) symbol.type = token_type symbol.doc = common.get_doc(expr.docs, collection.allocator) - + if expr.builtin || strings.contains(uri, "builtin.odin") { symbol.pkg = "$builtin" } else if strings.contains(uri, "intrinsics.odin") { @@ -397,34 +560,42 @@ collect_symbols :: proc(collection: ^SymbolCollection, file: ast.File, uri: stri } symbol.uri = get_index_unique_string(collection, uri) - + pkg: ^map[string]Symbol ok: bool if pkg, ok = &collection.packages[symbol.pkg]; !ok { - collection.packages[symbol.pkg] = make(map[string]Symbol, 100, collection.allocator) + collection.packages[symbol.pkg] = make( + map[string]Symbol, + 100, + collection.allocator, + ) pkg = &collection.packages[symbol.pkg] - } + } if v, ok := pkg[symbol.name]; !ok || v.name == "" { pkg[symbol.name] = symbol } else { free_symbol(symbol, collection.allocator) - } + } } return .None } Reference :: struct { - identifiers: [dynamic]common.Location, - selectors: map[string][dynamic]common.Range, + identifiers: [dynamic]common.Location, + selectors: map[string][dynamic]common.Range, } /* Gets the map from import alias to absolute package directory */ -get_package_mapping :: proc(file: ast.File, config: ^common.Config, directory: string) -> map[string]string { +get_package_mapping :: proc( + file: ast.File, + config: ^common.Config, + directory: string, +) -> map[string]string { package_map := make(map[string]string, 0, context.temp_allocator) for imp, index in file.imports { @@ -441,7 +612,10 @@ get_package_mapping :: proc(file: ast.File, config: ^common.Config, directory: s name: string - full := path.join(elems = {dir, p}, allocator = context.temp_allocator) + full := path.join( + elems = {dir, p}, + allocator = context.temp_allocator, + ) if imp.name.text != "" { name = imp.name.text @@ -453,7 +627,10 @@ get_package_mapping :: proc(file: ast.File, config: ^common.Config, directory: s } else { name: string - full := path.join(elems = {directory, imp.fullpath[1:len(imp.fullpath) - 1]}, allocator = context.temp_allocator) + full := path.join( + elems = {directory, imp.fullpath[1:len(imp.fullpath) - 1]}, + allocator = context.temp_allocator, + ) full = path.clean(full, context.temp_allocator) if imp.name.text != "" { @@ -481,23 +658,39 @@ replace_package_alias :: proc { replace_package_alias_dynamic_array, } -replace_package_alias_array :: proc(array: $A/[]^$T, package_map: map[string]string, collection: ^SymbolCollection) { +replace_package_alias_array :: proc( + array: $A/[]^$T, + package_map: map[string]string, + collection: ^SymbolCollection, +) { for elem, i in array { replace_package_alias(elem, package_map, collection) } } -replace_package_alias_dynamic_array :: proc(array: $A/[dynamic]^$T, package_map: map[string]string, collection: ^SymbolCollection) { +replace_package_alias_dynamic_array :: proc( + array: $A/[dynamic]^$T, + package_map: map[string]string, + collection: ^SymbolCollection, +) { for elem, i in array { replace_package_alias(elem, package_map, collection) } } -replace_package_alias_expr :: proc(node: ^ast.Expr, package_map: map[string]string, collection: ^SymbolCollection) { +replace_package_alias_expr :: proc( + node: ^ast.Expr, + package_map: map[string]string, + collection: ^SymbolCollection, +) { replace_package_alias_node(node, package_map, collection) } -replace_package_alias_node :: proc(node: ^ast.Node, package_map: map[string]string, collection: ^SymbolCollection) { +replace_package_alias_node :: proc( + node: ^ast.Node, + package_map: map[string]string, + collection: ^SymbolCollection, +) { using ast if node == nil { diff --git a/src/server/completion.odin b/src/server/completion.odin index a3b80c1..2f695af 100644 --- a/src/server/completion.odin +++ b/src/server/completion.odin @@ -32,20 +32,38 @@ Completion_Type :: enum { Package, } -get_completion_list :: proc(document: ^Document, position: common.Position, completion_context: CompletionContext) -> (CompletionList, bool) { +get_completion_list :: proc( + document: ^Document, + position: common.Position, + completion_context: CompletionContext, +) -> ( + CompletionList, + bool, +) { list: CompletionList - position_context, ok := get_document_position_context(document, position, .Completion) + position_context, ok := get_document_position_context( + document, + position, + .Completion, + ) if !ok || position_context.abort_completion { return list, true } - if position_context.import_stmt == nil && strings.contains_any(completion_context.triggerCharacter, "/:\"") { + if position_context.import_stmt == nil && + strings.contains_any(completion_context.triggerCharacter, "/:\"") { return list, true } - ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri, document.fullpath) + ast_context := make_ast_context( + document.ast, + document.imports, + document.package_name, + document.uri.uri, + document.fullpath, + ) get_globals(document.ast, &ast_context) @@ -53,7 +71,12 @@ get_completion_list :: proc(document: ^Document, position: common.Position, comp ast_context.value_decl = position_context.value_decl if position_context.function != nil { - get_locals(document.ast, position_context.function, &ast_context, &position_context) + get_locals( + document.ast, + position_context.function, + &ast_context, + &position_context, + ) } completion_type: Completion_Type = .Identifier @@ -78,12 +101,17 @@ get_completion_list :: proc(document: ^Document, position: common.Position, comp completion_type = .Package } - if position_context.switch_type_stmt != nil && position_context.case_clause != nil { - if assign, ok := position_context.switch_type_stmt.tag.derived.(^ast.Assign_Stmt); ok && assign.rhs != nil && len(assign.rhs) == 1 { + if position_context.switch_type_stmt != nil && + position_context.case_clause != nil { + 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 ast_context.use_locals = true - if symbol, ok := resolve_type_expression(&ast_context, assign.rhs[0]); ok { + if symbol, ok := resolve_type_expression( + &ast_context, + assign.rhs[0], + ); ok { if union_value, ok := symbol.value.(SymbolUnionValue); ok { completion_type = .Switch_Type } @@ -111,21 +139,29 @@ get_completion_list :: proc(document: ^Document, position: common.Position, comp return list, true } -get_attribute_completion :: proc(ast_context: ^AstContext, position_context: ^DocumentPositionContext, list: ^CompletionList) { - +get_attribute_completion :: proc( + ast_context: ^AstContext, + position_context: ^DocumentPositionContext, + list: ^CompletionList, +) { + } -get_directive_completion :: proc(ast_context: ^AstContext, position_context: ^DocumentPositionContext, list: ^CompletionList) { +get_directive_completion :: proc( + ast_context: ^AstContext, + position_context: ^DocumentPositionContext, + list: ^CompletionList, +) { list.isIncomplete = false - + items := make([dynamic]CompletionItem, context.temp_allocator) /* Right now just return all the possible completions, but later on I should give the context specific ones */ - directive_list := []string { + directive_list := []string{ "file", "line", "packed", @@ -150,8 +186,8 @@ get_directive_completion :: proc(ast_context: ^AstContext, position_context: ^Do for elem in directive_list { item := CompletionItem { detail = elem, - label = elem, - kind = .Constant, + label = elem, + kind = .Constant, } append(&items, item) @@ -160,30 +196,53 @@ get_directive_completion :: proc(ast_context: ^AstContext, position_context: ^Do list.items = items[:] } -get_comp_lit_completion :: proc(ast_context: ^AstContext, position_context: ^DocumentPositionContext, list: ^CompletionList) { +get_comp_lit_completion :: proc( + ast_context: ^AstContext, + position_context: ^DocumentPositionContext, + list: ^CompletionList, +) { items := make([dynamic]CompletionItem, context.temp_allocator) if position_context.parent_comp_lit.type == nil { return } - if symbol, ok := resolve_type_expression(ast_context, position_context.parent_comp_lit.type); ok { - if comp_symbol, _, ok := resolve_type_comp_literal(ast_context, position_context, symbol, position_context.parent_comp_lit); ok { - ast_context.current_package = comp_symbol.pkg; + if symbol, ok := resolve_type_expression( + ast_context, + position_context.parent_comp_lit.type, + ); ok { + if comp_symbol, _, ok := resolve_type_comp_literal( + ast_context, + position_context, + symbol, + position_context.parent_comp_lit, + ); ok { + ast_context.current_package = comp_symbol.pkg #partial switch v in comp_symbol.value { case SymbolStructValue: for name, i in v.names { ast_context.current_package = comp_symbol.pkg - if resolved, ok := resolve_type_expression(ast_context, v.types[i]); ok { - if field_exists_in_comp_lit(position_context.comp_lit, name) { + if resolved, ok := resolve_type_expression( + ast_context, + v.types[i], + ); ok { + if field_exists_in_comp_lit( + position_context.comp_lit, + name, + ) { continue } item := CompletionItem { - label = name, - kind = .Field, - detail = fmt.tprintf("%v.%v: %v", comp_symbol.name, name, common.node_to_string(v.types[i])), + label = name, + kind = .Field, + detail = fmt.tprintf( + "%v.%v: %v", + comp_symbol.name, + name, + common.node_to_string(v.types[i]), + ), documentation = resolved.doc, } @@ -197,7 +256,11 @@ get_comp_lit_completion :: proc(ast_context: ^AstContext, position_context: ^Doc list.items = items[:] } -get_selector_completion :: proc(ast_context: ^AstContext, position_context: ^DocumentPositionContext, list: ^CompletionList) { +get_selector_completion :: proc( + ast_context: ^AstContext, + position_context: ^DocumentPositionContext, + list: ^CompletionList, +) { items := make([dynamic]CompletionItem, context.temp_allocator) ast_context.current_package = ast_context.document_package @@ -208,13 +271,18 @@ get_selector_completion :: proc(ast_context: ^AstContext, position_context: ^Doc ast_context.use_locals = true ast_context.use_globals = true - selector, ok = resolve_type_expression(ast_context, position_context.selector) + selector, ok = resolve_type_expression( + ast_context, + position_context.selector, + ) if !ok { return } - if selector.type != .Variable && selector.type != .Package && selector.type != .Enum { + if selector.type != .Variable && + selector.type != .Package && + selector.type != .Enum { return } @@ -235,7 +303,10 @@ get_selector_completion :: proc(ast_context: ^AstContext, position_context: ^Doc if s, ok := selector.value.(SymbolProcedureValue); ok { if len(s.return_types) == 1 { - if selector, ok = resolve_type_expression(ast_context, s.return_types[0].type); !ok { + if selector, ok = resolve_type_expression( + ast_context, + s.return_types[0].type, + ); !ok { return } } @@ -265,7 +336,7 @@ get_selector_completion :: proc(ast_context: ^AstContext, position_context: ^Doc containsCoord += 1 } } - } + } if containsColor == 1 && containsCoord == 1 { save := expr_len @@ -277,13 +348,18 @@ get_selector_completion :: proc(ast_context: ^AstContext, position_context: ^Doc expr_len -= 1 item := CompletionItem { - label = fmt.tprintf("%v%c", field, k), - kind = .Property, - detail = fmt.tprintf("%v%c: %v", field, k, common.node_to_string(v.expr)), + label = fmt.tprintf("%v%c", field, k), + kind = .Property, + detail = fmt.tprintf( + "%v%c: %v", + field, + k, + common.node_to_string(v.expr), + ), } append(&items, item) } - + expr_len = save for k in swizzle_coord_components { @@ -294,13 +370,18 @@ get_selector_completion :: proc(ast_context: ^AstContext, position_context: ^Doc expr_len -= 1 item := CompletionItem { - label = fmt.tprintf("%v%c", field, k), - kind = .Property, - detail = fmt.tprintf("%v%c: %v", field, k, common.node_to_string(v.expr)), + label = fmt.tprintf("%v%c", field, k), + kind = .Property, + detail = fmt.tprintf( + "%v%c: %v", + field, + k, + common.node_to_string(v.expr), + ), } append(&items, item) } - } + } if containsColor > 1 { for k in swizzle_color_components { @@ -311,9 +392,15 @@ get_selector_completion :: proc(ast_context: ^AstContext, position_context: ^Doc expr_len -= 1 item := CompletionItem { - label = fmt.tprintf("%v%c", field, k), - kind = .Property, - detail = fmt.tprintf("%v%c: [%v]%v", field, k, containsColor, common.node_to_string(v.expr)), + label = fmt.tprintf("%v%c", field, k), + kind = .Property, + detail = fmt.tprintf( + "%v%c: [%v]%v", + field, + k, + containsColor, + common.node_to_string(v.expr), + ), } append(&items, item) } @@ -326,13 +413,19 @@ get_selector_completion :: proc(ast_context: ^AstContext, position_context: ^Doc expr_len -= 1 item := CompletionItem { - label = fmt.tprintf("%v%c", field, k), - kind = .Property, - detail = fmt.tprintf("%v%c: [%v]%v", field, k, containsCoord, common.node_to_string(v.expr)), + label = fmt.tprintf("%v%c", field, k), + kind = .Property, + detail = fmt.tprintf( + "%v%c: [%v]%v", + field, + k, + containsCoord, + common.node_to_string(v.expr), + ), } append(&items, item) } - } + } case SymbolUnionValue: list.isIncomplete = false @@ -343,16 +436,35 @@ get_selector_completion :: proc(ast_context: ^AstContext, position_context: ^Doc base := path.base(symbol.pkg, false, context.temp_allocator) item := CompletionItem { - kind = .EnumMember, - detail = fmt.tprintf("%v", selector.name), + kind = .EnumMember, + detail = fmt.tprintf("%v", selector.name), documentation = symbol.doc, } - if symbol.pkg == ast_context.document_package || base == "runtime" || base == "$builtin" { - item.label = fmt.aprintf("(%v%v)", common.repeat("^", symbol.pointers, context.temp_allocator), common.node_to_string(type, true)) + if symbol.pkg == ast_context.document_package || + base == "runtime" || + base == "$builtin" { + item.label = fmt.aprintf( + "(%v%v)", + common.repeat( + "^", + symbol.pointers, + context.temp_allocator, + ), + common.node_to_string(type, true), + ) } else { - item.label = fmt.aprintf("(%v%v.%v)", common.repeat("^", symbol.pointers, context.temp_allocator), path.base(symbol.pkg, false, context.temp_allocator), common.node_to_string(type, true)) - } + item.label = fmt.aprintf( + "(%v%v.%v)", + common.repeat( + "^", + symbol.pointers, + context.temp_allocator, + ), + path.base(symbol.pkg, false, context.temp_allocator), + common.node_to_string(type, true), + ) + } append(&items, item) } @@ -363,8 +475,8 @@ get_selector_completion :: proc(ast_context: ^AstContext, position_context: ^Doc for name in v.names { item := CompletionItem { - label = name, - kind = .EnumMember, + label = name, + kind = .EnumMember, detail = fmt.tprintf("%v.%v", selector.name, name), } append(&items, item) @@ -380,8 +492,10 @@ get_selector_completion :: proc(ast_context: ^AstContext, position_context: ^Doc ast_context.current_package = ast_context.document_package } - if symbol, ok := resolve_type_expression(ast_context, v.types[i]); ok { - if expr, ok := position_context.selector.derived.(^ast.Selector_Expr); ok { + if symbol, ok := resolve_type_expression(ast_context, v.types[i]); + ok { + if expr, ok := position_context.selector.derived.(^ast.Selector_Expr); + ok { if expr.op.text == "->" && symbol.type != .Function { continue } @@ -392,9 +506,14 @@ get_selector_completion :: proc(ast_context: ^AstContext, position_context: ^Doc } item := CompletionItem { - label = name, - kind = .Field, - detail = fmt.tprintf("%v.%v: %v", selector.name, name, type_to_string(ast_context, v.types[i])), + label = name, + kind = .Field, + detail = fmt.tprintf( + "%v.%v: %v", + selector.name, + name, + type_to_string(ast_context, v.types[i]), + ), documentation = symbol.doc, } @@ -402,9 +521,13 @@ get_selector_completion :: proc(ast_context: ^AstContext, position_context: ^Doc } else { //just give some generic symbol with name. item := CompletionItem { - label = symbol.name, - kind = .Field, - detail = fmt.tprintf("%v: %v", name, common.node_to_string(v.types[i])), + label = symbol.name, + kind = .Field, + detail = fmt.tprintf( + "%v: %v", + name, + common.node_to_string(v.types[i]), + ), documentation = symbol.doc, } @@ -423,45 +546,62 @@ get_selector_completion :: proc(ast_context: ^AstContext, position_context: ^Doc resolve_unresolved_symbol(ast_context, &symbol) build_procedure_symbol_signature(&symbol) - + item := CompletionItem { - label = symbol.name, - kind = cast(CompletionItemKind)symbol.type, - detail = concatenate_symbol_information(ast_context, symbol, true), + label = symbol.name, + kind = cast(CompletionItemKind)symbol.type, + detail = concatenate_symbol_information( + ast_context, + symbol, + true, + ), documentation = symbol.doc, } if symbol.type == .Function && common.config.enable_snippets { item.insertText = fmt.tprintf("%v($0)", item.label) item.insertTextFormat = .Snippet - item.command.command = "editor.action.triggerParameterHints" - item.deprecated = .Deprecated in symbol.flags + item.command.command = + "editor.action.triggerParameterHints" + item.deprecated = .Deprecated in symbol.flags } append(&items, item) } } else { - log.errorf("Failed to fuzzy search, field: %v, package: %v", field, selector.pkg) + log.errorf( + "Failed to fuzzy search, field: %v, package: %v", + field, + selector.pkg, + ) return } case SymbolDynamicArrayValue: list.isIncomplete = false - append_magic_dynamic_array_completion(position_context, selector, &items) + append_magic_dynamic_array_completion( + position_context, + selector, + &items, + ) case SymbolMapValue: - list.isIncomplete = false + list.isIncomplete = false append_magic_map_completion(position_context, selector, &items) } list.items = items[:] } -get_implicit_completion :: proc(ast_context: ^AstContext, position_context: ^DocumentPositionContext, list: ^CompletionList) { +get_implicit_completion :: proc( + ast_context: ^AstContext, + position_context: ^DocumentPositionContext, + list: ^CompletionList, +) { items := make([dynamic]CompletionItem, context.temp_allocator) list.isIncomplete = false selector: Symbol - + ast_context.use_locals = true ast_context.use_globals = true @@ -472,12 +612,16 @@ get_implicit_completion :: proc(ast_context: ^AstContext, position_context: ^Doc } //value decl infer a : My_Enum = .* - if position_context.value_decl != nil && position_context.value_decl.type != nil { - if enum_value, ok := unwrap_enum(ast_context, position_context.value_decl.type); ok { + if position_context.value_decl != nil && + position_context.value_decl.type != nil { + if enum_value, ok := unwrap_enum( + ast_context, + position_context.value_decl.type, + ); ok { for name in enum_value.names { item := CompletionItem { - label = name, - kind = .EnumMember, + label = name, + kind = .EnumMember, detail = name, } append(&items, item) @@ -489,14 +633,18 @@ get_implicit_completion :: proc(ast_context: ^AstContext, position_context: ^Doc } //enum switch infer - if position_context.switch_stmt != nil && position_context.case_clause != nil && position_context.switch_stmt.cond != nil { + if position_context.switch_stmt != nil && + position_context.case_clause != nil && + position_context.switch_stmt.cond != nil { used_enums := make(map[string]bool, 5, context.temp_allocator) - if block, ok := position_context.switch_stmt.body.derived.(^ast.Block_Stmt); ok { + if block, ok := position_context.switch_stmt.body.derived.(^ast.Block_Stmt); + ok { for stmt in block.stmts { if case_clause, ok := stmt.derived.(^ast.Case_Clause); ok { for name in case_clause.list { - if implicit, ok := name.derived.(^ast.Implicit_Selector_Expr); ok { + if implicit, ok := name.derived.(^ast.Implicit_Selector_Expr); + ok { used_enums[implicit.field.name] = true } } @@ -504,15 +652,18 @@ get_implicit_completion :: proc(ast_context: ^AstContext, position_context: ^Doc } } - if enum_value, ok := unwrap_enum(ast_context, position_context.switch_stmt.cond); ok { + if enum_value, ok := unwrap_enum( + ast_context, + position_context.switch_stmt.cond, + ); ok { for name in enum_value.names { if name in used_enums { continue } item := CompletionItem { - label = name, - kind = .EnumMember, + label = name, + kind = .EnumMember, detail = name, } @@ -524,15 +675,21 @@ get_implicit_completion :: proc(ast_context: ^AstContext, position_context: ^Doc } } - if position_context.assign != nil && position_context.assign.lhs != nil && len(position_context.assign.lhs) == 1 && is_bitset_assignment_operator(position_context.assign.op.text) { + if position_context.assign != nil && + position_context.assign.lhs != nil && + len(position_context.assign.lhs) == 1 && + is_bitset_assignment_operator(position_context.assign.op.text) { //bitsets - if symbol, ok := resolve_type_expression(ast_context, position_context.assign.lhs[0]); ok { + if symbol, ok := resolve_type_expression( + ast_context, + position_context.assign.lhs[0], + ); ok { if value, ok := unwrap_bitset(ast_context, symbol); ok { for name in value.names { item := CompletionItem { - label = name, - kind = .EnumMember, + label = name, + kind = .EnumMember, detail = name, } @@ -545,14 +702,19 @@ get_implicit_completion :: proc(ast_context: ^AstContext, position_context: ^Doc } } - if position_context.comp_lit != nil && position_context.parent_binary != nil && is_bitset_binary_operator(position_context.binary.op.text) { + if position_context.comp_lit != nil && + position_context.parent_binary != nil && + is_bitset_binary_operator(position_context.binary.op.text) { //bitsets - if symbol, ok := resolve_first_symbol_from_binary_expression(ast_context, position_context.parent_binary); ok { + if symbol, ok := resolve_first_symbol_from_binary_expression( + ast_context, + position_context.parent_binary, + ); ok { if value, ok := unwrap_bitset(ast_context, symbol); ok { for name in value.names { item := CompletionItem { - label = name, - kind = .EnumMember, + label = name, + kind = .EnumMember, detail = name, } @@ -574,17 +736,26 @@ get_implicit_completion :: proc(ast_context: ^AstContext, position_context: ^Doc field_name: string if position_context.field_value != nil { - if field, ok := position_context.field_value.field.derived.(^ast.Ident); ok { + if field, ok := position_context.field_value.field.derived.(^ast.Ident); + ok { field_name = field.name } else { return - } + } } - if symbol, ok := resolve_type_expression(ast_context, position_context.parent_comp_lit.type); ok { - if comp_symbol, comp_lit, ok := resolve_type_comp_literal(ast_context, position_context, symbol, position_context.parent_comp_lit); ok { + if symbol, ok := resolve_type_expression( + ast_context, + position_context.parent_comp_lit.type, + ); ok { + if comp_symbol, comp_lit, ok := resolve_type_comp_literal( + ast_context, + position_context, + symbol, + position_context.parent_comp_lit, + ); ok { if s, ok := comp_symbol.value.(SymbolStructValue); ok { - ast_context.current_package = comp_symbol.pkg; + ast_context.current_package = comp_symbol.pkg //We can either have the final elem_index := -1 @@ -600,21 +771,21 @@ get_implicit_completion :: proc(ast_context: ^AstContext, position_context: ^Doc for name, i in s.names { if name != field_name { continue - } + } type = s.types[i] break } - if type == nil && len(s.types) > elem_index { + if type == nil && len(s.types) > elem_index { type = s.types[elem_index] } if enum_value, ok := unwrap_enum(ast_context, type); ok { for enum_name in enum_value.names { item := CompletionItem { - label = enum_name, - kind = .EnumMember, + label = enum_name, + kind = .EnumMember, detail = enum_name, } @@ -623,27 +794,34 @@ get_implicit_completion :: proc(ast_context: ^AstContext, position_context: ^Doc list.items = items[:] return - } else if bitset_symbol, ok := resolve_type_expression(ast_context, type); ok { - if value, ok := unwrap_bitset(ast_context, bitset_symbol); ok { + } else if bitset_symbol, ok := resolve_type_expression( + ast_context, + type, + ); ok { + if value, ok := unwrap_bitset( + ast_context, + bitset_symbol, + ); ok { for name in value.names { - + item := CompletionItem { - label = name, - kind = .EnumMember, + label = name, + kind = .EnumMember, detail = name, } - + append(&items, item) - } + } list.items = items[:] return } } - } else if s, ok := unwrap_bitset(ast_context, comp_symbol); ok { + } else if s, ok := unwrap_bitset(ast_context, comp_symbol); + ok { for enum_name in s.names { item := CompletionItem { - label = enum_name, - kind = .EnumMember, + label = enum_name, + kind = .EnumMember, detail = enum_name, } @@ -655,16 +833,24 @@ get_implicit_completion :: proc(ast_context: ^AstContext, position_context: ^Doc } } } - } - - if position_context.binary != nil && (position_context.binary.op.text == "==" || position_context.binary.op.text == "!=") { + } + + if position_context.binary != nil && + (position_context.binary.op.text == "==" || + position_context.binary.op.text == "!=") { context_node: ^ast.Expr enum_node: ^ast.Expr - if position_in_node(position_context.binary.right, position_context.position) { + if position_in_node( + 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) { + } else if position_in_node( + position_context.binary.left, + position_context.position, + ) { context_node = position_context.binary.left enum_node = position_context.binary.right } @@ -673,8 +859,8 @@ get_implicit_completion :: proc(ast_context: ^AstContext, position_context: ^Doc if enum_value, ok := unwrap_enum(ast_context, enum_node); ok { for name in enum_value.names { item := CompletionItem { - label = name, - kind = .EnumMember, + label = name, + kind = .EnumMember, detail = name, } @@ -687,7 +873,9 @@ get_implicit_completion :: proc(ast_context: ^AstContext, position_context: ^Doc } } - if position_context.assign != nil && position_context.assign.rhs != nil && position_context.assign.lhs != nil { + if position_context.assign != nil && + position_context.assign.rhs != nil && + position_context.assign.lhs != nil { rhs_index: int for elem in position_context.assign.rhs { @@ -695,8 +883,10 @@ get_implicit_completion :: proc(ast_context: ^AstContext, position_context: ^Doc break } else { //procedures are the only types that can return more than one value - if symbol, ok := resolve_type_expression(ast_context, elem); ok { - if procedure, ok := symbol.value.(SymbolProcedureValue); ok { + if symbol, ok := resolve_type_expression(ast_context, elem); + ok { + if procedure, ok := symbol.value.(SymbolProcedureValue); + ok { if procedure.return_types == nil { return } @@ -710,7 +900,10 @@ get_implicit_completion :: proc(ast_context: ^AstContext, position_context: ^Doc } if len(position_context.assign.lhs) > rhs_index { - if enum_value, ok := unwrap_enum(ast_context, position_context.assign.lhs[rhs_index]); ok { + if enum_value, ok := unwrap_enum( + ast_context, + position_context.assign.lhs[rhs_index], + ); ok { for name in enum_value.names { item := CompletionItem { label = name, @@ -750,11 +943,16 @@ get_implicit_completion :: proc(ast_context: ^AstContext, position_context: ^Doc } if len(position_context.function.type.results.list) > return_index { - if enum_value, ok := unwrap_enum(ast_context, position_context.function.type.results.list[return_index].type); ok { + if enum_value, ok := unwrap_enum( + ast_context, + position_context.function.type.results.list[ + return_index \ + ].type, + ); ok { for name in enum_value.names { item := CompletionItem { - label = name, - kind = .EnumMember, + label = name, + kind = .EnumMember, detail = name, } @@ -769,18 +967,25 @@ get_implicit_completion :: proc(ast_context: ^AstContext, position_context: ^Doc if position_context.call != nil { if call, ok := position_context.call.derived.(^ast.Call_Expr); ok { - parameter_index, parameter_ok := find_position_in_call_param(ast_context, call^) - if symbol, ok := resolve_type_expression(ast_context, call.expr); ok && parameter_ok { + parameter_index, parameter_ok := find_position_in_call_param( + ast_context, + call^, + ) + if symbol, ok := resolve_type_expression(ast_context, call.expr); + ok && parameter_ok { if proc_value, ok := symbol.value.(SymbolProcedureValue); ok { if len(proc_value.arg_types) <= parameter_index { return } - if enum_value, ok := unwrap_enum(ast_context, proc_value.arg_types[parameter_index].type); ok { + if enum_value, ok := unwrap_enum( + ast_context, + proc_value.arg_types[parameter_index].type, + ); ok { for name in enum_value.names { item := CompletionItem { - label = name, - kind = .EnumMember, + label = name, + kind = .EnumMember, detail = name, } @@ -796,10 +1001,14 @@ get_implicit_completion :: proc(ast_context: ^AstContext, position_context: ^Doc } } -get_identifier_completion :: proc(ast_context: ^AstContext, position_context: ^DocumentPositionContext, list: ^CompletionList) { +get_identifier_completion :: proc( + ast_context: ^AstContext, + position_context: ^DocumentPositionContext, + list: ^CompletionList, +) { CombinedResult :: struct { score: f32, - snippet: Snippet_Info, + snippet: Snippet_Info, name: string, type: SymbolType, doc: string, @@ -832,7 +1041,7 @@ get_identifier_completion :: proc(ast_context: ^AstContext, position_context: ^D append(&pkgs, ast_context.document_package) append(&pkgs, "$builtin") - + if results, ok := fuzzy_search(lookup_name, pkgs[:]); ok { for r in results { r := r @@ -841,15 +1050,18 @@ get_identifier_completion :: proc(ast_context: ^AstContext, position_context: ^D uri, _ := common.parse_uri(r.symbol.uri, context.temp_allocator) if uri.path != ast_context.fullpath { - append(&combined, CombinedResult { - score = r.score, - type = r.symbol.type, - name = r.symbol.name, - doc = r.symbol.doc, - flags = r.symbol.flags, - signature = r.symbol.signature, - pkg = r.symbol.pkg, - }) + append( + &combined, + CombinedResult{ + score = r.score, + type = r.symbol.type, + name = r.symbol.name, + doc = r.symbol.doc, + flags = r.symbol.flags, + signature = r.symbol.signature, + pkg = r.symbol.pkg, + }, + ) } } } @@ -872,24 +1084,32 @@ get_identifier_completion :: proc(ast_context: ^AstContext, position_context: ^D ast_context.use_globals = true ast_context.current_package = ast_context.document_package - ident := new_type(ast.Ident, v.expr.pos, v.expr.end, context.temp_allocator) + ident := new_type( + ast.Ident, + v.expr.pos, + v.expr.end, + context.temp_allocator, + ) ident.name = k - if symbol, ok := resolve_type_identifier(ast_context, ident^); ok { + if symbol, ok := resolve_type_identifier(ast_context, ident^); ok { symbol.signature = get_signature(ast_context, ident^, symbol) build_procedure_symbol_signature(&symbol) if score, ok := common.fuzzy_match(matcher, ident.name); ok == 1 { - append(&combined, CombinedResult { - score = score * 1.1, - type = symbol.type, - name = ident.name, - doc = symbol.doc, - flags = symbol.flags, - pkg = symbol.pkg, - signature = symbol.signature, - }) + append( + &combined, + CombinedResult{ + score = score * 1.1, + type = symbol.type, + name = ident.name, + doc = symbol.doc, + flags = symbol.flags, + pkg = symbol.pkg, + signature = symbol.signature, + }, + ) } } } @@ -900,30 +1120,43 @@ get_identifier_completion :: proc(ast_context: ^AstContext, position_context: ^D break } - local_offset := get_local_offset(ast_context, position_context.position, k) + local_offset := get_local_offset( + ast_context, + position_context.position, + k, + ) ast_context.use_locals = true ast_context.use_globals = true ast_context.current_package = ast_context.document_package - ident := new_type(ast.Ident, {offset = local_offset}, {offset = local_offset}, context.temp_allocator) + ident := new_type( + ast.Ident, + {offset = local_offset}, + {offset = local_offset}, + context.temp_allocator, + ) ident.name = k - if symbol, ok := resolve_type_identifier(ast_context, ident^); ok { + if symbol, ok := resolve_type_identifier(ast_context, ident^); ok { symbol.signature = get_signature(ast_context, ident^, symbol) build_procedure_symbol_signature(&symbol) - if score, ok := common.fuzzy_match(matcher, ident.name); ok == 1 { - append(&combined, CombinedResult { - score = score * 1.7, - type = symbol.type, - name = ident.name, - doc = symbol.doc, - flags = symbol.flags, - pkg = symbol.pkg, - signature = symbol.signature, - }) + if score, ok := common.fuzzy_match(matcher, ident.name); + ok == 1 { + append( + &combined, + CombinedResult{ + score = score * 1.7, + type = symbol.type, + name = ident.name, + doc = symbol.doc, + flags = symbol.flags, + pkg = symbol.pkg, + signature = symbol.signature, + }, + ) } } } @@ -940,15 +1173,18 @@ get_identifier_completion :: proc(ast_context: ^AstContext, position_context: ^D } if score, ok := common.fuzzy_match(matcher, symbol.name); ok == 1 { - append(&combined, CombinedResult { - score = score * 1.1, - type = symbol.type, - name = symbol.name, - doc = symbol.doc, - flags = symbol.flags, - signature = symbol.signature, - pkg = symbol.pkg, - }) + append( + &combined, + CombinedResult{ + score = score * 1.1, + type = symbol.type, + name = symbol.name, + doc = symbol.doc, + flags = symbol.flags, + signature = symbol.signature, + pkg = symbol.pkg, + }, + ) } } @@ -959,18 +1195,21 @@ get_identifier_completion :: proc(ast_context: ^AstContext, position_context: ^D } if score, ok := common.fuzzy_match(matcher, keyword); ok == 1 { - append(&combined, CombinedResult { - score = score, - type = symbol.type, - name = symbol.name, - doc = symbol.doc, - flags = symbol.flags, - signature = symbol.signature, - pkg = symbol.pkg, - }) + append( + &combined, + CombinedResult{ + score = score, + type = symbol.type, + name = symbol.name, + doc = symbol.doc, + flags = symbol.flags, + signature = symbol.signature, + pkg = symbol.pkg, + }, + ) } } - + for keyword, _ in language_keywords { symbol := Symbol { name = keyword, @@ -978,22 +1217,28 @@ get_identifier_completion :: proc(ast_context: ^AstContext, position_context: ^D } if score, ok := common.fuzzy_match(matcher, keyword); ok == 1 { - append(&combined, CombinedResult { - score = score * 1.1, - type = symbol.type, - name = symbol.name, - doc = symbol.doc, - flags = symbol.flags, - signature = symbol.signature, - pkg = symbol.pkg, - }) + append( + &combined, + CombinedResult{ + score = score * 1.1, + type = symbol.type, + name = symbol.name, + doc = symbol.doc, + flags = symbol.flags, + signature = symbol.signature, + pkg = symbol.pkg, + }, + ) } } if common.config.enable_snippets { for k, v in snippets { if score, ok := common.fuzzy_match(matcher, k); ok == 1 { - append(&combined, CombinedResult {score = score * 1.1, snippet = v, name = k}) + append( + &combined, + CombinedResult{score = score * 1.1, snippet = v, name = k}, + ) } } } @@ -1009,23 +1254,28 @@ get_identifier_completion :: proc(ast_context: ^AstContext, position_context: ^D result := result //Skip procedures when the position is in proc decl - if position_in_proc_decl(position_context) && result.type == .Function && common.config.enable_procedure_context { + if position_in_proc_decl(position_context) && + result.type == .Function && + common.config.enable_procedure_context { continue } if result.snippet.insert != "" { item := CompletionItem { - label = result.name, - insertText = result.snippet.insert, - kind = .Snippet, - detail = result.snippet.detail, + label = result.name, + insertText = result.snippet.insert, + kind = .Snippet, + detail = result.snippet.detail, insertTextFormat = .Snippet, } edits := make([dynamic]TextEdit, context.temp_allocator) for pkg in result.snippet.packages { - edit, ok := get_core_insert_package_if_non_existent(ast_context, pkg) + edit, ok := get_core_insert_package_if_non_existent( + ast_context, + pkg, + ) if ok { append(&edits, edit) } @@ -1036,7 +1286,7 @@ get_identifier_completion :: proc(ast_context: ^AstContext, position_context: ^D append(&items, item) } else { item := CompletionItem { - label = result.name, + label = result.name, documentation = result.doc, } @@ -1045,11 +1295,18 @@ get_identifier_completion :: proc(ast_context: ^AstContext, position_context: ^D if result.type == .Function && common.config.enable_snippets { item.insertText = fmt.tprintf("%v($0)", item.label) item.insertTextFormat = .Snippet - item.deprecated = .Deprecated in result.flags + item.deprecated = .Deprecated in result.flags item.command.command = "editor.action.triggerParameterHints" } - - item.detail = concatenate_symbol_information(ast_context, result.pkg, result.name, result.signature, result.type, true) + + item.detail = concatenate_symbol_information( + ast_context, + result.pkg, + result.name, + result.signature, + result.type, + true, + ) append(&items, item) } @@ -1058,7 +1315,11 @@ get_identifier_completion :: proc(ast_context: ^AstContext, position_context: ^D list.items = items[:] } -get_package_completion :: proc(ast_context: ^AstContext, position_context: ^DocumentPositionContext, list: ^CompletionList) { +get_package_completion :: proc( + ast_context: ^AstContext, + position_context: ^DocumentPositionContext, + list: ^CompletionList, +) { items := make([dynamic]CompletionItem, context.temp_allocator) list.isIncomplete = false @@ -1069,30 +1330,47 @@ get_package_completion :: proc(ast_context: ^AstContext, position_context: ^Docu return } - without_quotes := position_context.import_stmt.fullpath[1:fullpath_length-1] + without_quotes := position_context.import_stmt.fullpath[1:fullpath_length - + 1] absolute_path := without_quotes colon_index := strings.index(without_quotes, ":") if colon_index >= 0 { c := without_quotes[0:colon_index] - if colon_index+1 < len(without_quotes) { - absolute_path = filepath.join(elems = {common.config.collections[c], filepath.dir(without_quotes[colon_index+1:], context.temp_allocator)}, allocator = context.temp_allocator) + if colon_index + 1 < len(without_quotes) { + absolute_path = filepath.join( + elems = { + common.config.collections[c], + filepath.dir( + without_quotes[colon_index + 1:], + context.temp_allocator, + ), + }, + allocator = context.temp_allocator, + ) } else { absolute_path = common.config.collections[c] } } else { - import_file_dir := filepath.dir(position_context.import_stmt.pos.file, context.temp_allocator) + import_file_dir := filepath.dir( + position_context.import_stmt.pos.file, + context.temp_allocator, + ) import_dir := filepath.dir(without_quotes, context.temp_allocator) - absolute_path = filepath.join(elems = {import_file_dir, import_dir}, allocator = context.temp_allocator) + absolute_path = filepath.join( + elems = {import_file_dir, import_dir}, + allocator = context.temp_allocator, + ) } - if !strings.contains(position_context.import_stmt.fullpath, "/") && !strings.contains(position_context.import_stmt.fullpath, ":") { + if !strings.contains(position_context.import_stmt.fullpath, "/") && + !strings.contains(position_context.import_stmt.fullpath, ":") { for key, _ in common.config.collections { item := CompletionItem { detail = "collection", - label = key, - kind = .Module, + label = key, + kind = .Module, } append(&items, item) @@ -1102,8 +1380,8 @@ get_package_completion :: proc(ast_context: ^AstContext, position_context: ^Docu for pkg in search_for_packages(absolute_path) { item := CompletionItem { detail = pkg, - label = filepath.base(pkg), - kind = .Folder, + label = filepath.base(pkg), + kind = .Folder, } if item.label[0] == '.' { @@ -1116,7 +1394,7 @@ get_package_completion :: proc(ast_context: ^AstContext, position_context: ^Docu list.items = items[:] } -search_for_packages :: proc(fullpath: string) -> [] string { +search_for_packages :: proc(fullpath: string) -> []string { packages := make([dynamic]string, context.temp_allocator) fh, err := os.open(fullpath) @@ -1137,13 +1415,18 @@ search_for_packages :: proc(fullpath: string) -> [] string { return packages[:] } -get_type_switch_completion :: proc(ast_context: ^AstContext, position_context: ^DocumentPositionContext, list: ^CompletionList) { +get_type_switch_completion :: proc( + ast_context: ^AstContext, + position_context: ^DocumentPositionContext, + list: ^CompletionList, +) { items := make([dynamic]CompletionItem, context.temp_allocator) list.isIncomplete = false used_unions := make(map[string]bool, 5, context.temp_allocator) - if block, ok := position_context.switch_type_stmt.body.derived.(^ast.Block_Stmt); ok { + if block, ok := position_context.switch_type_stmt.body.derived.(^ast.Block_Stmt); + ok { for stmt in block.stmts { if case_clause, ok := stmt.derived.(^ast.Case_Clause); ok { for name in case_clause.list { @@ -1155,26 +1438,51 @@ get_type_switch_completion :: proc(ast_context: ^AstContext, position_context: ^ } } - ast_context.use_locals = true + ast_context.use_locals = true ast_context.use_globals = true - if assign, ok := position_context.switch_type_stmt.tag.derived.(^ast.Assign_Stmt); ok && assign.rhs != nil && len(assign.rhs) == 1 { + if assign, ok := position_context.switch_type_stmt.tag.derived.(^ast.Assign_Stmt); + ok && assign.rhs != nil && len(assign.rhs) == 1 { if union_value, ok := unwrap_union(ast_context, assign.rhs[0]); ok { for type, i in union_value.types { - if symbol, ok := resolve_type_expression(ast_context, union_value.types[i]); ok { + if symbol, ok := resolve_type_expression( + ast_context, + union_value.types[i], + ); ok { name := symbol.name if name in used_unions { continue } - + item := CompletionItem { kind = .EnumMember, } - + if symbol.pkg == ast_context.document_package { - item.label = fmt.aprintf("%v%v", common.repeat("^", symbol.pointers, context.temp_allocator), name) + item.label = fmt.aprintf( + "%v%v", + common.repeat( + "^", + symbol.pointers, + context.temp_allocator, + ), + name, + ) } else { - item.label = fmt.aprintf("%v%v.%v", common.repeat("^", symbol.pointers, context.temp_allocator), path.base(symbol.pkg, false, context.temp_allocator), name) + item.label = fmt.aprintf( + "%v%v.%v", + common.repeat( + "^", + symbol.pointers, + context.temp_allocator, + ), + path.base( + symbol.pkg, + false, + context.temp_allocator, + ), + name, + ) } append(&items, item) @@ -1186,7 +1494,13 @@ get_type_switch_completion :: proc(ast_context: ^AstContext, position_context: ^ list.items = items[:] } -get_core_insert_package_if_non_existent :: proc(ast_context: ^AstContext, pkg: string) -> (TextEdit, bool) { +get_core_insert_package_if_non_existent :: proc( + ast_context: ^AstContext, + pkg: string, +) -> ( + TextEdit, + bool, +) { builder := strings.builder_make(context.temp_allocator) for imp in ast_context.imports { @@ -1212,9 +1526,17 @@ get_core_insert_package_if_non_existent :: proc(ast_context: ^AstContext, pkg: s }, true } -get_range_from_selection_start_to_dot :: proc(position_context: ^DocumentPositionContext) -> (common.Range, bool) { +get_range_from_selection_start_to_dot :: proc( + position_context: ^DocumentPositionContext, +) -> ( + common.Range, + bool, +) { if position_context.selector != nil { - range := common.get_token_range(position_context.selector, position_context.file.src) + range := common.get_token_range( + position_context.selector, + position_context.file.src, + ) range.end.character += 1 return range, true } @@ -1222,20 +1544,24 @@ get_range_from_selection_start_to_dot :: proc(position_context: ^DocumentPositio return {}, false } -append_magic_map_completion :: proc(position_context: ^DocumentPositionContext, symbol: Symbol, items: ^[dynamic]CompletionItem) { +append_magic_map_completion :: proc( + position_context: ^DocumentPositionContext, + symbol: Symbol, + items: ^[dynamic]CompletionItem, +) { range, ok := get_range_from_selection_start_to_dot(position_context) if !ok { - return + return } remove_range := common.Range { start = range.start, - end = range.end, + end = range.end, } remove_edit := TextEdit { - range = remove_range, + range = remove_range, newText = "", } @@ -1249,37 +1575,41 @@ append_magic_map_completion :: proc(position_context: ^DocumentPositionContext, kind = .Snippet, detail = "for", additionalTextEdits = additionalTextEdits, - textEdit = TextEdit { - newText = fmt.tprintf("for ${{1:k}}, ${{2:v}} in %v {{\n\t$0 \n}}", symbol.name), - range = { - start = range.end, - end = range.end, - }, + textEdit = TextEdit{ + newText = fmt.tprintf( + "for ${{1:k}}, ${{2:v}} in %v {{\n\t$0 \n}}", + symbol.name, + ), + range = {start = range.end, end = range.end}, }, insertTextFormat = .Snippet, InsertTextMode = .adjustIndentation, } - + append(items, item) } } -append_magic_dynamic_array_completion :: proc(position_context: ^DocumentPositionContext, symbol: Symbol, items: ^[dynamic]CompletionItem) { +append_magic_dynamic_array_completion :: proc( + position_context: ^DocumentPositionContext, + symbol: Symbol, + items: ^[dynamic]CompletionItem, +) { range, ok := get_range_from_selection_start_to_dot(position_context) if !ok { - return + return } remove_range := common.Range { start = range.start, - end = range.end, + end = range.end, } remove_edit := TextEdit { - range = remove_range, + range = remove_range, newText = "", } @@ -1294,12 +1624,9 @@ append_magic_dynamic_array_completion :: proc(position_context: ^DocumentPositio label = "len", kind = .Function, detail = "len", - textEdit = TextEdit { + textEdit = TextEdit{ newText = text, - range = { - start = range.end, - end = range.end, - }, + range = {start = range.end, end = range.end}, }, additionalTextEdits = additionalTextEdits, } @@ -1314,42 +1641,46 @@ append_magic_dynamic_array_completion :: proc(position_context: ^DocumentPositio kind = .Snippet, detail = "for", additionalTextEdits = additionalTextEdits, - textEdit = TextEdit { - newText = fmt.tprintf("for i in %v {{\n\t$0 \n}}", symbol.name), - range = { - start = range.end, - end = range.end, - }, + textEdit = TextEdit{ + newText = fmt.tprintf( + "for i in %v {{\n\t$0 \n}}", + symbol.name, + ), + range = {start = range.end, end = range.end}, }, insertTextFormat = .Snippet, InsertTextMode = .adjustIndentation, } - + append(items, item) } - + } -append_magic_union_completion :: proc(position_context: ^DocumentPositionContext, symbol: Symbol, items: ^[dynamic]CompletionItem) { +append_magic_union_completion :: proc( + position_context: ^DocumentPositionContext, + symbol: Symbol, + items: ^[dynamic]CompletionItem, +) { range, ok := get_range_from_selection_start_to_dot(position_context) if !ok { - return + return } remove_range := common.Range { start = range.start, - end = range.end, + end = range.end, } remove_edit := TextEdit { - range = remove_range, + range = remove_range, newText = "", } additionalTextEdits := make([]TextEdit, 1, context.temp_allocator) additionalTextEdits[0] = remove_edit - + //switch { item := CompletionItem { @@ -1357,28 +1688,28 @@ append_magic_union_completion :: proc(position_context: ^DocumentPositionContext kind = .Snippet, detail = "switch", additionalTextEdits = additionalTextEdits, - textEdit = TextEdit { - newText = fmt.tprintf("switch v in %v {{\n\t$0 \n}}", symbol.name), - range = { - start = range.end, - end = range.end, - }, + textEdit = TextEdit{ + newText = fmt.tprintf( + "switch v in %v {{\n\t$0 \n}}", + symbol.name, + ), + range = {start = range.end, end = range.end}, }, insertTextFormat = .Snippet, InsertTextMode = .adjustIndentation, } - + append(items, item) } } bitset_operators: map[string]bool = { - "|" = true, - "&" = true, - "~" = true, - "<" = true, - ">" = true, + "|" = true, + "&" = true, + "~" = true, + "<" = true, + ">" = true, "==" = true, } @@ -1388,7 +1719,7 @@ bitset_assignment_operators: map[string]bool = { "~=" = true, "<=" = true, ">=" = true, - "=" = true, + "=" = true, "+=" = true, } @@ -1445,9 +1776,9 @@ language_keywords: []string = { } swizzle_color_components: map[u8]bool = { - 'r' = true, - 'g' = true, - 'b' = true, + 'r' = true, + 'g' = true, + 'b' = true, 'a' = true, } @@ -1456,4 +1787,4 @@ swizzle_coord_components: map[u8]bool = { 'y' = true, 'z' = true, 'w' = true, -}; +} diff --git a/src/server/definition.odin b/src/server/definition.odin index ad9e7a8..309cde1 100644 --- a/src/server/definition.odin +++ b/src/server/definition.odin @@ -16,16 +16,32 @@ import "core:os" import "shared:common" -get_definition_location :: proc(document: ^Document, position: common.Position) -> ([]common.Location, bool) { +get_definition_location :: proc( + document: ^Document, + position: common.Position, +) -> ( + []common.Location, + bool, +) { locations := make([dynamic]common.Location, context.temp_allocator) location: common.Location - ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri, document.fullpath) + ast_context := make_ast_context( + document.ast, + document.imports, + document.package_name, + document.uri.uri, + document.fullpath, + ) uri: string - position_context, ok := get_document_position_context(document, position, .Definition) + position_context, ok := get_document_position_context( + document, + position, + .Definition, + ) if !ok { log.warn("Failed to get position context") @@ -35,16 +51,25 @@ get_definition_location :: proc(document: ^Document, position: common.Position) get_globals(document.ast, &ast_context) if position_context.function != nil { - get_locals(document.ast, position_context.function, &ast_context, &position_context) + get_locals( + document.ast, + position_context.function, + &ast_context, + &position_context, + ) } if position_context.selector_expr != nil { //if the base selector is the client wants to go to. - if base, ok := position_context.selector.derived.(^ast.Ident); ok && position_context.identifier != nil { + if base, ok := position_context.selector.derived.(^ast.Ident); + ok && position_context.identifier != nil { ident := position_context.identifier.derived.(^ast.Ident) if position_in_node(base, position_context.position) { - if resolved, ok := resolve_location_identifier(&ast_context, ident^); ok { + if resolved, ok := resolve_location_identifier( + &ast_context, + ident^, + ); ok { location.range = resolved.range if resolved.uri == "" { @@ -62,12 +87,18 @@ get_definition_location :: proc(document: ^Document, position: common.Position) } } - if resolved, ok := resolve_location_selector(&ast_context, position_context.selector_expr); ok { + if resolved, ok := resolve_location_selector( + &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 { + if resolved, ok := resolve_location_identifier( + &ast_context, + position_context.identifier.derived.(^ast.Ident)^, + ); ok { location.range = resolved.range uri = resolved.uri } else { @@ -87,4 +118,4 @@ get_definition_location :: proc(document: ^Document, position: common.Position) append(&locations, location) return locations[:], true -}
\ No newline at end of file +} diff --git a/src/server/document_links.odin b/src/server/document_links.odin index 0049509..17113ff 100644 --- a/src/server/document_links.odin +++ b/src/server/document_links.odin @@ -25,7 +25,11 @@ get_document_links :: proc(document: ^Document) -> ([]DocumentLink, bool) { continue } - e := strings.split(imp.relpath.text[1:len(imp.relpath.text)-1], ":", context.temp_allocator) + e := strings.split( + imp.relpath.text[1:len(imp.relpath.text) - 1], + ":", + context.temp_allocator, + ) if len(e) != 2 { continue @@ -43,7 +47,7 @@ get_document_links :: proc(document: ^Document) -> ([]DocumentLink, bool) { line = imp.relpath.pos.line, }, end = { - offset = imp.relpath.pos.offset + len(imp.relpath.text) - 1, + offset = imp.relpath.pos.offset + len(imp.relpath.text) - 1, column = imp.relpath.pos.column + len(imp.relpath.text) - 1, line = imp.relpath.pos.line, }, @@ -52,8 +56,12 @@ get_document_links :: proc(document: ^Document) -> ([]DocumentLink, bool) { range := common.get_token_range(node, string(document.text)) link := DocumentLink { - range = range, - target = fmt.tprintf("https://pkg.odin-lang.org/%v/%v", e[0], e[1]), + range = range, + target = fmt.tprintf( + "https://pkg.odin-lang.org/%v/%v", + e[0], + e[1], + ), tooltip = "Documentation", } diff --git a/src/server/document_symbols.odin b/src/server/document_symbols.odin index 274c37f..bed5734 100644 --- a/src/server/document_symbols.odin +++ b/src/server/document_symbols.odin @@ -18,7 +18,13 @@ import "core:os" import "shared:common" get_document_symbols :: proc(document: ^Document) -> []DocumentSymbol { - ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri, document.fullpath) + ast_context := make_ast_context( + document.ast, + document.imports, + document.package_name, + document.uri.uri, + document.fullpath, + ) get_globals(document.ast, &ast_context) @@ -31,11 +37,13 @@ get_document_symbols :: proc(document: ^Document) -> []DocumentSymbol { } package_symbol.kind = .Package - package_symbol.name = path.base(document.package_name, false, context.temp_allocator) + package_symbol.name = path.base( + document.package_name, + false, + context.temp_allocator, + ) package_symbol.range = { - start = { - line = document.ast.decls[0].pos.line, - }, + start = {line = document.ast.decls[0].pos.line}, end = { line = document.ast.decls[len(document.ast.decls) - 1].end.line, }, @@ -47,7 +55,10 @@ get_document_symbols :: proc(document: ^Document) -> []DocumentSymbol { for k, global in ast_context.globals { symbol: DocumentSymbol - symbol.range = common.get_token_range(global.expr, ast_context.file.src) + symbol.range = common.get_token_range( + global.expr, + ast_context.file.src, + ) symbol.selectionRange = symbol.range symbol.name = k diff --git a/src/server/documents.odin b/src/server/documents.odin index 52309ed..5adfdfb 100644 --- a/src/server/documents.odin +++ b/src/server/documents.odin @@ -72,7 +72,7 @@ document_get_allocator :: proc() -> ^common.Scratch_Allocator { return pop(&document_storage.free_allocators) } else { allocator := new(common.Scratch_Allocator) - common.scratch_allocator_init(allocator, mem.Megabyte*3) + common.scratch_allocator_init(allocator, mem.Megabyte * 3) return allocator } } @@ -111,7 +111,12 @@ document_release :: proc(document: ^Document) { Client opens a document with transferred text */ -document_open :: proc(uri_string: string, text: string, config: ^common.Config, writer: ^Writer) -> common.Error { +document_open :: proc( + uri_string: string, + text: string, + config: ^common.Config, + writer: ^Writer, +) -> common.Error { uri, parsed_ok := common.parse_uri(uri_string, context.allocator) if !parsed_ok { @@ -121,7 +126,10 @@ document_open :: proc(uri_string: string, text: string, config: ^common.Config, if document := &document_storage.documents[uri.path]; document != nil { if document.client_owned { - log.errorf("Client called open on an already open document: %v ", document.uri.path) + log.errorf( + "Client called open on an already open document: %v ", + document.uri.path, + ) return .InvalidRequest } @@ -138,11 +146,11 @@ document_open :: proc(uri_string: string, text: string, config: ^common.Config, } } else { document := Document { - uri = uri, - text = transmute([]u8)text, + uri = uri, + text = transmute([]u8)text, client_owned = true, - used_text = len(text), - allocator = document_get_allocator(), + used_text = len(text), + allocator = document_get_allocator(), } document_setup(&document) @@ -160,37 +168,46 @@ document_open :: proc(uri_string: string, text: string, config: ^common.Config, } document_setup :: proc(document: ^Document) { - //Right now not all clients return the case correct windows path, and that causes issues with indexing, so we ensure that it's case correct. - when ODIN_OS == .Windows { - package_name := path.dir(document.uri.path, context.temp_allocator) - forward, _ := filepath.to_slash(common.get_case_sensitive_path(package_name), context.temp_allocator) - if forward == "" { - document.package_name = package_name - } else { - document.package_name = strings.clone(forward) - } + //Right now not all clients return the case correct windows path, and that causes issues with indexing, so we ensure that it's case correct. + when ODIN_OS == .Windows { + package_name := path.dir(document.uri.path, context.temp_allocator) + forward, _ := filepath.to_slash( + common.get_case_sensitive_path(package_name), + context.temp_allocator, + ) + if forward == "" { + document.package_name = package_name } else { - document.package_name = path.dir(document.uri.path) + document.package_name = strings.clone(forward) } + } else { + document.package_name = path.dir(document.uri.path) + } - when ODIN_OS == .Windows { - correct := common.get_case_sensitive_path(document.uri.path) - fullpath: string - if correct == "" { - //This is basically here to handle the tests where the physical file doesn't actual exist. - document.fullpath, _ = filepath.to_slash(document.uri.path) - } else { - document.fullpath, _ = filepath.to_slash(correct) - } + when ODIN_OS == .Windows { + correct := common.get_case_sensitive_path(document.uri.path) + fullpath: string + if correct == "" { + //This is basically here to handle the tests where the physical file doesn't actual exist. + document.fullpath, _ = filepath.to_slash(document.uri.path) } else { - document.fullpath = document.uri.path + document.fullpath, _ = filepath.to_slash(correct) } + } else { + document.fullpath = document.uri.path + } } /* Function that applies changes to the given document through incremental syncronization */ -document_apply_changes :: proc(uri_string: string, changes: [dynamic]TextDocumentContentChangeEvent, version: Maybe(int), config: ^common.Config, writer: ^Writer) -> common.Error { +document_apply_changes :: proc( + uri_string: string, + changes: [dynamic]TextDocumentContentChangeEvent, + version: Maybe(int), + config: ^common.Config, + writer: ^Writer, +) -> common.Error { uri, parsed_ok := common.parse_uri(uri_string, context.temp_allocator) if !parsed_ok { @@ -202,14 +219,20 @@ document_apply_changes :: proc(uri_string: string, changes: [dynamic]TextDocumen document.version = version if !document.client_owned { - log.errorf("Client called change on an document not opened: %v ", document.uri.path) + log.errorf( + "Client called change on an document not opened: %v ", + document.uri.path, + ) return .InvalidRequest } for change in changes { //for some reason sublime doesn't seem to care even if i tell it to do incremental sync if range, ok := change.range.(common.Range); ok { - absolute_range, ok := common.get_absolute_range(range, document.text[:document.used_text]) + absolute_range, ok := common.get_absolute_range( + range, + document.text[:document.used_text], + ) if !ok { return .ParseError @@ -276,7 +299,10 @@ document_close :: proc(uri_string: string) -> common.Error { document := &document_storage.documents[uri.path] if document == nil || !document.client_owned { - log.errorf("Client called close on a document that was never opened: %v ", document.uri.path) + log.errorf( + "Client called close on a document that was never opened: %v ", + document.uri.path, + ) return .InvalidRequest } @@ -294,7 +320,11 @@ document_close :: proc(uri_string: string) -> common.Error { return .None } -document_refresh :: proc(document: ^Document, config: ^common.Config, writer: ^Writer) -> common.Error { +document_refresh :: proc( + document: ^Document, + config: ^common.Config, + writer: ^Writer, +) -> common.Error { errors, ok := parse_document(document, config) if !ok { @@ -305,32 +335,33 @@ document_refresh :: proc(document: ^Document, config: ^common.Config, writer: ^W document.diagnosed_errors = true params := NotificationPublishDiagnosticsParams { - uri = document.uri.uri, - diagnostics = make([]Diagnostic, len(errors), context.temp_allocator), + uri = document.uri.uri, + diagnostics = make( + []Diagnostic, + len(errors), + context.temp_allocator, + ), } for error, i in errors { params.diagnostics[i] = Diagnostic { - range = common.Range { - start = common.Position { + range = common.Range{ + start = common.Position{ line = error.line - 1, character = 0, }, - end = common.Position { - line = error.line, - character = 0, - }, + end = common.Position{line = error.line, character = 0}, }, severity = DiagnosticSeverity.Error, code = "Syntax", message = error.message, } } - + notifaction := Notification { jsonrpc = "2.0", - method = "textDocument/publishDiagnostics", - params = params, + method = "textDocument/publishDiagnostics", + params = params, } send_notification(notifaction, writer) @@ -343,9 +374,13 @@ document_refresh :: proc(document: ^Document, config: ^common.Config, writer: ^W notifaction := Notification { jsonrpc = "2.0", method = "textDocument/publishDiagnostics", - params = NotificationPublishDiagnosticsParams { + params = NotificationPublishDiagnosticsParams{ uri = document.uri.uri, - diagnostics = make([]Diagnostic, len(errors), context.temp_allocator), + diagnostics = make( + []Diagnostic, + len(errors), + context.temp_allocator, + ), }, } @@ -362,13 +397,22 @@ current_errors: [dynamic]ParserError parser_error_handler :: proc(pos: tokenizer.Pos, msg: string, args: ..any) { error := ParserError { - line = pos.line,column = pos.column,file = pos.file, - offset = pos.offset,message = fmt.tprintf(msg, ..args), + line = pos.line, + column = pos.column, + file = pos.file, + offset = pos.offset, + message = fmt.tprintf(msg, ..args), } append(¤t_errors, error) } -parse_document :: proc(document: ^Document, config: ^common.Config) -> ([]ParserError, bool) { +parse_document :: proc( + document: ^Document, + config: ^common.Config, +) -> ( + []ParserError, + bool, +) { p := parser.Parser { err = parser_error_handler, warn = common.parser_warning_handler, @@ -391,8 +435,8 @@ parse_document :: proc(document: ^Document, config: ^common.Config) -> ([]Parser document.ast = ast.File { fullpath = document.fullpath, - src = string(document.text[:document.used_text]), - pkg = pkg, + src = string(document.text[:document.used_text]), + pkg = pkg, } parser.parse_file(&p, &document.ast) @@ -404,14 +448,15 @@ parse_document :: proc(document: ^Document, config: ^common.Config) -> ([]Parser parse_imports :: proc(document: ^Document, config: ^common.Config) { imports := make([dynamic]Package) - + for imp, index in document.ast.imports { if i := strings.index(imp.fullpath, "\""); i == -1 { continue } //collection specified - if i := strings.index(imp.fullpath, ":"); i != -1 && i > 1 && i < len(imp.fullpath) - 1 { + if i := strings.index(imp.fullpath, ":"); + i != -1 && i > 1 && i < len(imp.fullpath) - 1 { if len(imp.fullpath) < 2 { continue } @@ -426,14 +471,19 @@ parse_imports :: proc(document: ^Document, config: ^common.Config) { } import_: Package - import_.name = strings.clone(path.join(elems = {dir, p}, allocator = context.temp_allocator)) + import_.name = strings.clone( + path.join( + elems = {dir, p}, + allocator = context.temp_allocator, + ), + ) if imp.name.text != "" { import_.base = imp.name.text } else { import_.base = path.base(import_.name, false) } - + append(&imports, import_) } else { //relative @@ -442,7 +492,13 @@ parse_imports :: proc(document: ^Document, config: ^common.Config) { } import_: Package - import_.name = path.join(elems = {document.package_name, imp.fullpath[1:len(imp.fullpath) - 1]}, allocator = context.temp_allocator) + import_.name = path.join( + elems = { + document.package_name, + imp.fullpath[1:len(imp.fullpath) - 1], + }, + allocator = context.temp_allocator, + ) import_.name = path.clean(import_.name) if imp.name.text != "" { diff --git a/src/server/format.odin b/src/server/format.odin index 236bee2..cbb4082 100644 --- a/src/server/format.odin +++ b/src/server/format.odin @@ -20,7 +20,13 @@ DocumentFormattingParams :: struct { options: FormattingOptions, } -get_complete_format :: proc(document: ^Document, config: ^common.Config) -> ([]TextEdit, bool) { +get_complete_format :: proc( + document: ^Document, + config: ^common.Config, +) -> ( + []TextEdit, + bool, +) { if document.ast.syntax_error_count > 0 { return {}, true } @@ -29,7 +35,9 @@ get_complete_format :: proc(document: ^Document, config: ^common.Config) -> ([]T return {}, true } - style := format.find_config_file_or_default(filepath.dir(document.fullpath, context.temp_allocator)) + style := format.find_config_file_or_default( + filepath.dir(document.fullpath, context.temp_allocator), + ) prnt := printer.make_printer(style, context.temp_allocator) src := printer.print(&prnt, &document.ast) @@ -42,7 +50,9 @@ get_complete_format :: proc(document: ^Document, config: ^common.Config) -> ([]T last := document.text[0] line := 0 - for current_index := 0; current_index < len(document.text); current_index += 1 { + for current_index := 0; + current_index < len(document.text); + current_index += 1 { current := document.text[current_index] if last == '\r' && current == '\n' { @@ -58,14 +68,8 @@ get_complete_format :: proc(document: ^Document, config: ^common.Config) -> ([]T edit := TextEdit { newText = src, range = { - start = { - character = 0, - line = 0, - }, - end = { - character = 1, - line = line+1, - }, + start = {character = 0, line = 0}, + end = {character = 1, line = line + 1}, }, } diff --git a/src/server/hover.odin b/src/server/hover.odin index 0e00fa0..580038f 100644 --- a/src/server/hover.odin +++ b/src/server/hover.odin @@ -15,17 +15,24 @@ import "core:slice" import "shared:common" -write_hover_content :: proc(ast_context: ^AstContext, symbol: Symbol) -> MarkupContent { +write_hover_content :: proc( + ast_context: ^AstContext, + symbol: Symbol, +) -> MarkupContent { content: MarkupContent symbol := symbol if untyped, ok := symbol.value.(SymbolUntypedValue); ok { switch untyped.type { - case .String: symbol.signature = "string" - case .Bool: symbol.signature = "bool" - case .Float: symbol.signature = "float" - case .Integer: symbol.signature = "int" + case .String: + symbol.signature = "string" + case .Bool: + symbol.signature = "bool" + case .Float: + symbol.signature = "float" + case .Integer: + symbol.signature = "int" } } @@ -44,80 +51,133 @@ write_hover_content :: proc(ast_context: ^AstContext, symbol: Symbol) -> MarkupC } builtin_identifier_hover: map[string]string = { - "context" = fmt.aprintf("```odin\n%v\n```\n%v", "runtime.context: Context", "This context variable is local to each scope and is implicitly passed by pointer to any procedure call in that scope (if the procedure has the Odin calling convention)."), + "context" = fmt.aprintf( + "```odin\n%v\n```\n%v", + "runtime.context: Context", + "This context variable is local to each scope and is implicitly passed by pointer to any procedure call in that scope (if the procedure has the Odin calling convention).", + ), } -get_hover_information :: proc(document: ^Document, position: common.Position) -> (Hover, bool, bool) { +get_hover_information :: proc( + document: ^Document, + position: common.Position, +) -> ( + Hover, + bool, + bool, +) { hover := Hover { - contents = { - kind = "plaintext", - }, + contents = {kind = "plaintext"}, } - ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri, document.fullpath) + ast_context := make_ast_context( + document.ast, + document.imports, + document.package_name, + document.uri.uri, + document.fullpath, + ) - position_context, ok := get_document_position_context(document, position, .Hover) + position_context, ok := get_document_position_context( + document, + position, + .Hover, + ) get_globals(document.ast, &ast_context) if position_context.function != nil { - get_locals(document.ast, position_context.function, &ast_context, &position_context) + get_locals( + document.ast, + position_context.function, + &ast_context, + &position_context, + ) } if position_context.identifier != nil { if ident, ok := position_context.identifier.derived.(^ast.Ident); ok { if _, ok := common.keyword_map[ident.name]; ok { hover.contents.kind = "plaintext" - hover.range = common.get_token_range(position_context.identifier^, ast_context.file.src) + hover.range = common.get_token_range( + position_context.identifier^, + ast_context.file.src, + ) return hover, true, true } if str, ok := builtin_identifier_hover[ident.name]; ok { hover.contents.kind = "markdown" hover.contents.value = str - hover.range = common.get_token_range(position_context.identifier^, ast_context.file.src) + hover.range = common.get_token_range( + position_context.identifier^, + ast_context.file.src, + ) return hover, true, true } - } + } } if position_context.implicit_context != nil { - if str, ok := builtin_identifier_hover[position_context.implicit_context.tok.text]; ok { + if str, ok := + builtin_identifier_hover[ + position_context.implicit_context.tok.text \ + ]; ok { hover.contents.kind = "markdown" hover.contents.value = str - hover.range = common.get_token_range(position_context.implicit_context^, ast_context.file.src) + hover.range = common.get_token_range( + position_context.implicit_context^, + ast_context.file.src, + ) return hover, true, true } } if position_context.selector != nil && position_context.identifier != nil { - hover.range = common.get_token_range(position_context.identifier^, ast_context.file.src) + hover.range = common.get_token_range( + position_context.identifier^, + ast_context.file.src, + ) ast_context.use_locals = true ast_context.use_globals = true ast_context.current_package = ast_context.document_package //if the base selector is the client wants to go to. - if base, ok := position_context.selector.derived.(^ast.Ident); ok && position_context.identifier != nil { + if base, ok := position_context.selector.derived.(^ast.Ident); + ok && position_context.identifier != nil { ident := position_context.identifier.derived.(^ast.Ident)^ if position_in_node(base, position_context.position) { - if resolved, ok := resolve_type_identifier(&ast_context, ident); ok { - resolved.signature = get_signature(&ast_context, ident, resolved) + if resolved, ok := resolve_type_identifier( + &ast_context, + ident, + ); ok { + resolved.signature = get_signature( + &ast_context, + ident, + resolved, + ) resolved.name = ident.name if resolved.type == .Variable { resolved.pkg = ast_context.document_package } - hover.contents = write_hover_content(&ast_context, resolved) + hover.contents = write_hover_content( + &ast_context, + resolved, + ) return hover, true, true } } } selector: Symbol - selector, ok = resolve_type_expression(&ast_context, position_context.selector) + selector, ok = resolve_type_expression( + &ast_context, + position_context.selector, + ) if !ok { return hover, false, true @@ -138,20 +198,33 @@ get_hover_information :: proc(document: ^Document, position: common.Position) -> case SymbolStructValue: for name, i in v.names { if name == field { - if symbol, ok := resolve_type_expression(&ast_context, v.types[i]); ok { + if symbol, ok := resolve_type_expression( + &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]) - hover.contents = write_hover_content(&ast_context, symbol) + hover.contents = write_hover_content( + &ast_context, + symbol, + ) return hover, true, true } } } case SymbolPackageValue: if position_context.field != nil { - if ident, ok := position_context.field.derived.(^ast.Ident); ok { - if symbol, ok := resolve_type_identifier(&ast_context, ident^); ok { - hover.contents = write_hover_content(&ast_context, symbol) + if ident, ok := position_context.field.derived.(^ast.Ident); + ok { + if symbol, ok := resolve_type_identifier( + &ast_context, + ident^, + ); ok { + hover.contents = write_hover_content( + &ast_context, + symbol, + ) return hover, true, true } } @@ -164,9 +237,12 @@ get_hover_information :: proc(document: ^Document, position: common.Position) -> ident := position_context.identifier.derived.(^ast.Ident)^ - hover.range = common.get_token_range(position_context.identifier^, document.ast.src) + hover.range = common.get_token_range( + position_context.identifier^, + document.ast.src, + ) - if resolved, ok := resolve_type_identifier(&ast_context, ident); ok { + if resolved, ok := resolve_type_identifier(&ast_context, ident); ok { resolved.signature = get_signature(&ast_context, ident, resolved) resolved.name = ident.name diff --git a/src/server/indexer.odin b/src/server/indexer.odin index 581bd37..7b7d071 100644 --- a/src/server/indexer.odin +++ b/src/server/indexer.odin @@ -9,7 +9,7 @@ import "core:slice" Indexer :: struct { builtin_packages: [dynamic]string, - index: MemoryIndex, + index: MemoryIndex, } indexer: Indexer @@ -19,7 +19,14 @@ FuzzyResult :: struct { score: f32, } -lookup :: proc(name: string, pkg: string, loc := #caller_location) -> (Symbol, bool) { +lookup :: proc( + name: string, + pkg: string, + loc := #caller_location, +) -> ( + Symbol, + bool, +) { if symbol, ok := memory_index_lookup(&indexer.index, name, pkg); ok { return symbol, true } diff --git a/src/server/inlay_hints.odin b/src/server/inlay_hints.odin index fb989db..59f3c86 100644 --- a/src/server/inlay_hints.odin +++ b/src/server/inlay_hints.odin @@ -1,14 +1,26 @@ -package server +package server import "core:odin/ast" import "core:fmt" import "shared:common" -get_inlay_hints :: proc(document: ^Document, symbols: map[uintptr]SymbolAndNode) -> ([]InlayHint, bool) { +get_inlay_hints :: proc( + document: ^Document, + symbols: map[uintptr]SymbolAndNode, +) -> ( + []InlayHint, + bool, +) { hints := make([dynamic]InlayHint, context.temp_allocator) - ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri, document.fullpath) + ast_context := make_ast_context( + document.ast, + document.imports, + document.package_name, + document.uri.uri, + document.fullpath, + ) Visit_Data :: struct { calls: [dynamic]^ast.Node, @@ -33,7 +45,7 @@ get_inlay_hints :: proc(document: ^Document, symbols: map[uintptr]SymbolAndNode) } visitor := ast.Visitor { - data = &data, + data = &data, visit = visit, } @@ -53,7 +65,8 @@ get_inlay_hints :: proc(document: ^Document, symbols: map[uintptr]SymbolAndNode) } if symbol_and_node, ok := symbols[cast(uintptr)node_call]; ok { - if symbol_call, ok := symbol_and_node.symbol.value.(SymbolProcedureValue); ok { + if symbol_call, ok := symbol_and_node.symbol.value.(SymbolProcedureValue); + ok { for arg in symbol_call.arg_types { for name in arg.names { if symbol_arg_count >= len(call.args) { @@ -62,12 +75,15 @@ get_inlay_hints :: proc(document: ^Document, symbols: map[uintptr]SymbolAndNode) if ident, ok := name.derived.(^ast.Ident); ok { hint := InlayHint { - kind = "parameter", + kind = "parameter", label = fmt.tprintf("%v = ", ident.name), - range = common.get_token_range(call.args[symbol_arg_count], string(document.text)), + range = common.get_token_range( + call.args[symbol_arg_count], + string(document.text), + ), } append(&hints, hint) - } + } symbol_arg_count += 1 } } @@ -76,4 +92,4 @@ get_inlay_hints :: proc(document: ^Document, symbols: map[uintptr]SymbolAndNode) } return hints[:], true -}
\ No newline at end of file +} diff --git a/src/server/lens.odin b/src/server/lens.odin index 5525554..99eaea3 100644 --- a/src/server/lens.odin +++ b/src/server/lens.odin @@ -15,13 +15,25 @@ CodeLensOptions :: struct { } CodeLens :: struct { - range: common.Range, + range: common.Range, command: Command, - data: string, + data: string, } -get_code_lenses :: proc(document: ^Document, position: common.Position) -> ([]CodeLens, bool) { - ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri, document.fullpath) +get_code_lenses :: proc( + document: ^Document, + position: common.Position, +) -> ( + []CodeLens, + bool, +) { + ast_context := make_ast_context( + document.ast, + document.imports, + document.package_name, + document.uri.uri, + document.fullpath, + ) get_globals(document.ast, &ast_context) @@ -33,18 +45,16 @@ get_code_lenses :: proc(document: ^Document, position: common.Position) -> ([]Co for name, global in ast_context.globals { - + if proc_lit, ok := global.expr.derived.(^ast.Proc_Lit); ok { - } } - + return {}, false } - diff --git a/src/server/log.odin b/src/server/log.odin index c23270d..8660e88 100644 --- a/src/server/log.odin +++ b/src/server/log.odin @@ -6,29 +6,35 @@ import "core:os" import "core:time" import "core:log" -Default_Console_Logger_Opts :: log.Options { - .Level, - .Terminal_Color, - .Short_File_Path, - .Line, - .Procedure, -} | log.Full_Timestamp_Opts +Default_Console_Logger_Opts :: + log.Options{.Level, .Terminal_Color, .Short_File_Path, .Line, .Procedure} | + log.Full_Timestamp_Opts Lsp_Logger_Data :: struct { writer: ^Writer, } -create_lsp_logger :: proc(writer: ^Writer, lowest := log.Level.Debug, opt := Default_Console_Logger_Opts) -> log.Logger { +create_lsp_logger :: proc( + writer: ^Writer, + lowest := log.Level.Debug, + opt := Default_Console_Logger_Opts, +) -> log.Logger { data := new(Lsp_Logger_Data) data.writer = writer - return log.Logger {lsp_logger_proc, data, lowest, opt} + return log.Logger{lsp_logger_proc, data, lowest, opt} } destroy_lsp_logger :: proc(log: ^log.Logger) { free(log.data) } -lsp_logger_proc :: proc(logger_data: rawptr, level: log.Level, text: string, options: log.Options, location := #caller_location) { +lsp_logger_proc :: proc( + logger_data: rawptr, + level: log.Level, + text: string, + options: log.Options, + location := #caller_location, +) { data := cast(^Lsp_Logger_Data)logger_data @@ -36,16 +42,20 @@ lsp_logger_proc :: proc(logger_data: rawptr, level: log.Level, text: string, opt message_type: DiagnosticSeverity switch level { - case .Debug: message_type = DiagnosticSeverity.Hint - case .Info: message_type = DiagnosticSeverity.Information - case .Warning: message_type = DiagnosticSeverity.Warning - case .Error, .Fatal: message_type = DiagnosticSeverity.Error + case .Debug: + message_type = DiagnosticSeverity.Hint + case .Info: + message_type = DiagnosticSeverity.Information + case .Warning: + message_type = DiagnosticSeverity.Warning + case .Error, .Fatal: + message_type = DiagnosticSeverity.Error } - + notification := Notification { jsonrpc = "2.0", method = "window/logMessage", - params = NotificationLoggingParams { + params = NotificationLoggingParams{ type = message_type, message = message, }, diff --git a/src/server/memory_index.odin b/src/server/memory_index.odin index edb3dd6..3af9ea0 100644 --- a/src/server/memory_index.odin +++ b/src/server/memory_index.odin @@ -9,24 +9,29 @@ import "core:slice" import "shared:common" MemoryIndex :: struct { - collection: SymbolCollection, + collection: SymbolCollection, last_package_name: string, - last_package: ^map[string]Symbol, + last_package: ^map[string]Symbol, } make_memory_index :: proc(collection: SymbolCollection) -> MemoryIndex { - return MemoryIndex { - collection = collection, - } + return MemoryIndex{collection = collection} } -memory_index_lookup :: proc(index: ^MemoryIndex, name: string, pkg: string) -> (Symbol, bool) { +memory_index_lookup :: proc( + index: ^MemoryIndex, + name: string, + pkg: string, +) -> ( + Symbol, + bool, +) { if index.last_package_name == pkg && index.last_package != nil { return index.last_package[name] } if _pkg, ok := &index.collection.packages[pkg]; ok { - index.last_package = _pkg + index.last_package = _pkg index.last_package_name = pkg return _pkg[name] } else { @@ -37,7 +42,14 @@ memory_index_lookup :: proc(index: ^MemoryIndex, name: string, pkg: string) -> ( return {}, false } -memory_index_fuzzy_search :: proc(index: ^MemoryIndex, name: string, pkgs: []string) -> ([]FuzzyResult, bool) { +memory_index_fuzzy_search :: proc( + index: ^MemoryIndex, + name: string, + pkgs: []string, +) -> ( + []FuzzyResult, + bool, +) { symbols := make([dynamic]FuzzyResult, 0, context.temp_allocator) fuzzy_matcher := common.make_fuzzy_matcher(name) @@ -47,16 +59,17 @@ memory_index_fuzzy_search :: proc(index: ^MemoryIndex, name: string, pkgs: []str for pkg in pkgs { if pkg, ok := index.collection.packages[pkg]; ok { for _, symbol in pkg { - if score, ok := common.fuzzy_match(fuzzy_matcher, symbol.name); ok == 1 { + if score, ok := common.fuzzy_match(fuzzy_matcher, symbol.name); + ok == 1 { result := FuzzyResult { symbol = symbol, - score = score, + score = score, } - + append(&symbols, result) } } - } + } } slice.sort_by(symbols[:], proc(i, j: FuzzyResult) -> bool { @@ -69,4 +82,3 @@ memory_index_fuzzy_search :: proc(index: ^MemoryIndex, name: string, pkgs: []str return symbols[:min(top, len(symbols))], true } } - diff --git a/src/server/reader.odin b/src/server/reader.odin index e704ad8..1a32b6f 100644 --- a/src/server/reader.odin +++ b/src/server/reader.odin @@ -12,7 +12,7 @@ Reader :: struct { } make_reader :: proc(reader_fn: ReaderFn, reader_context: rawptr) -> Reader { - return Reader {reader_context = reader_context, reader_fn = reader_fn} + return Reader{reader_context = reader_context, reader_fn = reader_fn} } read_u8 :: proc(reader: ^Reader) -> (u8, bool) { @@ -27,7 +27,11 @@ read_u8 :: proc(reader: ^Reader) -> (u8, bool) { return value[0], true } -read_until_delimiter :: proc(reader: ^Reader, delimiter: u8, builder: ^strings.Builder) -> bool { +read_until_delimiter :: proc( + reader: ^Reader, + delimiter: u8, + builder: ^strings.Builder, +) -> bool { for true { value, success := read_u8(reader) diff --git a/src/server/references.odin b/src/server/references.odin index 11631b2..4b3a6d3 100644 --- a/src/server/references.odin +++ b/src/server/references.odin @@ -1,4 +1,4 @@ -package server +package server import "shared:common" @@ -16,7 +16,13 @@ import "core:runtime" fullpaths: [dynamic]string -walk_directories :: proc(info: os.File_Info, in_err: os.Errno) -> (err: os.Errno, skip_dir: bool) { +walk_directories :: proc( + info: os.File_Info, + in_err: os.Errno, +) -> ( + err: os.Errno, + skip_dir: bool, +) { if info.is_dir { return 0, false } @@ -32,7 +38,10 @@ walk_directories :: proc(info: os.File_Info, in_err: os.Errno) -> (err: os.Errno return 0, false } -position_in_struct_names :: proc(position_context: ^DocumentPositionContext, type: ^ast.Struct_Type) -> bool { +position_in_struct_names :: proc( + position_context: ^DocumentPositionContext, + type: ^ast.Struct_Type, +) -> bool { for field in type.fields.list { for name in field.names { if position_in_node(name, position_context.position) { @@ -45,7 +54,13 @@ position_in_struct_names :: proc(position_context: ^DocumentPositionContext, typ } -resolve_references :: proc(ast_context: ^AstContext, position_context: ^DocumentPositionContext) -> ([]common.Location, bool) { +resolve_references :: proc( + ast_context: ^AstContext, + position_context: ^DocumentPositionContext, +) -> ( + []common.Location, + bool, +) { locations := make([dynamic]common.Location, 0, ast_context.allocator) fullpaths = make([dynamic]string, 10, ast_context.allocator) @@ -56,14 +71,21 @@ resolve_references :: proc(ast_context: ^AstContext, position_context: ^Document pkg := "" walker_arena: mem.Arena - mem.arena_init(&walker_arena, make([]byte, mem.Megabyte*5)) - + mem.arena_init(&walker_arena, make([]byte, mem.Megabyte * 5)) + { context.temp_allocator = mem.arena_allocator(&walker_arena) - filepath.walk(filepath.dir(os.args[0], context.allocator), walk_directories) + filepath.walk( + filepath.dir(os.args[0], context.allocator), + walk_directories, + ) } - if position_context.struct_type != nil && position_in_struct_names(position_context, position_context.struct_type) { + if position_context.struct_type != nil && + position_in_struct_names( + position_context, + position_context.struct_type, + ) { return {}, true } else if position_context.enum_type != nil { return {}, true @@ -88,19 +110,22 @@ resolve_references :: proc(ast_context: ^AstContext, position_context: ^Document symbol, ok = resolve_location_identifier(ast_context, ident^) location := common.Location { - range = common.get_token_range(position_context.identifier^, string(ast_context.file.src)), - uri = strings.clone(symbol.uri, ast_context.allocator), + range = common.get_token_range( + position_context.identifier^, + string(ast_context.file.src), + ), + uri = strings.clone(symbol.uri, ast_context.allocator), } append(&locations, location) } - + if !ok { return {}, true } resolve_arena: mem.Arena - mem.arena_init(&resolve_arena, make([]byte, mem.Megabyte*25)) + mem.arena_init(&resolve_arena, make([]byte, mem.Megabyte * 25)) context.allocator = mem.arena_allocator(&resolve_arena) @@ -131,8 +156,8 @@ resolve_references :: proc(ast_context: ^AstContext, position_context: ^Document file := ast.File { fullpath = fullpath, - src = string(data), - pkg = pkg, + src = string(data), + pkg = pkg, } ok = parser.parse_file(&p, &file) @@ -148,7 +173,7 @@ resolve_references :: proc(ast_context: ^AstContext, position_context: ^Document ast = file, } - document.uri = uri + document.uri = uri document.text = transmute([]u8)file.src document.used_text = len(file.src) @@ -159,20 +184,33 @@ resolve_references :: proc(ast_context: ^AstContext, position_context: ^Document in_pkg := false for pkg in document.imports { - if pkg.name == symbol.pkg || symbol.pkg == ast_context.document_package { + if pkg.name == symbol.pkg || + symbol.pkg == ast_context.document_package { in_pkg = true } } if in_pkg { - symbols_and_nodes := resolve_entire_file(&document, reference, resolve_flag, context.allocator) + symbols_and_nodes := resolve_entire_file( + &document, + reference, + resolve_flag, + context.allocator, + ) for k, v in symbols_and_nodes { - if v.symbol.uri == symbol.uri && v.symbol.range == symbol.range { + if v.symbol.uri == symbol.uri && + v.symbol.range == symbol.range { location := common.Location { - range = common.get_token_range(v.node^, string(document.text)), - uri = strings.clone(v.symbol.uri, ast_context.allocator), - } + range = common.get_token_range( + v.node^, + string(document.text), + ), + uri = strings.clone( + v.symbol.uri, + ast_context.allocator, + ), + } append(&locations, location) } } @@ -184,25 +222,47 @@ resolve_references :: proc(ast_context: ^AstContext, position_context: ^Document return locations[:], true } -get_references :: proc(document: ^Document, position: common.Position) -> ([]common.Location, bool) { - data := make([]byte, mem.Megabyte*55, runtime.default_allocator()) +get_references :: proc( + document: ^Document, + position: common.Position, +) -> ( + []common.Location, + bool, +) { + data := make([]byte, mem.Megabyte * 55, runtime.default_allocator()) //defer delete(data) - + arena: mem.Arena mem.arena_init(&arena, data) - - context.allocator = mem.arena_allocator(&arena) - ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri, document.fullpath, context.allocator) + context.allocator = mem.arena_allocator(&arena) - position_context, ok := get_document_position_context(document, position, .Hover) + ast_context := make_ast_context( + document.ast, + document.imports, + document.package_name, + document.uri.uri, + document.fullpath, + context.allocator, + ) + + position_context, ok := get_document_position_context( + document, + position, + .Hover, + ) get_globals(document.ast, &ast_context) ast_context.current_package = ast_context.document_package if position_context.function != nil { - get_locals(document.ast, position_context.function, &ast_context, &position_context) + get_locals( + document.ast, + position_context.function, + &ast_context, + &position_context, + ) } locations, ok2 := resolve_references(&ast_context, &position_context) @@ -212,10 +272,10 @@ get_references :: proc(document: ^Document, position: common.Position) -> ([]com for location in locations { temp_location := common.Location { range = location.range, - uri = strings.clone(location.uri, context.temp_allocator), + uri = strings.clone(location.uri, context.temp_allocator), } append(&temp_locations, temp_location) } return temp_locations[:], ok2 -}
\ No newline at end of file +} diff --git a/src/server/rename.odin b/src/server/rename.odin index 45fad45..0ab27ab 100644 --- a/src/server/rename.odin +++ b/src/server/rename.odin @@ -1,11 +1,18 @@ -package server +package server import "shared:common" import "core:log" import "core:odin/ast" -get_rename :: proc(document: ^Document, new_text: string, position: common.Position) -> (WorkspaceEdit, bool) { +get_rename :: proc( + document: ^Document, + new_text: string, + position: common.Position, +) -> ( + WorkspaceEdit, + bool, +) { workspace: WorkspaceEdit document_changes := make([dynamic]TextDocumentEdit, context.temp_allocator) @@ -15,16 +22,13 @@ get_rename :: proc(document: ^Document, new_text: string, position: common.Posit document_change := TextDocumentEdit { edits = edits[:], - textDocument = { - uri = document.uri.uri, - version = document.version, - }, + textDocument = {uri = document.uri.uri, version = document.version}, } append(&document_changes, document_change) workspace.documentChanges = document_changes[:] - + return workspace, true -}
\ No newline at end of file +} diff --git a/src/server/requests.odin b/src/server/requests.odin index 29e78c1..55052e0 100644 --- a/src/server/requests.odin +++ b/src/server/requests.odin @@ -57,20 +57,18 @@ RequestInfo :: struct { } -make_response_message :: proc (id: RequestId, params: ResponseParams) -> ResponseMessage { - return ResponseMessage { - jsonrpc = "2.0", - id = id, - result = params, - } +make_response_message :: proc( + id: RequestId, + params: ResponseParams, +) -> ResponseMessage { + return ResponseMessage{jsonrpc = "2.0", id = id, result = params} } -make_response_message_error :: proc (id: RequestId, error: ResponseError) -> ResponseMessageError { - return ResponseMessageError { - jsonrpc = "2.0", - id = id, - error = error, - } +make_response_message_error :: proc( + id: RequestId, + error: ResponseError, +) -> ResponseMessageError { + return ResponseMessageError{jsonrpc = "2.0", id = id, error = error} } RequestThreadData :: struct { @@ -137,13 +135,13 @@ thread_request_main :: proc(data: rawptr) { method := root["method"].(json.String) if method == "$/cancelRequest" { - append(&deletings, Request { id = id }) + append(&deletings, Request{id = id}) json.destroy_value(root) } else if method in notification_map { - append(&requests, Request { value = root, is_notification = true}) + append(&requests, Request{value = root, is_notification = true}) sync.sema_post(&requests_sempahore) } else { - append(&requests, Request { id = id, value = root}) + append(&requests, Request{id = id, value = root}) sync.sema_post(&requests_sempahore) } @@ -153,11 +151,11 @@ thread_request_main :: proc(data: rawptr) { } } -read_and_parse_header :: proc (reader: ^Reader) -> (Header, bool) { +read_and_parse_header :: proc(reader: ^Reader) -> (Header, bool) { header: Header builder := strings.builder_make(context.temp_allocator) - + found_content_length := false for true { @@ -186,7 +184,7 @@ read_and_parse_header :: proc (reader: ^Reader) -> (Header, bool) { return header, false } - header_name := message[0:index] + header_name := message[0:index] header_value := message[len(header_name) + 2:len(message) - 2] if strings.compare(header_name, "Content-Length") == 0 { @@ -216,7 +214,13 @@ read_and_parse_header :: proc (reader: ^Reader) -> (Header, bool) { return header, found_content_length } -read_and_parse_body :: proc (reader: ^Reader, header: Header) -> (json.Value, bool) { +read_and_parse_body :: proc( + reader: ^Reader, + header: Header, +) -> ( + json.Value, + bool, +) { value: json.Value data := make([]u8, header.content_length, context.temp_allocator) @@ -228,7 +232,11 @@ read_and_parse_body :: proc (reader: ^Reader, header: Header) -> (json.Value, bo err: json.Error - value, err = json.parse(data = data, allocator = context.allocator, parse_integers = true) + value, err = json.parse( + data = data, + allocator = context.allocator, + parse_integers = true, + ) if (err != json.Error.None) { log.error("Failed to parse body") @@ -238,39 +246,43 @@ read_and_parse_body :: proc (reader: ^Reader, header: Header) -> (json.Value, bo return value, true } -call_map : map [string] proc(json.Value, RequestId, ^common.Config, ^Writer) -> common.Error = -{ - "initialize" = request_initialize, - "initialized" = request_initialized, - "shutdown" = request_shutdown, - "exit" = notification_exit, - "textDocument/didOpen" = notification_did_open, - "textDocument/didChange" = notification_did_change, - "textDocument/didClose" = notification_did_close, - "textDocument/didSave" = notification_did_save, - "textDocument/definition" = request_definition, - "textDocument/completion" = request_completion, - "textDocument/signatureHelp" = request_signature_help, - "textDocument/documentSymbol" = request_document_symbols, - "textDocument/semanticTokens/full" = request_semantic_token_full, +call_map: map[string]proc( + _: json.Value, + _: RequestId, + _: ^common.Config, + _: ^Writer, +) -> common.Error = { + "initialize" = request_initialize, + "initialized" = request_initialized, + "shutdown" = request_shutdown, + "exit" = notification_exit, + "textDocument/didOpen" = notification_did_open, + "textDocument/didChange" = notification_did_change, + "textDocument/didClose" = notification_did_close, + "textDocument/didSave" = notification_did_save, + "textDocument/definition" = request_definition, + "textDocument/completion" = request_completion, + "textDocument/signatureHelp" = request_signature_help, + "textDocument/documentSymbol" = request_document_symbols, + "textDocument/semanticTokens/full" = request_semantic_token_full, "textDocument/semanticTokens/range" = request_semantic_token_range, - "textDocument/hover" = request_hover, - "textDocument/formatting" = request_format_document, - "odin/inlayHints" = request_inlay_hint, - "textDocument/documentLink" = request_document_links, - "textDocument/rename" = request_rename, - "textDocument/references" = request_references, + "textDocument/hover" = request_hover, + "textDocument/formatting" = request_format_document, + "odin/inlayHints" = request_inlay_hint, + "textDocument/documentLink" = request_document_links, + "textDocument/rename" = request_rename, + "textDocument/references" = request_references, } -notification_map: map [string] bool = { - "textDocument/didOpen" = true, +notification_map: map[string]bool = { + "textDocument/didOpen" = true, "textDocument/didChange" = true, - "textDocument/didClose" = true, - "textDocument/didSave" = true, - "initialized" = true, + "textDocument/didClose" = true, + "textDocument/didSave" = true, + "initialized" = true, } -consume_requests :: proc (config: ^common.Config, writer: ^Writer) -> bool { +consume_requests :: proc(config: ^common.Config, writer: ^Writer) -> bool { temp_requests := make([dynamic]Request, 0, context.allocator) defer delete(temp_requests) @@ -278,14 +290,19 @@ consume_requests :: proc (config: ^common.Config, writer: ^Writer) -> bool { for d in deletings { delete_index := -1 - for request, i in requests { + for request, i in requests { if request.id == d.id { delete_index := i break } - } + } if delete_index != -1 { - cancel(requests[delete_index].value, requests[delete_index].id, writer, config) + cancel( + requests[delete_index].value, + requests[delete_index].id, + writer, + config, + ) ordered_remove(&requests, delete_index) } } @@ -304,9 +321,9 @@ consume_requests :: proc (config: ^common.Config, writer: ^Writer) -> bool { json.destroy_value(request.value) free_all(context.temp_allocator) } - + sync.mutex_lock(&requests_mutex) - + for i := 0; i < request_index; i += 1 { pop_front(&requests) } @@ -325,34 +342,44 @@ consume_requests :: proc (config: ^common.Config, writer: ^Writer) -> bool { } -cancel :: proc(value: json.Value, id: RequestId, writer: ^Writer, config: ^common.Config) { - response := make_response_message( - id = id, - params = ResponseParams {}, - ) +cancel :: proc( + value: json.Value, + id: RequestId, + writer: ^Writer, + config: ^common.Config, +) { + response := make_response_message(id = id, params = ResponseParams{}) json.destroy_value(value) send_response(response, writer) } -call :: proc(value: json.Value, id: RequestId, writer: ^Writer, config: ^common.Config) { +call :: proc( + value: json.Value, + id: RequestId, + writer: ^Writer, + config: ^common.Config, +) { root := value.(json.Object) method := root["method"].(json.String) diff: time.Duration { time.SCOPED_TICK_DURATION(&diff) - + if fn, ok := call_map[method]; !ok { - response := make_response_message_error(id = id, error = ResponseError {code = .MethodNotFound, message = ""}) + response := make_response_message_error( + id = id, + error = ResponseError{code = .MethodNotFound, message = ""}, + ) send_error(response, writer) } else { err := fn(root["params"], id, config, writer) if err != .None { response := make_response_message_error( id = id, - error = ResponseError {code = err, message = ""}, + error = ResponseError{code = err, message = ""}, ) send_error(response, writer) } @@ -362,10 +389,15 @@ call :: proc(value: json.Value, id: RequestId, writer: ^Writer, config: ^common. //log.errorf("time duration %v for %v", time.duration_milliseconds(diff), method) } -request_initialize :: proc (params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { +request_initialize :: proc( + params: json.Value, + id: RequestId, + config: ^common.Config, + writer: ^Writer, +) -> common.Error { params_object, ok := params.(json.Object) - - if !ok { + + if !ok { return .ParseError } @@ -381,41 +413,77 @@ request_initialize :: proc (params: json.Value, id: RequestId, config: ^common.C append(&config.workspace_folders, s) } - read_ols_config :: proc(file: string, config: ^common.Config, uri: common.Uri) { + read_ols_config :: proc( + file: string, + config: ^common.Config, + uri: common.Uri, + ) { if data, ok := os.read_entire_file(file, context.temp_allocator); ok { - if value, err := json.parse(data = data, allocator = context.temp_allocator, parse_integers = true); err == .None { - ols_config: OlsConfig - - if unmarshal(value, ols_config, context.temp_allocator) == nil { + if value, err := json.parse( + data = data, + allocator = context.temp_allocator, + parse_integers = true, + ); err == .None { + ols_config: OlsConfig + + if unmarshal(value, ols_config, context.temp_allocator) == + nil { config.thread_count = ols_config.thread_pool_count - config.enable_document_symbols = ols_config.enable_document_symbols.(bool) or_else true - config.enable_hover = ols_config.enable_hover.(bool) or_else true - config.enable_semantic_tokens = ols_config.enable_semantic_tokens - config.enable_procedure_context = ols_config.enable_procedure_context + config.enable_document_symbols = + ols_config.enable_document_symbols.(bool) or_else true + config.enable_hover = + ols_config.enable_hover.(bool) or_else true + config.enable_semantic_tokens = + ols_config.enable_semantic_tokens + config.enable_procedure_context = + ols_config.enable_procedure_context config.enable_snippets = ols_config.enable_snippets config.enable_references = false config.verbose = ols_config.verbose config.file_log = ols_config.file_log - config.odin_command = strings.clone(ols_config.odin_command, context.allocator) - config.checker_args = strings.clone(ols_config.checker_args, context.allocator) + config.odin_command = strings.clone( + ols_config.odin_command, + context.allocator, + ) + config.checker_args = strings.clone( + ols_config.checker_args, + context.allocator, + ) config.enable_inlay_hints = ols_config.enable_inlay_hints config.enable_format = true - + for p in ols_config.collections { - forward_path, _ := filepath.to_slash(p.path, context.temp_allocator) + forward_path, _ := filepath.to_slash( + p.path, + context.temp_allocator, + ) //Support a basic use of '~' when ODIN_OS != .Windows { if forward_path[0] == '~' { - home := os.get_env("HOME", context.temp_allocator) - strings.replace(forward_path, "~", home, 1, context.temp_allocator) + home := os.get_env( + "HOME", + context.temp_allocator, + ) + strings.replace( + forward_path, + "~", + home, + 1, + context.temp_allocator, + ) } } if filepath.is_abs(p.path) { - config.collections[strings.clone(p.name)] = strings.clone(forward_path) + config.collections[strings.clone(p.name)] = + strings.clone(forward_path) } else { - config.collections[strings.clone(p.name)] = path.join(elems = {uri.path, forward_path}, allocator = context.allocator) + config.collections[strings.clone(p.name)] = + path.join( + elems = {uri.path, forward_path}, + allocator = context.allocator, + ) } } @@ -439,7 +507,10 @@ request_initialize :: proc (params: json.Value, id: RequestId, config: ^common.C } if uri, ok := common.parse_uri(project_uri, context.temp_allocator); ok { - ols_config_path := path.join(elems = {uri.path, "ols.json"}, allocator = context.temp_allocator) + ols_config_path := path.join( + elems = {uri.path, "ols.json"}, + allocator = context.temp_allocator, + ) read_ols_config(ols_config_path, config, uri) } @@ -452,18 +523,33 @@ request_initialize :: proc (params: json.Value, id: RequestId, config: ^common.C } if "core" not_in config.collections && odin_core_env != "" { - forward_path, _ := filepath.to_slash(odin_core_env, context.temp_allocator) - config.collections["core"] = path.join(elems = {forward_path, "core"}, allocator = context.allocator) + forward_path, _ := filepath.to_slash( + odin_core_env, + context.temp_allocator, + ) + config.collections["core"] = path.join( + elems = {forward_path, "core"}, + allocator = context.allocator, + ) } if "vendor" not_in config.collections && odin_core_env != "" { - forward_path, _ := filepath.to_slash(odin_core_env, context.temp_allocator) - config.collections["vendor"] = path.join(elems = {forward_path, "vendor"}, allocator = context.allocator) + forward_path, _ := filepath.to_slash( + odin_core_env, + context.temp_allocator, + ) + config.collections["vendor"] = path.join( + elems = {forward_path, "vendor"}, + allocator = context.allocator, + ) } when ODIN_OS == .Windows { for k, v in config.collections { - forward, _ := filepath.to_slash(common.get_case_sensitive_path(v), context.temp_allocator) + forward, _ := filepath.to_slash( + common.get_case_sensitive_path(v), + context.temp_allocator, + ) config.collections[k] = strings.clone(forward, context.allocator) } } @@ -480,24 +566,37 @@ request_initialize :: proc (params: json.Value, id: RequestId, config: ^common.C } } - config.enable_snippets &= initialize_params.capabilities.textDocument.completion.completionItem.snippetSupport - config.signature_offset_support = initialize_params.capabilities.textDocument.signatureHelp.signatureInformation.parameterInformation.labelOffsetSupport + config.enable_snippets &= + initialize_params.capabilities.textDocument.completion.completionItem.snippetSupport + config.signature_offset_support = + initialize_params.capabilities.textDocument.signatureHelp.signatureInformation.parameterInformation.labelOffsetSupport - completionTriggerCharacters := []string {".", ">", "#", "\"", "/", ":"} - signatureTriggerCharacters := []string {"(", ","} - signatureRetriggerCharacters := []string {","} + completionTriggerCharacters := []string{".", ">", "#", "\"", "/", ":"} + signatureTriggerCharacters := []string{"(", ","} + signatureRetriggerCharacters := []string{","} - token_type := type_info_of(SemanticTokenTypes).variant.(runtime.Type_Info_Named).base.variant.(runtime.Type_Info_Enum) - token_modifier := type_info_of(SemanticTokenModifiers).variant.(runtime.Type_Info_Named).base.variant.(runtime.Type_Info_Enum) + token_type := type_info_of( + SemanticTokenTypes, + ).variant.(runtime.Type_Info_Named).base.variant.(runtime.Type_Info_Enum) + token_modifier := type_info_of( + SemanticTokenModifiers, + ).variant.(runtime.Type_Info_Named).base.variant.(runtime.Type_Info_Enum) - token_types := make([]string, len(token_type.names), context.temp_allocator) - token_modifiers := make([]string, len(token_modifier.names), context.temp_allocator) + token_types := make( + []string, + len(token_type.names), + context.temp_allocator, + ) + token_modifiers := make( + []string, + len(token_modifier.names), + context.temp_allocator, + ) for name, i in token_type.names { - if name == "EnumMember" { + if name == "EnumMember" { token_types[i] = "enumMember" - } - else { + } else { token_types[i] = strings.to_lower(name, context.temp_allocator) } } @@ -507,43 +606,41 @@ request_initialize :: proc (params: json.Value, id: RequestId, config: ^common.C } response := make_response_message( - params = ResponseInitializeParams { - capabilities = ServerCapabilities { - textDocumentSync = TextDocumentSyncOptions { - openClose = true, - change = 2, //incremental - save = { - includeText = true, + params = ResponseInitializeParams{ + capabilities = ServerCapabilities{ + textDocumentSync = TextDocumentSyncOptions{ + openClose = true, + change = 2, + save = {includeText = true}, }, - }, - renameProvider = config.enable_rename, - referencesProvider = config.enable_references, - definitionProvider = true, - completionProvider = CompletionOptions { - resolveProvider = false, - triggerCharacters = completionTriggerCharacters, - }, - signatureHelpProvider = SignatureHelpOptions { - triggerCharacters = signatureTriggerCharacters, - retriggerCharacters = signatureRetriggerCharacters, - }, - semanticTokensProvider = SemanticTokensOptions { - range = config.enable_semantic_tokens, - full = config.enable_semantic_tokens, - legend = SemanticTokensLegend { - tokenTypes = token_types, - tokenModifiers = token_modifiers, + renameProvider = config.enable_rename,//incremental + referencesProvider = config.enable_references, + definitionProvider = true, + completionProvider = CompletionOptions{ + resolveProvider = false, + triggerCharacters = completionTriggerCharacters, }, - }, - inlayHintsProvider = config.enable_inlay_hints, - documentSymbolProvider = config.enable_document_symbols, - hoverProvider = config.enable_hover, - documentFormattingProvider = config.enable_format, - documentLinkProvider = { - resolveProvider = false, + signatureHelpProvider = SignatureHelpOptions{ + triggerCharacters = signatureTriggerCharacters, + retriggerCharacters = signatureRetriggerCharacters, + }, + semanticTokensProvider = SemanticTokensOptions{ + range = config.enable_semantic_tokens, + full = config.enable_semantic_tokens, + legend = SemanticTokensLegend{ + tokenTypes = token_types, + tokenModifiers = token_modifiers, + }, + }, + inlayHintsProvider = config.enable_inlay_hints, + documentSymbolProvider = config.enable_document_symbols, + hoverProvider = config.enable_hover, + documentFormattingProvider = config.enable_format, + documentLinkProvider = {resolveProvider = false}, }, }, - }, id = id) + id = id, + ) send_response(response, writer) @@ -562,11 +659,21 @@ request_initialize :: proc (params: json.Value, id: RequestId, config: ^common.C return .None } -request_initialized :: proc(params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { - return .None +request_initialized :: proc( + params: json.Value, + id: RequestId, + config: ^common.Config, + writer: ^Writer, +) -> common.Error { + return .None } -request_shutdown :: proc (params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { +request_shutdown :: proc( + params: json.Value, + id: RequestId, + config: ^common.Config, + writer: ^Writer, +) -> common.Error { response := make_response_message(params = nil, id = id) send_response(response, writer) @@ -574,7 +681,12 @@ request_shutdown :: proc (params: json.Value, id: RequestId, config: ^common.Con return .None } -request_definition :: proc (params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { +request_definition :: proc( + params: json.Value, + id: RequestId, + config: ^common.Config, + writer: ^Writer, +) -> common.Error { params_object, ok := params.(json.Object) if !ok { @@ -586,14 +698,17 @@ request_definition :: proc (params: json.Value, id: RequestId, config: ^common.C if unmarshal(params, definition_params, context.temp_allocator) != nil { return .ParseError } - + document := document_get(definition_params.textDocument.uri) - if document == nil { - return .InternalError - } + if document == nil { + return .InternalError + } - locations, ok2 := get_definition_location(document, definition_params.position) + locations, ok2 := get_definition_location( + document, + definition_params.position, + ) if !ok2 { log.warn("Failed to get definition location") @@ -610,7 +725,12 @@ request_definition :: proc (params: json.Value, id: RequestId, config: ^common.C return .None } -request_completion :: proc (params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { +request_completion :: proc( + params: json.Value, + id: RequestId, + config: ^common.Config, + writer: ^Writer, +) -> common.Error { params_object, ok := params.(json.Object) if !ok { @@ -626,12 +746,16 @@ request_completion :: proc (params: json.Value, id: RequestId, config: ^common.C document := document_get(completition_params.textDocument.uri) - if document == nil { - return .InternalError - } + if document == nil { + return .InternalError + } list: CompletionList - list, ok = get_completion_list(document, completition_params.position, completition_params.context_) + list, ok = get_completion_list( + document, + completition_params.position, + completition_params.context_, + ) if !ok { return .InternalError @@ -644,7 +768,12 @@ request_completion :: proc (params: json.Value, id: RequestId, config: ^common.C return .None } -request_signature_help :: proc (params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { +request_signature_help :: proc( + params: json.Value, + id: RequestId, + config: ^common.Config, + writer: ^Writer, +) -> common.Error { params_object, ok := params.(json.Object) if !ok { @@ -659,9 +788,9 @@ request_signature_help :: proc (params: json.Value, id: RequestId, config: ^comm document := document_get(signature_params.textDocument.uri) - if document == nil { - return .InternalError - } + if document == nil { + return .InternalError + } help: SignatureHelp help, ok = get_signature_information(document, signature_params.position) @@ -682,7 +811,12 @@ request_signature_help :: proc (params: json.Value, id: RequestId, config: ^comm return .None } -request_format_document :: proc (params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { +request_format_document :: proc( + params: json.Value, + id: RequestId, + config: ^common.Config, + writer: ^Writer, +) -> common.Error { params_object, ok := params.(json.Object) if !ok { @@ -696,10 +830,10 @@ request_format_document :: proc (params: json.Value, id: RequestId, config: ^com } document := document_get(format_params.textDocument.uri) - - if document == nil { - return .InternalError - } + + if document == nil { + return .InternalError + } edit: []TextEdit edit, ok = get_complete_format(document, config) @@ -715,12 +849,22 @@ request_format_document :: proc (params: json.Value, id: RequestId, config: ^com return .None } -notification_exit :: proc (params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { +notification_exit :: proc( + params: json.Value, + id: RequestId, + config: ^common.Config, + writer: ^Writer, +) -> common.Error { config.running = false return .None } -notification_did_open :: proc (params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { +notification_did_open :: proc( + params: json.Value, + id: RequestId, + config: ^common.Config, + writer: ^Writer, +) -> common.Error { params_object, ok := params.(json.Object) if !ok { @@ -735,14 +879,24 @@ notification_did_open :: proc (params: json.Value, id: RequestId, config: ^commo return .ParseError } - if n := document_open(open_params.textDocument.uri, open_params.textDocument.text, config, writer); n != .None { + if n := document_open( + open_params.textDocument.uri, + open_params.textDocument.text, + config, + writer, + ); n != .None { return .InternalError } return .None } -notification_did_change :: proc (params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { +notification_did_change :: proc( + params: json.Value, + id: RequestId, + config: ^common.Config, + writer: ^Writer, +) -> common.Error { params_object, ok := params.(json.Object) if !ok { @@ -755,12 +909,23 @@ notification_did_change :: proc (params: json.Value, id: RequestId, config: ^com return .ParseError } - document_apply_changes(change_params.textDocument.uri, change_params.contentChanges, change_params.textDocument.version, config, writer) + document_apply_changes( + change_params.textDocument.uri, + change_params.contentChanges, + change_params.textDocument.version, + config, + writer, + ) return .None } -notification_did_close :: proc(params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { +notification_did_close :: proc( + params: json.Value, + id: RequestId, + config: ^common.Config, + writer: ^Writer, +) -> common.Error { params_object, ok := params.(json.Object) if !ok { @@ -780,7 +945,12 @@ notification_did_close :: proc(params: json.Value, id: RequestId, config: ^commo return .None } -notification_did_save :: proc (params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { +notification_did_save :: proc( + params: json.Value, + id: RequestId, + config: ^common.Config, + writer: ^Writer, +) -> common.Error { params_object, ok := params.(json.Object) if !ok { @@ -795,7 +965,10 @@ notification_did_save :: proc (params: json.Value, id: RequestId, config: ^commo uri: common.Uri - if uri, ok = common.parse_uri(save_params.textDocument.uri, context.temp_allocator); !ok { + if uri, ok = common.parse_uri( + save_params.textDocument.uri, + context.temp_allocator, + ); !ok { return .ParseError } @@ -808,9 +981,12 @@ notification_did_save :: proc (params: json.Value, id: RequestId, config: ^commo } when ODIN_OS == .Windows { - correct := common.get_case_sensitive_path(fullpath, context.temp_allocator) + correct := common.get_case_sensitive_path( + fullpath, + context.temp_allocator, + ) fullpath, _ = filepath.to_slash(correct, context.temp_allocator) - } + } dir := filepath.base(filepath.dir(fullpath, context.temp_allocator)) @@ -825,8 +1001,8 @@ notification_did_save :: proc (params: json.Value, id: RequestId, config: ^commo file := ast.File { fullpath = fullpath, - src = save_params.text, - pkg = pkg, + src = save_params.text, + pkg = pkg, } ok = parser.parse_file(&p, &file) @@ -836,27 +1012,36 @@ notification_did_save :: proc (params: json.Value, id: RequestId, config: ^commo } corrected_uri := common.create_uri(fullpath, context.temp_allocator) - + for k, v in &indexer.index.collection.packages { for k2, v2 in &v { if corrected_uri.uri == v2.uri { free_symbol(v2, indexer.index.collection.allocator) v[k2] = {} - } + } } } - if ret := collect_symbols(&indexer.index.collection, file, corrected_uri.uri); ret != .None { + if ret := collect_symbols( + &indexer.index.collection, + file, + corrected_uri.uri, + ); ret != .None { log.errorf("failed to collect symbols on save %v", ret) } - + check(uri, writer, config) return .None } -request_semantic_token_full :: proc (params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { +request_semantic_token_full :: proc( + params: json.Value, + id: RequestId, + config: ^common.Config, + writer: ^Writer, +) -> common.Error { params_object, ok := params.(json.Object) if !ok { @@ -871,17 +1056,13 @@ request_semantic_token_full :: proc (params: json.Value, id: RequestId, config: document := document_get(semantic_params.textDocument.uri) - if document == nil { - return .InternalError - } + if document == nil { + return .InternalError + } range := common.Range { - start = common.Position { - line = 0, - }, - end = common.Position { - line = 9000000, //should be enough - }, + start = common.Position{line = 0}, + end = common.Position{line = 9000000}, //should be enough } symbols: SemanticTokens @@ -901,7 +1082,12 @@ request_semantic_token_full :: proc (params: json.Value, id: RequestId, config: return .None } -request_semantic_token_range :: proc (params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { +request_semantic_token_range :: proc( + params: json.Value, + id: RequestId, + config: ^common.Config, + writer: ^Writer, +) -> common.Error { params_object, ok := params.(json.Object) if !ok { @@ -916,15 +1102,19 @@ request_semantic_token_range :: proc (params: json.Value, id: RequestId, config: document := document_get(semantic_params.textDocument.uri) - if document == nil { - return .InternalError - } + if document == nil { + return .InternalError + } symbols: SemanticTokens if config.enable_semantic_tokens { if file, ok := file_resolve_cache.files[document.uri.uri]; ok { - symbols = get_semantic_tokens(document, semantic_params.range, file.symbols) + symbols = get_semantic_tokens( + document, + semantic_params.range, + file.symbols, + ) } } @@ -935,7 +1125,12 @@ request_semantic_token_range :: proc (params: json.Value, id: RequestId, config: return .None } -request_document_symbols :: proc (params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { +request_document_symbols :: proc( + params: json.Value, + id: RequestId, + config: ^common.Config, + writer: ^Writer, +) -> common.Error { params_object, ok := params.(json.Object) if !ok { @@ -950,9 +1145,9 @@ request_document_symbols :: proc (params: json.Value, id: RequestId, config: ^co document := document_get(symbol_params.textDocument.uri) - if document == nil { - return .InternalError - } + if document == nil { + return .InternalError + } symbols := get_document_symbols(document) @@ -963,7 +1158,12 @@ request_document_symbols :: proc (params: json.Value, id: RequestId, config: ^co return .None } -request_hover :: proc (params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { +request_hover :: proc( + params: json.Value, + id: RequestId, + config: ^common.Config, + writer: ^Writer, +) -> common.Error { params_object, ok := params.(json.Object) if !ok { @@ -978,9 +1178,9 @@ request_hover :: proc (params: json.Value, id: RequestId, config: ^common.Config document := document_get(hover_params.textDocument.uri) - if document == nil { - return .InternalError - } + if document == nil { + return .InternalError + } hover: Hover valid: bool @@ -993,8 +1193,7 @@ request_hover :: proc (params: json.Value, id: RequestId, config: ^common.Config if valid { response := make_response_message(params = hover, id = id) send_response(response, writer) - } - else { + } else { response := make_response_message(params = nil, id = id) send_response(response, writer) } @@ -1002,7 +1201,12 @@ request_hover :: proc (params: json.Value, id: RequestId, config: ^common.Config return .None } -request_inlay_hint :: proc (params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { +request_inlay_hint :: proc( + params: json.Value, + id: RequestId, + config: ^common.Config, + writer: ^Writer, +) -> common.Error { params_object, ok := params.(json.Object) if !ok { @@ -1017,9 +1221,9 @@ request_inlay_hint :: proc (params: json.Value, id: RequestId, config: ^common.C document := document_get(inlay_params.textDocument.uri) - if document == nil { - return .InternalError - } + if document == nil { + return .InternalError + } hints: []InlayHint @@ -1040,7 +1244,12 @@ request_inlay_hint :: proc (params: json.Value, id: RequestId, config: ^common.C return .None } -request_document_links :: proc (params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { +request_document_links :: proc( + params: json.Value, + id: RequestId, + config: ^common.Config, + writer: ^Writer, +) -> common.Error { params_object, ok := params.(json.Object) if !ok { @@ -1055,9 +1264,9 @@ request_document_links :: proc (params: json.Value, id: RequestId, config: ^comm document := document_get(link_params.textDocument.uri) - if document == nil { - return .InternalError - } + if document == nil { + return .InternalError + } links: []DocumentLink links, ok = get_document_links(document) @@ -1073,7 +1282,12 @@ request_document_links :: proc (params: json.Value, id: RequestId, config: ^comm return .None } -request_rename :: proc (params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { +request_rename :: proc( + params: json.Value, + id: RequestId, + config: ^common.Config, + writer: ^Writer, +) -> common.Error { params_object, ok := params.(json.Object) if !ok { @@ -1088,12 +1302,16 @@ request_rename :: proc (params: json.Value, id: RequestId, config: ^common.Confi document := document_get(rename_param.textDocument.uri) - if document == nil { - return .InternalError - } + if document == nil { + return .InternalError + } workspace_edit: WorkspaceEdit - workspace_edit, ok = get_rename(document, rename_param.newName, rename_param.position) + workspace_edit, ok = get_rename( + document, + rename_param.newName, + rename_param.position, + ) if !ok { return .InternalError @@ -1106,7 +1324,12 @@ request_rename :: proc (params: json.Value, id: RequestId, config: ^common.Confi return .None } -request_references :: proc (params: json.Value, id: RequestId, config: ^common.Config, writer: ^Writer) -> common.Error { +request_references :: proc( + params: json.Value, + id: RequestId, + config: ^common.Config, + writer: ^Writer, +) -> common.Error { params_object, ok := params.(json.Object) if !ok { @@ -1121,9 +1344,9 @@ request_references :: proc (params: json.Value, id: RequestId, config: ^common.C document := document_get(reference_param.textDocument.uri) - if document == nil { - return .InternalError - } + if document == nil { + return .InternalError + } locations: []common.Location locations, ok = get_references(document, reference_param.position) diff --git a/src/server/response.odin b/src/server/response.odin index e42f9ae..d31b3cd 100644 --- a/src/server/response.odin +++ b/src/server/response.odin @@ -3,7 +3,10 @@ package server import "core:fmt" import "core:encoding/json" -send_notification :: proc (notification: Notification, writer: ^Writer) -> bool { +send_notification :: proc( + notification: Notification, + writer: ^Writer, +) -> bool { data, error := json.marshal(notification, {}, context.temp_allocator) header := fmt.tprintf("Content-Length: %v\r\n\r\n", len(data)) @@ -23,7 +26,7 @@ send_notification :: proc (notification: Notification, writer: ^Writer) -> bool return true } -send_response :: proc (response: ResponseMessage, writer: ^Writer) -> bool { +send_response :: proc(response: ResponseMessage, writer: ^Writer) -> bool { data, error := json.marshal(response, {}, context.temp_allocator) header := fmt.tprintf("Content-Length: %v\r\n\r\n", len(data)) @@ -43,7 +46,7 @@ send_response :: proc (response: ResponseMessage, writer: ^Writer) -> bool { return true } -send_error :: proc (response: ResponseMessageError, writer: ^Writer) -> bool { +send_error :: proc(response: ResponseMessageError, writer: ^Writer) -> bool { data, error := json.marshal(response, {}, context.temp_allocator) header := fmt.tprintf("Content-Length: %v\r\n\r\n", len(data)) diff --git a/src/server/semantic_tokens.odin b/src/server/semantic_tokens.odin index b936419..b22d53f 100644 --- a/src/server/semantic_tokens.odin +++ b/src/server/semantic_tokens.odin @@ -32,15 +32,15 @@ SemanticTokenTypes :: enum { Method, } -SemanticTokenModifiers :: enum(u32) { - None = 0, +SemanticTokenModifiers :: enum (u32) { + None = 0, Declaration = 2, - Definition = 4, - Deprecated = 8, + Definition = 4, + Deprecated = 8, } SemanticTokensClientCapabilities :: struct { - requests: struct { + requests: struct { range: bool, }, tokenTypes: []string, @@ -81,33 +81,48 @@ SemanticTokenBuilder :: struct { selector: bool, } -make_token_builder :: proc(allocator := context.temp_allocator) -> SemanticTokenBuilder { - return { - tokens = make([dynamic]u32, 1000, context.temp_allocator), - } +make_token_builder :: proc( + allocator := context.temp_allocator, +) -> SemanticTokenBuilder { + return {tokens = make([dynamic]u32, 1000, context.temp_allocator)} } get_tokens :: proc(builder: SemanticTokenBuilder) -> SemanticTokens { - return { - data = builder.tokens[:], - } + return {data = builder.tokens[:]} } -get_semantic_tokens :: proc(document: ^Document, range: common.Range, symbols: map[uintptr]SymbolAndNode) -> SemanticTokens { +get_semantic_tokens :: proc( + document: ^Document, + range: common.Range, + symbols: map[uintptr]SymbolAndNode, +) -> SemanticTokens { builder := make_token_builder() if document.ast.pkg_decl != nil { - write_semantic_token(&builder, document.ast.pkg_token, document.ast.src, .Keyword, .None) + write_semantic_token( + &builder, + document.ast.pkg_token, + document.ast.src, + .Keyword, + .None, + ) } - ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri, document.fullpath) + ast_context := make_ast_context( + document.ast, + document.imports, + document.package_name, + document.uri.uri, + document.fullpath, + ) builder.symbols = symbols ast_context.current_package = ast_context.document_package for decl in document.ast.decls { - if range.start.line <= decl.pos.line && decl.end.line <= range.end.line { + if range.start.line <= decl.pos.line && + decl.end.line <= range.end.line { visit(decl, &builder, &ast_context) } } @@ -115,22 +130,74 @@ get_semantic_tokens :: proc(document: ^Document, range: common.Range, symbols: m return get_tokens(builder) } -write_semantic_node :: proc(builder: ^SemanticTokenBuilder, node: ^ast.Node, src: string, type: SemanticTokenTypes, modifier: SemanticTokenModifiers) { - position := common.get_relative_token_position(node.pos.offset, transmute([]u8)src, builder.current_start) +write_semantic_node :: proc( + builder: ^SemanticTokenBuilder, + node: ^ast.Node, + src: string, + type: SemanticTokenTypes, + modifier: SemanticTokenModifiers, +) { + position := common.get_relative_token_position( + node.pos.offset, + transmute([]u8)src, + builder.current_start, + ) name := common.get_ast_node_string(node, src) - append(&builder.tokens, cast(u32)position.line, cast(u32)position.character, cast(u32)len(name), cast(u32)type, cast(u32)modifier) + append( + &builder.tokens, + cast(u32)position.line, + cast(u32)position.character, + cast(u32)len(name), + cast(u32)type, + cast(u32)modifier, + ) builder.current_start = node.pos.offset } -write_semantic_token :: proc(builder: ^SemanticTokenBuilder, token: tokenizer.Token, src: string, type: SemanticTokenTypes, modifier: SemanticTokenModifiers) { - position := common.get_relative_token_position(token.pos.offset, transmute([]u8)src, builder.current_start) - append(&builder.tokens, cast(u32)position.line, cast(u32)position.character, cast(u32)len(token.text), cast(u32)type, cast(u32)modifier) +write_semantic_token :: proc( + builder: ^SemanticTokenBuilder, + token: tokenizer.Token, + src: string, + type: SemanticTokenTypes, + modifier: SemanticTokenModifiers, +) { + position := common.get_relative_token_position( + token.pos.offset, + transmute([]u8)src, + builder.current_start, + ) + append( + &builder.tokens, + cast(u32)position.line, + cast(u32)position.character, + cast(u32)len(token.text), + cast(u32)type, + cast(u32)modifier, + ) builder.current_start = token.pos.offset } -write_semantic_string :: proc(builder: ^SemanticTokenBuilder, pos: tokenizer.Pos, name: string, src: string, type: SemanticTokenTypes, modifier: SemanticTokenModifiers) { - position := common.get_relative_token_position(pos.offset, transmute([]u8)src, builder.current_start) - append(&builder.tokens, cast(u32)position.line, cast(u32)position.character, cast(u32)len(name), cast(u32)type, cast(u32)modifier) +write_semantic_string :: proc( + builder: ^SemanticTokenBuilder, + pos: tokenizer.Pos, + name: string, + src: string, + type: SemanticTokenTypes, + modifier: SemanticTokenModifiers, +) { + position := common.get_relative_token_position( + pos.offset, + transmute([]u8)src, + builder.current_start, + ) + append( + &builder.tokens, + cast(u32)position.line, + cast(u32)position.character, + cast(u32)len(name), + cast(u32)type, + cast(u32)modifier, + ) builder.current_start = pos.offset } @@ -141,23 +208,39 @@ visit :: proc { visit_stmt, } -visit_array :: proc(array: $A/[]^$T, builder: ^SemanticTokenBuilder, ast_context: ^AstContext) { +visit_array :: proc( + array: $A/[]^$T, + builder: ^SemanticTokenBuilder, + ast_context: ^AstContext, +) { for elem, i in array { visit(elem, builder, ast_context) } } -visit_dynamic_array :: proc(array: $A/[dynamic]^$T, builder: ^SemanticTokenBuilder, ast_context: ^AstContext) { +visit_dynamic_array :: proc( + array: $A/[dynamic]^$T, + builder: ^SemanticTokenBuilder, + ast_context: ^AstContext, +) { for elem, i in array { visit(elem, builder, ast_context) } } -visit_stmt :: proc(node: ^ast.Stmt, builder: ^SemanticTokenBuilder, ast_context: ^AstContext) { +visit_stmt :: proc( + node: ^ast.Stmt, + builder: ^SemanticTokenBuilder, + ast_context: ^AstContext, +) { visit_node(node, builder, ast_context) } -visit_node :: proc(node: ^ast.Node, builder: ^SemanticTokenBuilder, ast_context: ^AstContext) { +visit_node :: proc( + node: ^ast.Node, + builder: ^SemanticTokenBuilder, + ast_context: ^AstContext, +) { using ast if node == nil { @@ -166,47 +249,123 @@ visit_node :: proc(node: ^ast.Node, builder: ^SemanticTokenBuilder, ast_context: #partial switch n in node.derived { case ^Ellipsis: - write_semantic_string(builder, node.pos, "..", ast_context.file.src, .Operator, .None) + write_semantic_string( + builder, + node.pos, + "..", + ast_context.file.src, + .Operator, + .None, + ) visit(n.expr, builder, ast_context) case ^Ident: if symbol_and_node, ok := builder.symbols[cast(uintptr)node]; ok { - if symbol_and_node.symbol.type == .Variable || symbol_and_node.symbol.type == .Constant { - write_semantic_node(builder, node, ast_context.file.src, .Variable, .None) + if symbol_and_node.symbol.type == .Variable || + symbol_and_node.symbol.type == .Constant { + write_semantic_node( + builder, + node, + ast_context.file.src, + .Variable, + .None, + ) return - } + } - #partial switch v in symbol_and_node.symbol.value { + #partial switch v in symbol_and_node.symbol.value { case SymbolPackageValue: - write_semantic_node(builder, node, ast_context.file.src, .Namespace, .None) + write_semantic_node( + builder, + node, + ast_context.file.src, + .Namespace, + .None, + ) case SymbolStructValue: - write_semantic_node(builder, node, ast_context.file.src, .Struct, .None) + write_semantic_node( + builder, + node, + ast_context.file.src, + .Struct, + .None, + ) case SymbolEnumValue: - write_semantic_node(builder, node, ast_context.file.src, .Enum, .None) + write_semantic_node( + builder, + node, + ast_context.file.src, + .Enum, + .None, + ) case SymbolUnionValue: - write_semantic_node(builder, node, ast_context.file.src, .Enum, .None) + write_semantic_node( + builder, + node, + ast_context.file.src, + .Enum, + .None, + ) case SymbolProcedureValue: - write_semantic_node(builder, node, ast_context.file.src, .Function, .None) + write_semantic_node( + builder, + node, + ast_context.file.src, + .Function, + .None, + ) case SymbolProcedureGroupValue: - write_semantic_node(builder, node, ast_context.file.src, .Function, .None) + write_semantic_node( + builder, + node, + ast_context.file.src, + .Function, + .None, + ) case SymbolUntypedValue: - write_semantic_node(builder, node, ast_context.file.src, .Type, .None) + write_semantic_node( + builder, + node, + ast_context.file.src, + .Type, + .None, + ) case SymbolBasicValue: - write_semantic_node(builder, node, ast_context.file.src, .Type, .None) + write_semantic_node( + builder, + node, + ast_context.file.src, + .Type, + .None, + ) case: - //log.errorf("Unexpected symbol value: %v", symbol.value); - //panic(fmt.tprintf("Unexpected symbol value: %v", symbol.value)); + //log.errorf("Unexpected symbol value: %v", symbol.value); + //panic(fmt.tprintf("Unexpected symbol value: %v", symbol.value)); } } case ^Selector_Expr: visit_selector(cast(^Selector_Expr)node, builder, ast_context) builder.selector = false case ^When_Stmt: - write_semantic_string(builder, n.when_pos, "when", ast_context.file.src, .Keyword, .None) + write_semantic_string( + builder, + n.when_pos, + "when", + ast_context.file.src, + .Keyword, + .None, + ) visit(n.cond, builder, ast_context) visit(n.body, builder, ast_context) visit(n.else_stmt, builder, ast_context) case ^Pointer_Type: - write_semantic_string(builder, node.pos, "^", ast_context.file.src, .Operator, .None) + write_semantic_string( + builder, + node.pos, + "^", + ast_context.file.src, + .Operator, + .None, + ) visit(n.elem, builder, ast_context) case ^Value_Decl: visit_value_decl(n^, builder, ast_context) @@ -215,52 +374,126 @@ visit_node :: proc(node: ^ast.Node, builder: ^SemanticTokenBuilder, ast_context: case ^Expr_Stmt: visit(n.expr, builder, ast_context) case ^Branch_Stmt: - write_semantic_token(builder, n.tok, ast_context.file.src, .Keyword, .None) + write_semantic_token( + builder, + n.tok, + ast_context.file.src, + .Keyword, + .None, + ) case ^Poly_Type: - write_semantic_string(builder, n.dollar, "$", ast_context.file.src, .Operator, .None) + write_semantic_string( + builder, + n.dollar, + "$", + ast_context.file.src, + .Operator, + .None, + ) visit(n.type, builder, ast_context) visit(n.specialization, builder, ast_context) case ^Range_Stmt: - write_semantic_string(builder, n.for_pos, "for", ast_context.file.src, .Keyword, .None) + write_semantic_string( + builder, + n.for_pos, + "for", + ast_context.file.src, + .Keyword, + .None, + ) for val in n.vals { if ident, ok := val.derived.(^Ident); ok { - write_semantic_node(builder, val, ast_context.file.src, .Variable, .None) + write_semantic_node( + builder, + val, + ast_context.file.src, + .Variable, + .None, + ) } } - write_semantic_string(builder, n.in_pos, "in", ast_context.file.src, .Keyword, .None) + write_semantic_string( + builder, + n.in_pos, + "in", + ast_context.file.src, + .Keyword, + .None, + ) visit(n.expr, builder, ast_context) visit(n.body, builder, ast_context) case ^If_Stmt: - write_semantic_string(builder, n.if_pos, "if", ast_context.file.src, .Keyword, .None) + write_semantic_string( + builder, + n.if_pos, + "if", + ast_context.file.src, + .Keyword, + .None, + ) visit(n.init, builder, ast_context) visit(n.cond, builder, ast_context) visit(n.body, builder, ast_context) if n.else_stmt != nil { - write_semantic_string(builder, n.else_pos, "else", ast_context.file.src, .Keyword, .None) + write_semantic_string( + builder, + n.else_pos, + "else", + ast_context.file.src, + .Keyword, + .None, + ) visit(n.else_stmt, builder, ast_context) } case ^For_Stmt: - write_semantic_string(builder, n.for_pos, "for", ast_context.file.src, .Keyword, .None) + write_semantic_string( + builder, + n.for_pos, + "for", + ast_context.file.src, + .Keyword, + .None, + ) visit(n.init, builder, ast_context) visit(n.cond, builder, ast_context) visit(n.post, builder, ast_context) visit(n.body, builder, ast_context) case ^Switch_Stmt: - write_semantic_string(builder, n.switch_pos, "switch", ast_context.file.src, .Keyword, .None) + write_semantic_string( + builder, + n.switch_pos, + "switch", + ast_context.file.src, + .Keyword, + .None, + ) visit(n.init, builder, ast_context) visit(n.cond, builder, ast_context) visit(n.body, builder, ast_context) case ^Type_Switch_Stmt: - write_semantic_string(builder, n.switch_pos, "switch", ast_context.file.src, .Keyword, .None) + write_semantic_string( + builder, + n.switch_pos, + "switch", + ast_context.file.src, + .Keyword, + .None, + ) visit(n.tag, builder, ast_context) visit(n.expr, builder, ast_context) visit(n.body, builder, ast_context) case ^Assign_Stmt: for l in n.lhs { if ident, ok := l.derived.(^Ident); ok { - write_semantic_node(builder, l, ast_context.file.src, .Variable, .None) + write_semantic_node( + builder, + l, + ast_context.file.src, + .Variable, + .None, + ) } else { visit(l, builder, ast_context) } @@ -269,14 +502,27 @@ visit_node :: proc(node: ^ast.Node, builder: ^SemanticTokenBuilder, ast_context: visit_token_op(builder, n.op, ast_context.file.src) visit(n.rhs, builder, ast_context) case ^Case_Clause: - write_semantic_string(builder, n.case_pos, "case", ast_context.file.src, .Keyword, .None) + write_semantic_string( + builder, + n.case_pos, + "case", + ast_context.file.src, + .Keyword, + .None, + ) visit(n.list, builder, ast_context) visit(n.body, builder, ast_context) case ^Call_Expr: visit(n.expr, builder, ast_context) visit(n.args, builder, ast_context) case ^Implicit_Selector_Expr: - write_semantic_node(builder, n.field, ast_context.file.src, .Enum, .None) + write_semantic_node( + builder, + n.field, + ast_context.file.src, + .EnumMember, + .None, + ) case ^Array_Type: visit(n.elem, builder, ast_context) case ^Binary_Expr: @@ -287,13 +533,27 @@ visit_node :: proc(node: ^ast.Node, builder: ^SemanticTokenBuilder, ast_context: visit(n.type, builder, ast_context) visit(n.elems, builder, ast_context) case ^Struct_Type: - write_semantic_string(builder, n.pos, "struct", ast_context.file.src, .Keyword, .None) + write_semantic_string( + builder, + n.pos, + "struct", + ast_context.file.src, + .Keyword, + .None, + ) visit_struct_fields(n^, builder, ast_context) case ^Type_Assertion: visit(n.expr, builder, ast_context) visit(n.type, builder, ast_context) case ^Type_Cast: - write_semantic_string(builder, n.pos, "cast", ast_context.file.src, .Keyword, .None) + write_semantic_string( + builder, + n.pos, + "cast", + ast_context.file.src, + .Keyword, + .None, + ) visit(n.type, builder, ast_context) visit(n.expr, builder, ast_context) case ^Paren_Expr: @@ -301,17 +561,44 @@ visit_node :: proc(node: ^ast.Node, builder: ^SemanticTokenBuilder, ast_context: case ^Deref_Expr: visit(n.expr, builder, ast_context) case ^Return_Stmt: - write_semantic_string(builder, n.pos, "return", ast_context.file.src, .Keyword, .None) + write_semantic_string( + builder, + n.pos, + "return", + ast_context.file.src, + .Keyword, + .None, + ) visit(n.results, builder, ast_context) case ^Dynamic_Array_Type: - write_semantic_string(builder, n.dynamic_pos, "dynamic", ast_context.file.src, .Keyword, .None) + write_semantic_string( + builder, + n.dynamic_pos, + "dynamic", + ast_context.file.src, + .Keyword, + .None, + ) visit(n.elem, builder, ast_context) case ^Multi_Pointer_Type: - write_semantic_string(builder, n.pos, "[^]", ast_context.file.src, .Keyword, .None) + write_semantic_string( + builder, + n.pos, + "[^]", + ast_context.file.src, + .Keyword, + .None, + ) visit(n.elem, builder, ast_context) case ^Field_Value: if ident, ok := n.field.derived.(^Ident); ok { - write_semantic_node(builder, n.field, ast_context.file.src, .Property, .None) + write_semantic_node( + builder, + n.field, + ast_context.file.src, + .Property, + .None, + ) } visit(n.value, builder, ast_context) @@ -326,29 +613,80 @@ visit_node :: proc(node: ^ast.Node, builder: ^SemanticTokenBuilder, ast_context: case ^Slice_Expr: visit(n.expr, builder, ast_context) case ^Using_Stmt: - write_semantic_string(builder, n.pos, "using", ast_context.file.src, .Keyword, .None) + write_semantic_string( + builder, + n.pos, + "using", + ast_context.file.src, + .Keyword, + .None, + ) visit(n.list, builder, ast_context) case ^Map_Type: - write_semantic_string(builder, n.tok_pos, "map", ast_context.file.src, .Keyword, .None) + write_semantic_string( + builder, + n.tok_pos, + "map", + ast_context.file.src, + .Keyword, + .None, + ) visit(n.key, builder, ast_context) visit(n.value, builder, ast_context) case ^Defer_Stmt: - write_semantic_string(builder, n.pos, "defer", ast_context.file.src, .Keyword, .None) + write_semantic_string( + builder, + n.pos, + "defer", + ast_context.file.src, + .Keyword, + .None, + ) visit(n.stmt, builder, ast_context) case ^Import_Decl: - write_semantic_token(builder, n.import_tok, ast_context.file.src, .Keyword, .None) + write_semantic_token( + builder, + n.import_tok, + ast_context.file.src, + .Keyword, + .None, + ) if n.name.text != "" { - write_semantic_token(builder, n.name, ast_context.file.src, .Namespace, .None) + write_semantic_token( + builder, + n.name, + ast_context.file.src, + .Namespace, + .None, + ) } - write_semantic_token(builder, n.relpath, ast_context.file.src, .String, .None) + write_semantic_token( + builder, + n.relpath, + ast_context.file.src, + .String, + .None, + ) case ^Or_Return_Expr: visit(n.expr, builder, ast_context) - write_semantic_token(builder, n.token, ast_context.file.src, .Keyword, .None) + write_semantic_token( + builder, + n.token, + ast_context.file.src, + .Keyword, + .None, + ) case ^Or_Else_Expr: visit(n.x, builder, ast_context) - write_semantic_token(builder, n.token, ast_context.file.src, .Keyword, .None) + write_semantic_token( + builder, + n.token, + ast_context.file.src, + .Keyword, + .None, + ) visit(n.y, builder, ast_context) case ^Ternary_If_Expr: if n.op1.text == "if" { @@ -359,38 +697,70 @@ visit_node :: proc(node: ^ast.Node, builder: ^SemanticTokenBuilder, ast_context: visit(n.cond, builder, ast_context) visit(n.x, builder, ast_context) visit(n.y, builder, ast_context) - } + } case ^Ternary_When_Expr: visit(n.cond, builder, ast_context) visit(n.x, builder, ast_context) visit(n.y, builder, ast_context) case: - //log.errorf("unhandled semantic token node %v", n); - //panic(fmt.tprintf("Missed semantic token handling %v", n)); + //log.errorf("unhandled semantic token node %v", n); + //panic(fmt.tprintf("Missed semantic token handling %v", n)); } } -visit_basic_lit :: proc(basic_lit: ast.Basic_Lit, builder: ^SemanticTokenBuilder, ast_context: ^AstContext) { +visit_basic_lit :: proc( + basic_lit: ast.Basic_Lit, + builder: ^SemanticTokenBuilder, + ast_context: ^AstContext, +) { if symbol, ok := resolve_basic_lit(ast_context, basic_lit); ok { if untyped, ok := symbol.value.(SymbolUntypedValue); ok { switch untyped.type { case .Bool: - write_semantic_token(builder, basic_lit.tok, ast_context.file.src, .Keyword, .None) + write_semantic_token( + builder, + basic_lit.tok, + ast_context.file.src, + .Keyword, + .None, + ) case .Float, .Integer: - write_semantic_token(builder, basic_lit.tok, ast_context.file.src, .Number, .None) + write_semantic_token( + builder, + basic_lit.tok, + ast_context.file.src, + .Number, + .None, + ) case .String: - write_semantic_token(builder, basic_lit.tok, ast_context.file.src, .String, .None) + write_semantic_token( + builder, + basic_lit.tok, + ast_context.file.src, + .String, + .None, + ) } } } } -visit_value_decl :: proc(value_decl: ast.Value_Decl, builder: ^SemanticTokenBuilder, ast_context: ^AstContext) { +visit_value_decl :: proc( + value_decl: ast.Value_Decl, + builder: ^SemanticTokenBuilder, + ast_context: ^AstContext, +) { using ast if value_decl.type != nil { for name in value_decl.names { - write_semantic_node(builder, name, ast_context.file.src, .Variable, .None) + write_semantic_node( + builder, + name, + ast_context.file.src, + .Variable, + .None, + ) } visit(value_decl.type, builder, ast_context) @@ -401,41 +771,124 @@ visit_value_decl :: proc(value_decl: ast.Value_Decl, builder: ^SemanticTokenBuil if len(value_decl.values) == 1 { #partial switch v in value_decl.values[0].derived { case ^Union_Type: - write_semantic_node(builder, value_decl.names[0], ast_context.file.src, .Enum, .None) - write_semantic_string(builder, v.pos, "union", ast_context.file.src, .Keyword, .None) + write_semantic_node( + builder, + value_decl.names[0], + ast_context.file.src, + .Enum, + .None, + ) + write_semantic_string( + builder, + v.pos, + "union", + ast_context.file.src, + .Keyword, + .None, + ) visit(v.variants, builder, ast_context) case ^Struct_Type: - write_semantic_node(builder, value_decl.names[0], ast_context.file.src, .Struct, .None) - write_semantic_string(builder, v.pos, "struct", ast_context.file.src, .Keyword, .None) + write_semantic_node( + builder, + value_decl.names[0], + ast_context.file.src, + .Struct, + .None, + ) + write_semantic_string( + builder, + v.pos, + "struct", + ast_context.file.src, + .Keyword, + .None, + ) visit_struct_fields(v^, builder, ast_context) case ^Enum_Type: - write_semantic_node(builder, value_decl.names[0], ast_context.file.src, .Enum, .None) - write_semantic_string(builder, v.pos, "enum", ast_context.file.src, .Keyword, .None) + write_semantic_node( + builder, + value_decl.names[0], + ast_context.file.src, + .Enum, + .None, + ) + write_semantic_string( + builder, + v.pos, + "enum", + ast_context.file.src, + .Keyword, + .None, + ) visit_enum_fields(v^, builder, ast_context) case ^Proc_Group: - write_semantic_node(builder, value_decl.names[0], ast_context.file.src, .Function, .None) - write_semantic_string(builder, v.pos, "proc", ast_context.file.src, .Keyword, .None) + write_semantic_node( + builder, + value_decl.names[0], + ast_context.file.src, + .Function, + .None, + ) + write_semantic_string( + builder, + v.pos, + "proc", + ast_context.file.src, + .Keyword, + .None, + ) for arg in v.args { if ident, ok := arg.derived.(^Ident); ok { - write_semantic_node(builder, arg, ast_context.file.src, .Function, .None) + write_semantic_node( + builder, + arg, + ast_context.file.src, + .Function, + .None, + ) } } case ^Proc_Lit: - write_semantic_node(builder, value_decl.names[0], ast_context.file.src, .Function, .None) - write_semantic_string(builder, v.pos, "proc", ast_context.file.src, .Keyword, .None) + write_semantic_node( + builder, + value_decl.names[0], + ast_context.file.src, + .Function, + .None, + ) + write_semantic_string( + builder, + v.pos, + "proc", + ast_context.file.src, + .Keyword, + .None, + ) visit_proc_type(v.type, builder, ast_context) visit(v.body, builder, ast_context) case: for name in value_decl.names { - write_semantic_node(builder, name, ast_context.file.src, .Variable, .None) + write_semantic_node( + builder, + name, + ast_context.file.src, + .Variable, + .None, + ) } visit(value_decl.values[0], builder, ast_context) } } else { for name in value_decl.names { - write_semantic_node(builder, name, ast_context.file.src, .Variable, .None) + write_semantic_node( + builder, + name, + ast_context.file.src, + .Variable, + .None, + ) } for value in value_decl.values { @@ -444,15 +897,37 @@ visit_value_decl :: proc(value_decl: ast.Value_Decl, builder: ^SemanticTokenBuil } } -visit_token_op :: proc(builder: ^SemanticTokenBuilder, token: tokenizer.Token, src: string) { +visit_token_op :: proc( + builder: ^SemanticTokenBuilder, + token: tokenizer.Token, + src: string, +) { if token.text == "in" { - write_semantic_string(builder, token.pos, token.text, src, .Keyword, .None) + write_semantic_string( + builder, + token.pos, + token.text, + src, + .Keyword, + .None, + ) } else { - write_semantic_string(builder, token.pos, token.text, src, .Operator, .None) + write_semantic_string( + builder, + token.pos, + token.text, + src, + .Operator, + .None, + ) } } -visit_proc_type :: proc(node: ^ast.Proc_Type, builder: ^SemanticTokenBuilder, ast_context: ^AstContext) { +visit_proc_type :: proc( + node: ^ast.Proc_Type, + builder: ^SemanticTokenBuilder, + ast_context: ^AstContext, +) { using ast if node == nil { @@ -463,7 +938,13 @@ visit_proc_type :: proc(node: ^ast.Proc_Type, builder: ^SemanticTokenBuilder, as for param in node.params.list { for name in param.names { if ident, ok := name.derived.(^Ident); ok { - write_semantic_node(builder, name, ast_context.file.src, .Parameter, .None) + write_semantic_node( + builder, + name, + ast_context.file.src, + .Parameter, + .None, + ) } } @@ -479,7 +960,11 @@ visit_proc_type :: proc(node: ^ast.Proc_Type, builder: ^SemanticTokenBuilder, as } } -visit_enum_fields :: proc(node: ast.Enum_Type, builder: ^SemanticTokenBuilder, ast_context: ^AstContext) { +visit_enum_fields :: proc( + node: ast.Enum_Type, + builder: ^SemanticTokenBuilder, + ast_context: ^AstContext, +) { using ast if node.fields == nil { @@ -488,18 +973,33 @@ visit_enum_fields :: proc(node: ast.Enum_Type, builder: ^SemanticTokenBuilder, a for field in node.fields { if ident, ok := field.derived.(^Ident); ok { - write_semantic_node(builder, field, ast_context.file.src, .EnumMember, .None) - } - else if f, ok := field.derived.(^Field_Value); ok { + write_semantic_node( + builder, + field, + ast_context.file.src, + .EnumMember, + .None, + ) + } else if f, ok := field.derived.(^Field_Value); ok { if _, ok := f.field.derived.(^Ident); ok { - write_semantic_node(builder, f.field, ast_context.file.src, .EnumMember, .None) + write_semantic_node( + builder, + f.field, + ast_context.file.src, + .EnumMember, + .None, + ) } visit(f.value, builder, ast_context) } } } -visit_struct_fields :: proc(node: ast.Struct_Type, builder: ^SemanticTokenBuilder, ast_context: ^AstContext) { +visit_struct_fields :: proc( + node: ast.Struct_Type, + builder: ^SemanticTokenBuilder, + ast_context: ^AstContext, +) { using ast if node.fields == nil { @@ -509,7 +1009,13 @@ visit_struct_fields :: proc(node: ast.Struct_Type, builder: ^SemanticTokenBuilde for field in node.fields.list { for name in field.names { if ident, ok := name.derived.(^Ident); ok { - write_semantic_node(builder, name, ast_context.file.src, .Property, .None) + write_semantic_node( + builder, + name, + ast_context.file.src, + .Property, + .None, + ) } } @@ -517,9 +1023,17 @@ visit_struct_fields :: proc(node: ast.Struct_Type, builder: ^SemanticTokenBuilde } } -visit_selector :: proc(selector: ^ast.Selector_Expr, builder: ^SemanticTokenBuilder, ast_context: ^AstContext) { +visit_selector :: proc( + selector: ^ast.Selector_Expr, + builder: ^SemanticTokenBuilder, + ast_context: ^AstContext, +) { if _, ok := selector.expr.derived.(^ast.Selector_Expr); ok { - visit_selector(cast(^ast.Selector_Expr)selector.expr, builder, ast_context) + visit_selector( + cast(^ast.Selector_Expr)selector.expr, + builder, + ast_context, + ) } else { visit(selector.expr, builder, ast_context) builder.selector = true @@ -527,21 +1041,63 @@ visit_selector :: proc(selector: ^ast.Selector_Expr, builder: ^SemanticTokenBuil if symbol_and_node, ok := builder.symbols[cast(uintptr)selector]; ok { if symbol_and_node.symbol.type == .Variable { - write_semantic_node(builder, selector.field, ast_context.file.src, .Property, .None) + write_semantic_node( + builder, + selector.field, + ast_context.file.src, + .Property, + .None, + ) } - #partial switch v in symbol_and_node.symbol.value { + #partial switch v in symbol_and_node.symbol.value { case SymbolPackageValue: - write_semantic_node(builder, selector.field, ast_context.file.src, .Namespace, .None) + write_semantic_node( + builder, + selector.field, + ast_context.file.src, + .Namespace, + .None, + ) case SymbolStructValue: - write_semantic_node(builder, selector.field, ast_context.file.src, .Struct, .None) + write_semantic_node( + builder, + selector.field, + ast_context.file.src, + .Struct, + .None, + ) case SymbolEnumValue: - write_semantic_node(builder, selector.field, ast_context.file.src, .Enum, .None) + write_semantic_node( + builder, + selector.field, + ast_context.file.src, + .Enum, + .None, + ) case SymbolUnionValue: - write_semantic_node(builder, selector.field, ast_context.file.src, .Enum, .None) + write_semantic_node( + builder, + selector.field, + ast_context.file.src, + .Enum, + .None, + ) case SymbolProcedureValue: - write_semantic_node(builder, selector.field, ast_context.file.src, .Function, .None) + write_semantic_node( + builder, + selector.field, + ast_context.file.src, + .Function, + .None, + ) case SymbolProcedureGroupValue: - write_semantic_node(builder, selector.field, ast_context.file.src, .Function, .None) + write_semantic_node( + builder, + selector.field, + ast_context.file.src, + .Function, + .None, + ) } } -}
\ No newline at end of file +} diff --git a/src/server/signature.odin b/src/server/signature.odin index 0036bf2..e5acfa9 100644 --- a/src/server/signature.odin +++ b/src/server/signature.odin @@ -52,7 +52,7 @@ ParameterInformation :: struct { build_procedure_symbol_signature :: proc(symbol: ^Symbol) { if value, ok := symbol.value.(SymbolProcedureValue); ok { builder := strings.builder_make(context.temp_allocator) - + strings.write_string(&builder, "proc") strings.write_string(&builder, "(") for arg, i in value.arg_types { @@ -69,14 +69,14 @@ build_procedure_symbol_signature :: proc(symbol: ^Symbol) { if len(value.return_types) > 1 { strings.write_string(&builder, "(") } - + for arg, i in value.return_types { strings.write_string(&builder, common.node_to_string(arg)) if i != len(value.return_types) - 1 { strings.write_string(&builder, ", ") } } - + if len(value.return_types) > 1 { strings.write_string(&builder, ")") } @@ -90,7 +90,7 @@ build_procedure_symbol_signature :: proc(symbol: ^Symbol) { seperate_proc_field_arguments :: proc(procedure: ^Symbol) { if value, ok := &procedure.value.(SymbolProcedureValue); ok { types := make([dynamic]^ast.Field, context.temp_allocator) - + for arg, i in value.arg_types { if len(arg.names) == 1 { append(&types, arg) @@ -98,7 +98,12 @@ seperate_proc_field_arguments :: proc(procedure: ^Symbol) { } for name in arg.names { - field : ^ast.Field = new_type(ast.Field, {}, {}, context.temp_allocator) + field: ^ast.Field = new_type( + ast.Field, + {}, + {}, + context.temp_allocator, + ) field.names = make([]^ast.Expr, 1, context.temp_allocator) field.names[0] = name field.type = arg.type @@ -110,12 +115,28 @@ seperate_proc_field_arguments :: proc(procedure: ^Symbol) { } } -get_signature_information :: proc(document: ^Document, position: common.Position) -> (SignatureHelp, bool) { +get_signature_information :: proc( + document: ^Document, + position: common.Position, +) -> ( + SignatureHelp, + bool, +) { signature_help: SignatureHelp - ast_context := make_ast_context(document.ast, document.imports, document.package_name, document.uri.uri, document.fullpath) + ast_context := make_ast_context( + document.ast, + document.imports, + document.package_name, + document.uri.uri, + document.fullpath, + ) - position_context, ok := get_document_position_context(document, position, .SignatureHelp) + position_context, ok := get_document_position_context( + document, + position, + .SignatureHelp, + ) if !ok { return signature_help, true @@ -129,12 +150,17 @@ get_signature_information :: proc(document: ^Document, position: common.Position get_globals(document.ast, &ast_context) if position_context.function != nil { - get_locals(document.ast, position_context.function, &ast_context, &position_context) + get_locals( + document.ast, + position_context.function, + &ast_context, + &position_context, + ) } for comma, i in position_context.call_commas { if position_context.position > comma { - signature_help.activeParameter = i+1 + signature_help.activeParameter = i + 1 } else if position_context.position == comma { signature_help.activeParameter = i } @@ -144,20 +170,31 @@ get_signature_information :: proc(document: ^Document, position: common.Position call, ok = resolve_type_expression(&ast_context, position_context.call) if !ok { - return signature_help, true + return signature_help, true } seperate_proc_field_arguments(&call) - signature_information := make([dynamic]SignatureInformation, context.temp_allocator) + signature_information := make( + [dynamic]SignatureInformation, + context.temp_allocator, + ) if value, ok := call.value.(SymbolProcedureValue); ok { - parameters := make([]ParameterInformation, len(value.arg_types), context.temp_allocator) - + parameters := make( + []ParameterInformation, + len(value.arg_types), + context.temp_allocator, + ) + for arg, i in value.arg_types { if arg.type != nil { - if _, is_ellipsis := arg.type.derived.(^ast.Ellipsis); is_ellipsis { - signature_help.activeParameter = min(i, signature_help.activeParameter) + if _, is_ellipsis := arg.type.derived.(^ast.Ellipsis); + is_ellipsis { + signature_help.activeParameter = min( + i, + signature_help.activeParameter, + ) } } @@ -167,10 +204,14 @@ get_signature_information :: proc(document: ^Document, position: common.Position build_procedure_symbol_signature(&call) info := SignatureInformation { - label = concatenate_symbol_information(&ast_context, call, false), + label = concatenate_symbol_information( + &ast_context, + call, + false, + ), documentation = call.doc, - parameters = parameters, - } + parameters = parameters, + } append(&signature_information, info) } else if value, ok := call.value.(SymbolAggregateValue); ok { //function overloaded procedures @@ -178,12 +219,20 @@ get_signature_information :: proc(document: ^Document, position: common.Position symbol := symbol if value, ok := symbol.value.(SymbolProcedureValue); ok { - parameters := make([]ParameterInformation, len(value.arg_types), context.temp_allocator) + parameters := make( + []ParameterInformation, + len(value.arg_types), + context.temp_allocator, + ) - for arg, i in value.arg_types { + for arg, i in value.arg_types { if arg.type != nil { - if _, is_ellipsis := arg.type.derived.(^ast.Ellipsis); is_ellipsis { - signature_help.activeParameter = min(i, signature_help.activeParameter) + if _, is_ellipsis := arg.type.derived.(^ast.Ellipsis); + is_ellipsis { + signature_help.activeParameter = min( + i, + signature_help.activeParameter, + ) } } @@ -193,9 +242,13 @@ get_signature_information :: proc(document: ^Document, position: common.Position build_procedure_symbol_signature(&symbol) info := SignatureInformation { - label = concatenate_symbol_information(&ast_context, symbol, false), + label = concatenate_symbol_information( + &ast_context, + symbol, + false, + ), documentation = symbol.doc, - } + } append(&signature_information, info) } @@ -205,4 +258,4 @@ get_signature_information :: proc(document: ^Document, position: common.Position signature_help.signatures = signature_information[:] return signature_help, true -}
\ No newline at end of file +} diff --git a/src/server/snippets.odin b/src/server/snippets.odin index 94cb919..c8144bb 100644 --- a/src/server/snippets.odin +++ b/src/server/snippets.odin @@ -7,6 +7,14 @@ Snippet_Info :: struct { } snippets: map[string]Snippet_Info = { - "ff" = {insert = "fmt.printf(\"${1:text}\", ${0:args})", packages = []string{"fmt"}, detail = "printf"}, - "fl" = {insert = "fmt.println(\"${1:text}\")", packages = []string{"fmt"}, detail = "println"}, + "ff" = { + insert = "fmt.printf(\"${1:text}\", ${0:args})", + packages = []string{"fmt"}, + detail = "printf", + }, + "fl" = { + insert = "fmt.println(\"${1:text}\")", + packages = []string{"fmt"}, + detail = "println", + }, } diff --git a/src/server/symbol.odin b/src/server/symbol.odin index 4b4eea7..f143e5c 100644 --- a/src/server/symbol.odin +++ b/src/server/symbol.odin @@ -12,7 +12,7 @@ import "shared:common" SymbolAndNode :: struct { symbol: Symbol, - node: ^ast.Node, + node: ^ast.Node, } SymbolStructValue :: struct { @@ -46,7 +46,7 @@ SymbolEnumValue :: struct { SymbolUnionValue :: struct { types: []^ast.Expr, - poly: ^ast.Field_List, + poly: ^ast.Field_List, } SymbolDynamicArrayValue :: struct { @@ -75,7 +75,12 @@ SymbolBitSetValue :: struct { } SymbolUntypedValue :: struct { - type: enum {Integer, Float, String, Bool}, + type: enum { + Integer, + Float, + String, + Bool, + }, } SymbolMapValue :: struct { @@ -122,16 +127,16 @@ SymbolFlag :: enum { SymbolFlags :: bit_set[SymbolFlag] Symbol :: struct { - range: common.Range, //the range of the symbol in the file - uri: string, //uri of the file the symbol resides - pkg: string, //absolute directory path where the symbol resides - name: string, //name of the symbol - doc: string, - signature: string, //type signature - type: SymbolType, - value: SymbolValue, - pointers: int, //how many `^` are applied to the symbol - flags: SymbolFlags, + range: common.Range, //the range of the symbol in the file + uri: string, //uri of the file the symbol resides + pkg: string, //absolute directory path where the symbol resides + name: string, //name of the symbol + doc: string, + signature: string, //type signature + type: SymbolType, + value: SymbolValue, + pointers: int, //how many `^` are applied to the symbol + flags: SymbolFlags, } SymbolType :: enum { @@ -148,7 +153,10 @@ SymbolType :: enum { Unresolved = 1, //Use text if not being able to resolve it. } -new_clone_symbol :: proc(data: Symbol, allocator := context.allocator) -> (^Symbol) { +new_clone_symbol :: proc( + data: Symbol, + allocator := context.allocator, +) -> ^Symbol { new_symbol := new(Symbol, allocator) new_symbol^ = data new_symbol.value = data.value @@ -156,8 +164,10 @@ new_clone_symbol :: proc(data: Symbol, allocator := context.allocator) -> (^Symb } free_symbol :: proc(symbol: Symbol, allocator: mem.Allocator) { - if symbol.signature != "" && symbol.signature != "struct" && - symbol.signature != "union" && symbol.signature != "enum" && + if symbol.signature != "" && + symbol.signature != "struct" && + symbol.signature != "union" && + symbol.signature != "enum" && symbol.signature != "bitset" { delete(symbol.signature, allocator) } @@ -203,4 +213,4 @@ free_symbol :: proc(symbol: Symbol, allocator: mem.Allocator) { common.free_ast(v.value, allocator) case SymbolUntypedValue, SymbolPackageValue: } -}
\ No newline at end of file +} diff --git a/src/server/types.odin b/src/server/types.odin index dcc741a..80f13ad 100644 --- a/src/server/types.odin +++ b/src/server/types.odin @@ -119,7 +119,7 @@ HoverClientCapabilities :: struct { } DocumentSymbolClientCapabilities :: struct { - symbolKind: struct { + symbolKind: struct { valueSet: [dynamic]SymbolKind, }, hierarchicalDocumentSymbolSupport: bool, @@ -147,7 +147,7 @@ CompletionItemCapabilities :: struct { CompletionClientCapabilities :: struct { documentationFormat: [dynamic]string, completionItem: CompletionItemCapabilities, -} +} ParameterInformationCapabilities :: struct { labelOffsetSupport: bool, @@ -155,7 +155,7 @@ ParameterInformationCapabilities :: struct { ClientCapabilities :: struct { textDocument: TextDocumentClientCapabilities, - general: GeneralClientCapabilities, + general: GeneralClientCapabilities, } RangeOptional :: union { @@ -283,7 +283,7 @@ InsertTextFormat :: enum { } InsertTextMode :: enum { - asIs = 1, + asIs = 1, adjustIndentation = 2, } @@ -410,8 +410,8 @@ DocumentLinkParams :: struct { } DocumentLink :: struct { - range: common.Range, - target: string, + range: common.Range, + target: string, tooltip: string, } @@ -424,9 +424,9 @@ PrepareSupportDefaultBehavior :: enum { } RenameClientCapabilities :: struct { - prepareSupport: bool, + prepareSupport: bool, prepareSupportDefaultBehavior: PrepareSupportDefaultBehavior, - honorsChangeAnnotations: bool, + honorsChangeAnnotations: bool, } RenameParams :: struct { @@ -447,10 +447,9 @@ OptionalVersionedTextDocumentIdentifier :: struct { TextDocumentEdit :: struct { textDocument: OptionalVersionedTextDocumentIdentifier, - edits: []TextEdit, + edits: []TextEdit, } WorkspaceEdit :: struct { documentChanges: []TextDocumentEdit, } - diff --git a/src/server/unmarshal.odin b/src/server/unmarshal.odin index 7aba429..bda15a7 100644 --- a/src/server/unmarshal.odin +++ b/src/server/unmarshal.odin @@ -10,7 +10,11 @@ import "core:fmt" Right now union handling is type specific so you can only have one struct type, int type, etc. */ -unmarshal :: proc(json_value: json.Value, v: any, allocator: mem.Allocator) -> json.Marshal_Error { +unmarshal :: proc( + json_value: json.Value, + v: any, + allocator: mem.Allocator, +) -> json.Marshal_Error { using runtime @@ -29,11 +33,18 @@ unmarshal :: proc(json_value: json.Value, v: any, allocator: mem.Allocator) -> j #partial switch variant in type_info.variant { case Type_Info_Struct: for field, i in variant.names { - a := any {rawptr(uintptr(v.data) + uintptr(variant.offsets[i])), variant.types[i].id} + a := any{ + rawptr(uintptr(v.data) + uintptr(variant.offsets[i])), + variant.types[i].id, + } //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 { + if field[len(field) - 1] == '_' { + if ret := unmarshal( + j[field[:len(field) - 1]], + a, + allocator, + ); ret != nil { return ret } } else { @@ -47,31 +58,44 @@ unmarshal :: proc(json_value: json.Value, v: any, allocator: mem.Allocator) -> j case Type_Info_Union: tag_ptr := uintptr(v.data) + variant.tag_offset - tag_any := any {rawptr(tag_ptr), variant.tag_type.id} + tag_any := any{rawptr(tag_ptr), variant.tag_type.id} not_optional := 1 - mem.copy(cast(rawptr)tag_ptr, ¬_optional, size_of(variant.tag_type)) + mem.copy( + cast(rawptr)tag_ptr, + ¬_optional, + size_of(variant.tag_type), + ) id := variant.variants[0].id - unmarshal(json_value, any {v.data, id}, allocator) + unmarshal(json_value, any{v.data, id}, allocator) } case json.Array: #partial switch variant in type_info.variant { case Type_Info_Dynamic_Array: array := (^mem.Raw_Dynamic_Array)(v.data) if array.data == nil { - array.data = mem.alloc(len(j) * variant.elem_size, variant.elem.align, allocator) - array.len = len(j) - array.cap = len(j) + array.data = mem.alloc( + len(j) * variant.elem_size, + variant.elem.align, + allocator, + ) + array.len = len(j) + array.cap = len(j) array.allocator = allocator } else { return .Unsupported_Type } - for i in 0..<array.len { - a := any {rawptr(uintptr(array.data) + uintptr(variant.elem_size * i)), variant.elem.id} + for i in 0 ..< array.len { + a := any{ + rawptr( + uintptr(array.data) + uintptr(variant.elem_size * i), + ), + variant.elem.id, + } if ret := unmarshal(j[i], a, allocator); ret != nil { return ret @@ -91,7 +115,7 @@ unmarshal :: proc(json_value: json.Value, v: any, allocator: mem.Allocator) -> j for name, i in variant.names { lower_name := strings.to_lower(name, allocator) - lower_j := strings.to_lower(string(j), allocator) + lower_j := strings.to_lower(string(j), allocator) if lower_name == lower_j { mem.copy(v.data, &variant.values[i], size_of(variant.base)) @@ -142,20 +166,24 @@ unmarshal :: proc(json_value: json.Value, v: any, allocator: mem.Allocator) -> j case json.Null: case json.Boolean: #partial switch variant in &type_info.variant { - case Type_Info_Boolean: - tmp := bool(j) - mem.copy(v.data, &tmp, type_info.size) - case Type_Info_Union: - tag_ptr := uintptr(v.data) + variant.tag_offset - tag_any := any {rawptr(tag_ptr), variant.tag_type.id} - - not_optional := 1 - - mem.copy(cast(rawptr)tag_ptr, ¬_optional, size_of(variant.tag_type)) - - id := variant.variants[0].id - - unmarshal(json_value, any {v.data, id}, allocator) + case Type_Info_Boolean: + tmp := bool(j) + mem.copy(v.data, &tmp, type_info.size) + case Type_Info_Union: + tag_ptr := uintptr(v.data) + variant.tag_offset + tag_any := any{rawptr(tag_ptr), variant.tag_type.id} + + not_optional := 1 + + mem.copy( + cast(rawptr)tag_ptr, + ¬_optional, + size_of(variant.tag_type), + ) + + id := variant.variants[0].id + + unmarshal(json_value, any{v.data, id}, allocator) } case: return .Unsupported_Type diff --git a/src/server/writer.odin b/src/server/writer.odin index bbd0cac..5c39f69 100644 --- a/src/server/writer.odin +++ b/src/server/writer.odin @@ -15,7 +15,10 @@ Writer :: struct { } make_writer :: proc(writer_fn: WriterFn, writer_context: rawptr) -> Writer { - writer := Writer {writer_context = writer_context, writer_fn = writer_fn} + writer := Writer { + writer_context = writer_context, + writer_fn = writer_fn, + } return writer } diff --git a/src/testing/testing.odin b/src/testing/testing.odin index 5b0e30b..65694e6 100644 --- a/src/testing/testing.odin +++ b/src/testing/testing.odin @@ -12,13 +12,13 @@ import "shared:server" import "shared:common" Package :: struct { - pkg: string, - source: string, + pkg: string, + source: string, } Source :: struct { main: string, - packages: [] Package, + packages: []Package, document: ^server.Document, collections: map[string]string, config: common.Config, @@ -27,261 +27,360 @@ Source :: struct { @(private) setup :: proc(src: ^Source) { - src.main = strings.clone(src.main); - src.document = new(server.Document, context.temp_allocator); - src.document.uri = common.create_uri("test/test.odin", context.temp_allocator); - src.document.client_owned = true; - src.document.text = transmute([]u8)src.main; - src.document.used_text = len(src.document.text); - src.document.allocator = new(common.Scratch_Allocator); - src.document.package_name = "test"; - - common.scratch_allocator_init(src.document.allocator, mem.Kilobyte * 200, context.temp_allocator); + src.main = strings.clone(src.main) + src.document = new(server.Document, context.temp_allocator) + src.document.uri = common.create_uri( + "test/test.odin", + context.temp_allocator, + ) + src.document.client_owned = true + src.document.text = transmute([]u8)src.main + src.document.used_text = len(src.document.text) + src.document.allocator = new(common.Scratch_Allocator) + src.document.package_name = "test" + + common.scratch_allocator_init( + src.document.allocator, + mem.Kilobyte * 200, + context.temp_allocator, + ) //no unicode in tests currently - current, last: u8; - current_line, current_character: int; + current, last: u8 + current_line, current_character: int for current_index := 0; current_index < len(src.main); current_index += 1 { - current = src.main[current_index]; + current = src.main[current_index] if last == '\r' { - current_line += 1; - current_character = 0; + current_line += 1 + current_character = 0 } else if current == '\n' { - current_line += 1; - current_character = 0; + current_line += 1 + current_character = 0 } else if current == '*' { - dst_slice := transmute([]u8)src.main[current_index:]; - src_slice := transmute([]u8)src.main[current_index + 1:]; - copy(dst_slice, src_slice); - src.position.character = current_character; - src.position.line = current_line; - break; + dst_slice := transmute([]u8)src.main[current_index:] + src_slice := transmute([]u8)src.main[current_index + 1:] + copy(dst_slice, src_slice) + src.position.character = current_character + src.position.line = current_line + break } else { - current_character += 1; + current_character += 1 } - last = current; + last = current } server.setup_index() - + server.document_setup(src.document) - server.document_refresh(src.document, &src.config, nil); - + server.document_refresh(src.document, &src.config, nil) + /* There is a lot code here that is used in the real code, then i'd like to see. */ for src_pkg in src.packages { - uri := common.create_uri(fmt.aprintf("test/%v/package.odin", src_pkg.pkg), context.temp_allocator); + uri := common.create_uri( + fmt.aprintf("test/%v/package.odin", src_pkg.pkg), + context.temp_allocator, + ) - fullpath := uri.path; + fullpath := uri.path p := parser.Parser { //err = parser.default_error_handler, - err = server.log_error_handler, + err = server.log_error_handler, warn = server.log_warning_handler, - }; + } - dir := filepath.base(filepath.dir(fullpath, context.temp_allocator)); + dir := filepath.base(filepath.dir(fullpath, context.temp_allocator)) - pkg := new(ast.Package); - pkg.kind = .Normal; - pkg.fullpath = fullpath; - pkg.name = dir; + pkg := new(ast.Package) + pkg.kind = .Normal + pkg.fullpath = fullpath + pkg.name = dir if dir == "runtime" { - pkg.kind = .Runtime; + pkg.kind = .Runtime } - + file := ast.File { fullpath = fullpath, - src = src_pkg.source, - pkg = pkg, - }; + src = src_pkg.source, + pkg = pkg, + } - ok := parser.parse_file(&p, &file); + ok := parser.parse_file(&p, &file) if !ok || file.syntax_error_count > 0 { - panic("Parser error in test package source"); + panic("Parser error in test package source") } - if ret := server.collect_symbols(&server.indexer.index.collection, file, uri.uri); ret != .None { - return; + if ret := server.collect_symbols( + &server.indexer.index.collection, + file, + uri.uri, + ); + ret != .None { + return } } } -@private +@(private) teardown :: proc(src: ^Source) { server.free_index() server.indexer.index = {} } -expect_signature_labels :: proc(t: ^testing.T, src: ^Source, expect_labels: []string) { - setup(src); - defer teardown(src); +expect_signature_labels :: proc( + t: ^testing.T, + src: ^Source, + expect_labels: []string, +) { + setup(src) + defer teardown(src) - help, ok := server.get_signature_information(src.document, src.position); + help, ok := server.get_signature_information(src.document, src.position) if !ok { - testing.error(t, "Failed get_signature_information"); + testing.error(t, "Failed get_signature_information") } if len(expect_labels) == 0 && len(help.signatures) > 0 { - testing.errorf(t, "Expected empty signature label, but received %v", help.signatures); + testing.errorf( + t, + "Expected empty signature label, but received %v", + help.signatures, + ) } - flags := make([]int, len(expect_labels)); + flags := make([]int, len(expect_labels)) for expect_label, i in expect_labels { for signature, j in help.signatures { if expect_label == signature.label { - flags[i] += 1; + flags[i] += 1 } } } for flag, i in flags { if flag != 1 { - testing.errorf(t, "Expected signature label %v, but received %v", expect_labels[i], help.signatures); + testing.errorf( + t, + "Expected signature label %v, but received %v", + expect_labels[i], + help.signatures, + ) } } } -expect_signature_parameter_position :: proc(t: ^testing.T, src: ^Source, position: int) { - setup(src); - defer teardown(src); +expect_signature_parameter_position :: proc( + t: ^testing.T, + src: ^Source, + position: int, +) { + setup(src) + defer teardown(src) - help, ok := server.get_signature_information(src.document, src.position); + help, ok := server.get_signature_information(src.document, src.position) if help.activeParameter != position { - testing.errorf(t, "expected parameter position %v, but received %v", position, help.activeParameter); + testing.errorf( + t, + "expected parameter position %v, but received %v", + position, + help.activeParameter, + ) } } -expect_completion_labels :: proc(t: ^testing.T, src: ^Source, trigger_character: string, expect_labels: []string) { - setup(src); - defer teardown(src); +expect_completion_labels :: proc( + t: ^testing.T, + src: ^Source, + trigger_character: string, + expect_labels: []string, +) { + setup(src) + defer teardown(src) completion_context := server.CompletionContext { triggerCharacter = trigger_character, - }; + } - completion_list, ok := server.get_completion_list(src.document, src.position, completion_context); + completion_list, ok := server.get_completion_list( + src.document, + src.position, + completion_context, + ) if !ok { - testing.error(t, "Failed get_completion_list"); + testing.error(t, "Failed get_completion_list") } if len(expect_labels) == 0 && len(completion_list.items) > 0 { - testing.errorf(t, "Expected empty completion label, but received %v", completion_list.items); + testing.errorf( + t, + "Expected empty completion label, but received %v", + completion_list.items, + ) } - flags := make([]int, len(expect_labels)); + flags := make([]int, len(expect_labels)) for expect_label, i in expect_labels { for completion, j in completion_list.items { if expect_label == completion.label { - flags[i] += 1; + flags[i] += 1 } } } for flag, i in flags { if flag != 1 { - testing.errorf(t, "Expected completion detail %v, but received %v", expect_labels[i], completion_list.items); + testing.errorf( + t, + "Expected completion detail %v, but received %v", + expect_labels[i], + completion_list.items, + ) } } } -expect_completion_details :: proc(t: ^testing.T, src: ^Source, trigger_character: string, expect_details: []string) { - setup(src); - defer teardown(src); +expect_completion_details :: proc( + t: ^testing.T, + src: ^Source, + trigger_character: string, + expect_details: []string, +) { + setup(src) + defer teardown(src) completion_context := server.CompletionContext { triggerCharacter = trigger_character, - }; + } - completion_list, ok := server.get_completion_list(src.document, src.position, completion_context); + completion_list, ok := server.get_completion_list( + src.document, + src.position, + completion_context, + ) if !ok { - testing.error(t, "Failed get_completion_list"); + testing.error(t, "Failed get_completion_list") } if len(expect_details) == 0 && len(completion_list.items) > 0 { - testing.errorf(t, "Expected empty completion label, but received %v", completion_list.items); + testing.errorf( + t, + "Expected empty completion label, but received %v", + completion_list.items, + ) } - flags := make([]int, len(expect_details)); + flags := make([]int, len(expect_details)) for expect_detail, i in expect_details { for completion, j in completion_list.items { if expect_detail == completion.detail { - flags[i] += 1; + flags[i] += 1 } } } for flag, i in flags { if flag != 1 { - testing.errorf(t, "Expected completion label %v, but received %v", expect_details[i], completion_list.items); + testing.errorf( + t, + "Expected completion label %v, but received %v", + expect_details[i], + completion_list.items, + ) } } } -expect_hover :: proc(t: ^testing.T, src: ^Source, expect_hover_string: string) { - setup(src); - defer teardown(src); +expect_hover :: proc( + t: ^testing.T, + src: ^Source, + expect_hover_string: string, +) { + setup(src) + defer teardown(src) - hover, _, ok := server.get_hover_information(src.document, src.position); + hover, _, ok := server.get_hover_information(src.document, src.position) if !ok { - testing.error(t, "Failed get_hover_information"); + testing.error(t, "Failed get_hover_information") } if expect_hover_string == "" && hover.contents.value != "" { - testing.errorf(t, "Expected empty hover string, but received %v", hover.contents.value); + testing.errorf( + t, + "Expected empty hover string, but received %v", + hover.contents.value, + ) } if !strings.contains(hover.contents.value, expect_hover_string) { - testing.errorf(t, "Expected hover string %v, but received %v", expect_hover_string, hover.contents.value); + testing.errorf( + t, + "Expected hover string %v, but received %v", + expect_hover_string, + hover.contents.value, + ) } } -expect_definition_locations :: proc(t: ^testing.T, src: ^Source, expect_locations: []common.Location) { - setup(src); - defer teardown(src); +expect_definition_locations :: proc( + t: ^testing.T, + src: ^Source, + expect_locations: []common.Location, +) { + setup(src) + defer teardown(src) - locations, ok := server.get_definition_location(src.document, src.position); + locations, ok := server.get_definition_location(src.document, src.position) if !ok { - testing.error(t, "Failed get_definition_location"); + testing.error(t, "Failed get_definition_location") } if len(expect_locations) == 0 && len(locations) > 0 { - testing.errorf(t, "Expected empty locations, but received %v", locations); + testing.errorf( + t, + "Expected empty locations, but received %v", + locations, + ) } - flags := make([]int, len(expect_locations)); + flags := make([]int, len(expect_locations)) for expect_location, i in expect_locations { for location, j in locations { if location == expect_location { - flags[i] += 1; + flags[i] += 1 } } } for flag, i in flags { if flag != 1 { - testing.errorf(t, "Expected location %v, but received %v", expect_locations[i], locations); + testing.errorf( + t, + "Expected location %v, but received %v", + expect_locations[i], + locations, + ) } } } diff --git a/tools/odinfmt/main.odin b/tools/odinfmt/main.odin index 60e4f82..52ecdaa 100644 --- a/tools/odinfmt/main.odin +++ b/tools/odinfmt/main.odin @@ -23,134 +23,157 @@ print_help :: proc(args: []string) { print_arg_error :: proc(args: []string, error: flag.Flag_Error) { switch error { case .None: - print_help(args); + print_help(args) case .No_Base_Struct: - fmt.eprintln(args[0], "no base struct"); + fmt.eprintln(args[0], "no base struct") case .Arg_Error: - fmt.eprintln(args[0], "argument error"); + fmt.eprintln(args[0], "argument error") case .Arg_Unsupported_Field_Type: - fmt.eprintln(args[0], "argument: unsupported field type"); + fmt.eprintln(args[0], "argument: unsupported field type") case .Arg_Not_Defined: - fmt.eprintln(args[0], "argument: no defined"); + fmt.eprintln(args[0], "argument: no defined") case .Arg_Non_Optional: - fmt.eprintln(args[0], "argument: non optional"); + fmt.eprintln(args[0], "argument: non optional") case .Value_Parse_Error: - fmt.eprintln(args[0], "argument: value parse error"); + fmt.eprintln(args[0], "argument: value parse error") case .Tag_Error: - fmt.eprintln(args[0], "argument: tag error"); + fmt.eprintln(args[0], "argument: tag error") } } -format_file :: proc(filepath: string, config: printer.Config, allocator := context.allocator) -> (string, bool) { +format_file :: proc( + filepath: string, + config: printer.Config, + allocator := context.allocator, +) -> ( + string, + bool, +) { if data, ok := os.read_entire_file(filepath, allocator); ok { - return format.format(filepath, string(data), config, {.Optional_Semicolons}, allocator); + return format.format( + filepath, + string(data), + config, + {.Optional_Semicolons}, + allocator, + ) } else { - return "", false; + return "", false } } -files: [dynamic]string; +files: [dynamic]string -walk_files :: proc(info: os.File_Info, in_err: os.Errno) -> (err: os.Errno, skip_dir: bool) { +walk_files :: proc( + info: os.File_Info, + in_err: os.Errno, +) -> ( + err: os.Errno, + skip_dir: bool, +) { if info.is_dir { - return 0, false; + return 0, false } if filepath.ext(info.name) != ".odin" { - return 0, false; + return 0, false } - append(&files, strings.clone(info.fullpath)); + append(&files, strings.clone(info.fullpath)) - return 0, false; + return 0, false } main :: proc() { - arena: mem.Arena; - mem.init_arena(&arena, make([]byte, 50 * mem.Megabyte)); + arena: mem.Arena + mem.init_arena(&arena, make([]byte, 50 * mem.Megabyte)) - arena_allocator := mem.arena_allocator(&arena); + arena_allocator := mem.arena_allocator(&arena) - init_global_temporary_allocator(mem.Megabyte*20) //enough space for the walk + init_global_temporary_allocator(mem.Megabyte * 20) //enough space for the walk - args: Args; + args: Args if len(os.args) < 2 { - print_help(os.args); - os.exit(1); + print_help(os.args) + os.exit(1) } if res := flag.parse(args, os.args[1:len(os.args) - 1]); res != .None { - print_arg_error(os.args, res); - os.exit(1); + print_arg_error(os.args, res) + os.exit(1) } - path := os.args[len(os.args) - 1]; + path := os.args[len(os.args) - 1] - tick_time := time.tick_now(); + tick_time := time.tick_now() - write_failure := false; + write_failure := false watermark := 0 if os.is_file(path) { - config := format.find_config_file_or_default(path); + config := format.find_config_file_or_default(path) if _, ok := args.write.(bool); ok { - backup_path := strings.concatenate({path, "_bk"}); - defer delete(backup_path); + backup_path := strings.concatenate({path, "_bk"}) + defer delete(backup_path) if data, ok := format_file(path, config, arena_allocator); ok { - os.rename(path, backup_path); + os.rename(path, backup_path) if os.write_entire_file(path, transmute([]byte)data) { - os.remove(backup_path); + os.remove(backup_path) } } else { - fmt.eprintf("Failed to write %v", path); - write_failure = true; + fmt.eprintf("Failed to write %v", path) + write_failure = true } } else { if data, ok := format_file(path, config, arena_allocator); ok { - fmt.println(data); + fmt.println(data) } } } else if os.is_dir(path) { - config := format.find_config_file_or_default(path); - filepath.walk(path, walk_files); + config := format.find_config_file_or_default(path) + filepath.walk(path, walk_files) for file in files { - fmt.println(file); + fmt.println(file) - backup_path := strings.concatenate({file, "_bk"}); - defer delete(backup_path); + backup_path := strings.concatenate({file, "_bk"}) + defer delete(backup_path) if data, ok := format_file(file, config, arena_allocator); ok { if _, ok := args.write.(bool); ok { - os.rename(file, backup_path); + os.rename(file, backup_path) if os.write_entire_file(file, transmute([]byte)data) { - os.remove(backup_path); + os.remove(backup_path) } } else { - fmt.println(data); + fmt.println(data) } } else { - fmt.eprintf("Failed to format %v", file); - write_failure = true; + fmt.eprintf("Failed to format %v", file) + write_failure = true } watermark = max(watermark, arena.offset) - free_all(arena_allocator); + free_all(arena_allocator) } - - fmt.printf("Formatted %v files in %vms \n", len(files), time.duration_milliseconds(time.tick_lap_time(&tick_time))); + + fmt.printf( + "Formatted %v files in %vms \n", + len(files), + time.duration_milliseconds(time.tick_lap_time(&tick_time)), + ) fmt.printf("Peak memory used: %v \n", watermark / mem.Megabyte) } else { - fmt.eprintf("%v is neither a directory nor a file \n", path); - os.exit(1); + fmt.eprintf("%v is neither a directory nor a file \n", path) + os.exit(1) } - os.exit(1 if write_failure else 0); + os.exit(1 if write_failure else 0) } diff --git a/tools/odinfmt/snapshot/snapshot.odin b/tools/odinfmt/snapshot/snapshot.odin index 2f658a5..d5bdbd2 100644 --- a/tools/odinfmt/snapshot/snapshot.odin +++ b/tools/odinfmt/snapshot/snapshot.odin @@ -1,4 +1,4 @@ -package odinfmt_testing +package odinfmt_testing import "core:testing" import "core:os" @@ -9,15 +9,27 @@ import "core:fmt" import "shared:odin/format" -format_file :: proc(filepath: string, allocator := context.allocator) -> (string, bool) { +format_file :: proc( + filepath: string, + allocator := context.allocator, +) -> ( + string, + bool, +) { style := format.default_style style.character_width = 80 style.newline_style = .LF //We want to make sure it works on linux and windows. - if data, ok := os.read_entire_file(filepath, allocator); ok { - return format.format(filepath, string(data), style, {.Optional_Semicolons}, allocator); + if data, ok := os.read_entire_file(filepath, allocator); ok { + return format.format( + filepath, + string(data), + style, + {.Optional_Semicolons}, + allocator, + ) } else { - return "", false; + return "", false } } @@ -28,7 +40,7 @@ snapshot_directory :: proc(directory: string) -> bool { fmt.eprintf("Error in globbing directory: %v", directory) } - for match in matches { + for match in matches { if strings.contains(match, ".odin") { snapshot_file(match) or_return } @@ -49,20 +61,30 @@ snapshot_file :: proc(path: string) -> bool { fmt.printf("Testing snapshot %v", path) - snapshot_path := filepath.join(elems = {filepath.dir(path, context.temp_allocator), "/.snapshots", filepath.base(path)}, allocator = context.temp_allocator); + snapshot_path := filepath.join( + elems = { + filepath.dir(path, context.temp_allocator), + "/.snapshots", + filepath.base(path), + }, + allocator = context.temp_allocator, + ) formatted, ok := format_file(path, context.temp_allocator) if !ok { - fmt.eprintf("Format failed on file %v", path) + fmt.eprintf("Format failed on file %v", path) return false } if os.exists(snapshot_path) { - if snapshot_data, ok := os.read_entire_file(snapshot_path, context.temp_allocator); ok { - snapshot_scanner := scanner.Scanner {} + if snapshot_data, ok := os.read_entire_file( + snapshot_path, + context.temp_allocator, + ); ok { + snapshot_scanner := scanner.Scanner{} scanner.init(&snapshot_scanner, string(snapshot_data)) - formatted_scanner := scanner.Scanner {} + formatted_scanner := scanner.Scanner{} scanner.init(&formatted_scanner, string(formatted)) for { s_ch := scanner.next(&snapshot_scanner) @@ -75,7 +97,7 @@ snapshot_file :: proc(path: string) -> bool { if scanner.peek(&snapshot_scanner) == '\n' { s_ch = scanner.next(&snapshot_scanner) } - } + } if f_ch == '\r' { if scanner.peek(&formatted_scanner) == '\n' { f_ch = scanner.next(&formatted_scanner) @@ -83,8 +105,14 @@ snapshot_file :: proc(path: string) -> bool { } if s_ch != f_ch { - fmt.eprintf("\nFormatted file was different from snapshot file: %v", snapshot_path) - os.write_entire_file(fmt.tprintf("%v_failed", snapshot_path), transmute([]u8)formatted) + fmt.eprintf( + "\nFormatted file was different from snapshot file: %v", + snapshot_path, + ) + os.write_entire_file( + fmt.tprintf("%v_failed", snapshot_path), + transmute([]u8)formatted, + ) return false } } diff --git a/tools/odinfmt/tests.odin b/tools/odinfmt/tests.odin index 8bd0399..313e33c 100644 --- a/tools/odinfmt/tests.odin +++ b/tools/odinfmt/tests.odin @@ -9,10 +9,10 @@ import "snapshot" main :: proc() { - init_global_temporary_allocator(mem.Megabyte*100) - + init_global_temporary_allocator(mem.Megabyte * 100) + if !snapshot.snapshot_directory("tests") { os.exit(1) - } + } } |