From 1f563f2810e55fd2fefff6b29b64be9d2bf7d4e4 Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Wed, 14 Apr 2021 15:34:50 +0200 Subject: [PATCH] work on switch alignment --- core/odin/printer/printer.odin | 131 +++++++++++++++++++++++++++++++-- core/odin/printer/visit.odin | 32 ++++++-- 2 files changed, 149 insertions(+), 14 deletions(-) diff --git a/core/odin/printer/printer.odin b/core/odin/printer/printer.odin index bc2a0a913..f9610682f 100644 --- a/core/odin/printer/printer.odin +++ b/core/odin/printer/printer.odin @@ -8,7 +8,7 @@ import "core:fmt" import "core:unicode/utf8" import "core:mem" -Line_Type_Enum :: enum{Line_Comment, Value_Decl}; +Line_Type_Enum :: enum{Line_Comment, Value_Decl, Switch_Stmt}; Line_Type :: bit_set[Line_Type_Enum]; @@ -24,6 +24,7 @@ Format_Token :: struct { kind: tokenizer.Token_Kind, text: string, spaces_before: int, + parameter_count: int, } Printer :: struct { @@ -58,6 +59,7 @@ Config :: struct { align_assignments: bool, align_style: Alignment_Style, indent_cases: bool, + newline_style: Newline_Style, } Brace_Style :: enum { @@ -73,6 +75,7 @@ Block_Type :: enum { Proc, Generic, Comp_Lit, + Switch_Stmt, } Alignment_Style :: enum { @@ -80,6 +83,11 @@ Alignment_Style :: enum { Align_On_Type_And_Equals, } +Newline_Style :: enum { + CRLF, + LF, +} + default_style := Config { spaces = 4, newline_limit = 2, @@ -126,17 +134,25 @@ print :: proc(p: ^Printer, file: ^ast.File) -> string { fix_lines(p); - builder := strings.make_builder(p.allocator); + builder := strings.make_builder(0, mem.megabytes(5), p.allocator); last_line := 0; + newline: string; + + if p.config.newline_style == .LF { + newline = "\n"; + } else { + newline = "\r\n"; + } + 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 < diff_line; i += 1 { + strings.write_string(&builder, newline); + } + if p.config.tabs { for i := 0; i < line.depth; i += 1 { strings.write_byte(&builder, '\t'); @@ -167,17 +183,118 @@ print :: proc(p: ^Printer, file: ^ast.File) -> string { } fix_lines :: proc(p: ^Printer) { - align_comments(p); align_var_decls(p); align_blocks(p); + align_comments(p); //align them last since they rely on the other alignments } align_var_decls :: proc(p: ^Printer) { } +align_switch_smt :: proc(p: ^Printer, index: int) { + + switch_found := false; + brace_token: Format_Token; + brace_line: int; + + found_switch_brace: for line, line_index in p.lines[index:] { + + for format_token in line.format_tokens { + + if format_token.kind == .Open_Brace && switch_found { + brace_token = format_token; + brace_line = line_index; + break found_switch_brace; + } else if format_token.kind == .Open_Brace { + break; + } else if format_token.kind == .Switch { + switch_found = true; + } + + } + + } + + if !switch_found { + return; + } + + largest := 0; + + //find all the switch cases that are one lined + for line, line_index in p.lines[brace_line+1:] { + + case_found := false; + colon_found := false; + length := 0; + + for format_token in line.format_tokens { + + if format_token.kind == .Comment { + continue; + } + + //this will only happen if the case is one lined + if case_found && colon_found { + largest = max(length, largest); + break; + } + + if format_token.kind == .Case { + case_found = true; + } else if format_token.kind == .Colon { + colon_found = true; + } + + length += len(format_token.text) + format_token.spaces_before; + } + } + + for line, line_index in p.lines[brace_line+1:] { + + case_found := false; + colon_found := false; + length := 0; + + for format_token, i in line.format_tokens { + + if format_token.kind == .Comment { + continue; + } + + //this will only happen if the case is one lined + if case_found && colon_found { + line.format_tokens[i].spaces_before += (largest - length); + break; + } + + if format_token.kind == .Case { + case_found = true; + } else if format_token.kind == .Colon { + colon_found = true; + } + + length += len(format_token.text) + format_token.spaces_before; + } + } + +} + align_blocks :: proc(p: ^Printer) { + for line, line_index in p.lines { + + if len(line.format_tokens) <= 0 { + continue; + } + + if .Switch_Stmt in line.types { + align_switch_smt(p, line_index); + } + + } + } align_comments :: proc(p: ^Printer) { diff --git a/core/odin/printer/visit.odin b/core/odin/printer/visit.odin index 8899b8e5f..6afc04a61 100644 --- a/core/odin/printer/visit.odin +++ b/core/odin/printer/visit.odin @@ -9,6 +9,7 @@ import "core:unicode/utf8" import "core:mem" import "core:sort" +//right the attribute order is not linearly parsed(bug?) @(private) sort_attribute :: proc(s: ^[dynamic]^ast.Attribute) -> sort.Interface { return sort.Interface { @@ -209,8 +210,11 @@ append_format_token :: proc(p: ^Printer, format_token: Format_Token) -> ^Format_ push_comments(p, p.source_position); unwrapped_line := p.current_line; - unwrapped_line.used = true; - unwrapped_line.depth = p.depth; + + if !unwrapped_line.used { + unwrapped_line.used = true; + unwrapped_line.depth = p.depth; + } if len(unwrapped_line.format_tokens) == 0 && format_token.spaces_before == 1 { format_token.spaces_before = 0; @@ -223,6 +227,11 @@ append_format_token :: proc(p: ^Printer, format_token: Format_Token) -> ^Format_ return &unwrapped_line.format_tokens[len(unwrapped_line.format_tokens)-1]; } +@(private) +push_format_token :: proc(p: ^Printer, format_token: Format_Token) { + p.last_token = append_format_token(p, format_token); +} + @(private) push_generic_token :: proc(p: ^Printer, kind: tokenizer.Token_Kind, spaces_before: int, value := "") { @@ -541,7 +550,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener if v.pos.line == v.end.line && len(v.stmts) > 1 && p.config.split_multiple_stmts { if !empty_block { - visit_begin_brace(p, v.pos, block_type); + visit_begin_brace(p, v.pos, block_type, len(v.stmts)); } set_source_position(p, v.pos); @@ -569,7 +578,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener } } else { if !empty_block { - visit_begin_brace(p, v.pos, block_type); + visit_begin_brace(p, v.pos, block_type, len(v.stmts)); } set_source_position(p, v.pos); @@ -644,6 +653,8 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener push_generic_token(p, .Switch, 1); + hint_current_line(p, {.Switch_Stmt}); + if v.init != nil { p.skip_semicolon = true; visit_stmt(p, v.init); @@ -1201,7 +1212,7 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr) { } -visit_begin_brace :: proc(p: ^Printer, begin: tokenizer.Pos, type: Block_Type) { +visit_begin_brace :: proc(p: ^Printer, begin: tokenizer.Pos, type: Block_Type, count := 0) { set_source_position(p, begin); @@ -1209,12 +1220,19 @@ visit_begin_brace :: proc(p: ^Printer, begin: tokenizer.Pos, type: Block_Type) { newline_braced |= p.config.brace_style == .K_And_R && type == .Proc; newline_braced &= p.config.brace_style != ._1TBS; + format_token := Format_Token { + kind = .Open_Brace, + parameter_count = count, + text = "{", + }; + if newline_braced { newline_position(p, 1); - push_generic_token(p, .Open_Brace, 0); + push_format_token(p, format_token); indent(p); } else { - push_generic_token(p, .Open_Brace, 1); + format_token.spaces_before = 1; + push_format_token(p, format_token); indent(p); } }