diff --git a/core/odin/printer/printer.odin b/core/odin/printer/printer.odin index 7786de2b4..67b494f2c 100644 --- a/core/odin/printer/printer.odin +++ b/core/odin/printer/printer.odin @@ -8,11 +8,16 @@ import "core:fmt" import "core:unicode/utf8" import "core:mem" +Line_Type_Enum :: enum{Line_Comment, Value_Decl}; + +Line_Type :: bit_set[Line_Type_Enum]; + Line :: struct { format_tokens: [dynamic] Format_Token, finalized: bool, used: bool, depth: int, + types: Line_Type, } Format_Token :: struct { @@ -31,7 +36,7 @@ Printer :: struct { file: ^ast.File, source_position: tokenizer.Pos, last_source_position: tokenizer.Pos, - lines: map [int]^Line, + lines: [dynamic] Line, //need to look into a better data structure, one that can handle inserting lines rather than appending skip_semicolon: bool, current_line: ^Line, current_line_index: int, @@ -80,7 +85,7 @@ default_style := Config { newline_limit = 2, convert_do = false, semicolons = true, - tabs = true, + tabs = false, brace_style = ._1TBS, split_multiple_stmts = true, align_assignments = true, @@ -99,6 +104,15 @@ make_printer :: proc(config: Config, allocator := context.allocator) -> Printer print :: proc(p: ^Printer, file: ^ast.File) -> string { p.comments = file.comments; + + if len(file.decls) > 0 { + p.lines = make([dynamic] Line, 0, (file.decls[len(file.decls)-1].end.line - file.decls[0].pos.line) * 2, context.temp_allocator); + } + + set_line(p, 0); + + push_generic_token(p, .Package, 0); + push_ident_token(p, file.pkg_name, 1); for decl in file.decls { visit_decl(p, cast(^ast.Decl)decl); @@ -110,22 +124,28 @@ print :: proc(p: ^Printer, file: ^ast.File) -> string { last_line := 0; - for key, value in p.lines { - diff_line := key - last_line; - + for line, line_index in p.lines { + diff_line := line_index - last_line; + for i := 0; i < diff_line; i += 1 { strings.write_byte(&builder, '\n'); } - for i := 0; i < value.depth * 4; i += 1 { - strings.write_byte(&builder, ' '); + if p.config.tabs { + for i := 0; i < line.depth; i += 1 { + strings.write_byte(&builder, '\t'); + } + } else { + for i := 0; i < line.depth * p.config.spaces; i += 1 { + strings.write_byte(&builder, ' '); + } } if p.debug { - strings.write_string(&builder, fmt.tprintf("line %v: ", key)); + strings.write_string(&builder, fmt.tprintf("line %v: ", line_index)); } - for format_token in value.format_tokens { + for format_token in line.format_tokens { for i := 0; i < format_token.spaces_before; i += 1 { strings.write_byte(&builder, ' '); @@ -134,23 +154,95 @@ print :: proc(p: ^Printer, file: ^ast.File) -> string { strings.write_string(&builder, format_token.text); } - last_line = key; + last_line = line_index; } return strings.to_string(builder); } fix_lines :: proc(p: ^Printer) { + align_comments(p); + align_var_decls(p); +} - for key, value in p.lines { +align_var_decls :: proc(p: ^Printer) { - if len(value.format_tokens) <= 0 { +} + +align_comments :: proc(p: ^Printer) { + + Comment_Align_Info :: struct { + length: int, + begin: int, + end: int, + }; + + comment_infos := make([dynamic]Comment_Align_Info, 0, context.temp_allocator); + + current_info: Comment_Align_Info; + + for line, line_index in p.lines { + + if len(line.format_tokens) <= 0 { continue; } + if .Line_Comment in line.types { + if current_info.end + 1 != line_index { + + if (current_info.begin != 0 && current_info.end != 0) || current_info.length > 0 { + append(&comment_infos, current_info); + } + + current_info.begin = line_index; + current_info.end = line_index; + current_info.length = 0; + } + + length := 0; + + for format_token, i in line.format_tokens { + + if format_token.kind == .Comment { + current_info.length = max(current_info.length, length); + current_info.end = line_index; + } + + length += format_token.spaces_before + len(format_token.text); + } + + } } + if (current_info.begin != 0 && current_info.end != 0) || current_info.length > 0 { + append(&comment_infos, current_info); + } -} + for info in comment_infos { + + for i := info.begin; i <= info.end; i += 1 { + + l := p.lines[i]; + + length := 0; + + for format_token, i in l.format_tokens { + + if format_token.kind == .Comment { + if len(l.format_tokens) == 1 { + l.format_tokens[i].spaces_before += info.length + 1; + } else { + l.format_tokens[i].spaces_before += info.length - length; + } + } + + length += format_token.spaces_before + len(format_token.text); + } + + } + + } + +} \ No newline at end of file diff --git a/core/odin/printer/visit.odin b/core/odin/printer/visit.odin index ebd2a98ce..f9a2b59d6 100644 --- a/core/odin/printer/visit.odin +++ b/core/odin/printer/visit.odin @@ -27,7 +27,7 @@ next_comment_group :: proc(p: ^Printer) { } @(private) -write_comment :: proc(p: ^Printer, comment: tokenizer.Token) -> int { +push_comment :: proc(p: ^Printer, comment: tokenizer.Token) -> int { if len(comment.text) == 0 { return 0; @@ -50,6 +50,8 @@ write_comment :: proc(p: ^Printer, comment: tokenizer.Token) -> int { append(&p.current_line.format_tokens, format_token); p.last_token = &p.current_line.format_tokens[len(p.current_line.format_tokens)-1]; + hint_current_line(p, {.Line_Comment}); + return 0; } else { @@ -132,7 +134,7 @@ write_comment :: proc(p: ^Printer, comment: tokenizer.Token) -> int { } @(private) -write_comments :: proc(p: ^Printer, pos: tokenizer.Pos, format_token: Format_Token) { +push_comments :: proc(p: ^Printer, pos: tokenizer.Pos, format_token: Format_Token) { prev_comment: ^tokenizer.Token; prev_comment_lines: int; @@ -152,7 +154,7 @@ write_comments :: proc(p: ^Printer, pos: tokenizer.Pos, format_token: Format_Tok newline_position(p, min(p.config.newline_limit, comment.pos.line - prev_comment.pos.line - prev_comment_lines)); } - prev_comment_lines = write_comment(p, comment); + prev_comment_lines = push_comment(p, comment); prev_comment = &comment_group.list[i]; } @@ -181,7 +183,7 @@ append_format_token :: proc(p: ^Printer, format_token: Format_Token) -> ^Format_ p.space_next_token = false; } - write_comments(p, p.source_position, format_token); + push_comments(p, p.source_position, format_token); unwrapped_line := p.current_line; unwrapped_line.used = true; @@ -262,12 +264,15 @@ set_line :: proc(p: ^Printer, line: int) -> ^Line { unwrapped_line: ^Line; - if line not_in p.lines { - unwrapped_line = new(Line, p.allocator); - unwrapped_line.format_tokens = make([dynamic] Format_Token, 0, 50, p.allocator); - p.lines[line] = unwrapped_line; + if line >= len(p.lines) { + for i := len(p.lines); i <= line; i += 1 { + new_line: Line; + new_line.format_tokens = make([dynamic] Format_Token, 0, 50, p.allocator); + append(&p.lines, new_line); + } + unwrapped_line = &p.lines[line]; } else { - unwrapped_line = p.lines[line]; + unwrapped_line = &p.lines[line]; } p.current_line = unwrapped_line; @@ -297,10 +302,16 @@ merge_next_token :: proc(p: ^Printer) { p.merge_next_token = true; } +@(private) space_next_token :: proc(p: ^Printer) { p.space_next_token = true; } +@(private) +hint_current_line :: proc(p: ^Printer, hint: Line_Type) { + p.current_line.types |= hint; +} + @(private) visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) {