Browse Source

work on switch alignment

Daniel Gavin 4 years ago
parent
commit
1f563f2810
2 changed files with 149 additions and 14 deletions
  1. 124 7
      core/odin/printer/printer.odin
  2. 25 7
      core/odin/printer/visit.odin

+ 124 - 7
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) {

+ 25 - 7
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);
 	}
 }