diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/odin/printer/document.odin | 66 | ||||
| -rw-r--r-- | src/odin/printer/printer.odin | 7 | ||||
| -rw-r--r-- | src/odin/printer/visit.odin | 30 |
3 files changed, 80 insertions, 23 deletions
diff --git a/src/odin/printer/document.odin b/src/odin/printer/document.odin index 1e5ce3a..d77a490 100644 --- a/src/odin/printer/document.odin +++ b/src/odin/printer/document.odin @@ -13,6 +13,7 @@ Document :: union { Document_Cons, Document_If_Break, Document_Align, + Document_Nest_If_Break, } Document_Nil :: struct { @@ -33,6 +34,13 @@ Document_Nest :: struct { document: ^Document, } +Document_Nest_If_Break :: struct { + indentation: int, + alignment: int, + document: ^Document, + group_id: string, +} + Document_Break :: struct { value: string, newline: bool, @@ -45,6 +53,7 @@ Document_If_Break :: struct { Document_Group :: struct { document: ^Document, mode: Document_Group_Mode, + options: Document_Group_Options, } Document_Cons :: struct { @@ -62,6 +71,10 @@ Document_Group_Mode :: enum { Fit, } +Document_Group_Options :: struct { + id: string, +} + empty :: proc(allocator := context.allocator) -> ^Document { document := new(Document, allocator) document^ = Document_Nil {} @@ -93,6 +106,16 @@ nest :: proc(level: int, nested_document: ^Document, allocator := context.alloca return document } +nest_if_break :: proc(level: int, nested_document: ^Document, group_id := "", allocator := context.allocator) -> ^Document { + document := new(Document, allocator) + document^ = Document_Nest_If_Break { + indentation = level, + document = nested_document, + group_id = group_id, + } + return document +} + hang :: proc(align: int, hanged_document: ^Document, allocator := context.allocator) -> ^Document { document := new(Document, allocator) document^ = Document_Nest { @@ -153,10 +176,11 @@ break_with_no_newline :: proc(allocator := context.allocator) -> ^Document { return break_with(" ", false, allocator) } -group :: proc(grouped_document: ^Document, 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, } return document } @@ -201,7 +225,7 @@ Tuple :: struct { document: ^Document, } -fits :: proc(width: int, list: ^[dynamic]Tuple, consumed: ^int) -> bool { +fits :: proc(width: int, list: ^[dynamic]Tuple) -> bool { assert(list != nil) start_width := width @@ -216,8 +240,7 @@ fits :: proc(width: int, list: ^[dynamic]Tuple, consumed: ^int) -> bool { for len(list) != 0 { data: Tuple = pop(list) - if width < 0 { - consumed^ = start_width + if width <= 0 { return false } @@ -225,7 +248,6 @@ fits :: proc(width: int, list: ^[dynamic]Tuple, consumed: ^int) -> bool { case Document_Nil: case Document_Newline: if v.amount > 0 { - consumed^ = start_width - width return true } case Document_Cons: @@ -239,7 +261,6 @@ fits :: proc(width: int, list: ^[dynamic]Tuple, consumed: ^int) -> bool { width -= len(v.value) case Document_Break: if data.mode == .Break && v.newline { - consumed^ = start_width - width return true } else { width -= len(v.value) @@ -248,14 +269,18 @@ fits :: proc(width: int, list: ^[dynamic]Tuple, consumed: ^int) -> bool { if data.mode == .Break { width -= len(v.value) } + case Document_Nest_If_Break: + if data.mode == .Break { + append(list, Tuple {indentation = data.indentation + v.indentation, mode = data.mode, document = v.document, alignment = data.alignment + v.alignment}) + } else { + 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 = .Flat, document = v.document, alignment = data.alignment}) + append(list, Tuple {indentation = data.indentation, mode = data.mode, document = v.document, alignment = data.alignment}) } } - consumed^ = start_width - width - - return width <= 0 + return width > 0 } format_newline :: proc(indentation: int, alignment: int, consumed: ^int, builder: ^strings.Builder, p: ^Printer) { @@ -267,7 +292,7 @@ format_newline :: proc(indentation: int, alignment: int, consumed: ^int, builder strings.write_string(builder, " ") } - consumed^ = indentation + alignment + consumed^ = indentation * p.indentation_width + alignment } format :: proc(width: int, list: ^[dynamic]Tuple, builder: ^strings.Builder, p: ^Printer) { @@ -292,7 +317,7 @@ 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 + data.alignment + consumed = data.indentation * p.indentation_width + data.alignment } case Document_Cons: append(list, Tuple {indentation = data.indentation, mode = data.mode, document = v.rhs, alignment = data.alignment}) @@ -316,21 +341,26 @@ format :: proc(width: int, list: ^[dynamic]Tuple, builder: ^strings.Builder, p: strings.write_string(builder, v.value) consumed += len(v.value) } + 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 + v.indentation, mode = data.mode, document = v.document, alignment = data.alignment + v.alignment}) + } else { + append(list, Tuple {indentation = data.indentation, mode = data.mode, document = v.document, alignment = data.alignment}) + } case Document_Group: l := make([dynamic]Tuple, 0, len(list)) for element in list { append(&l, element) } - - append(&l, Tuple {indentation = data.indentation, mode = .Flat, document = v.document, alignment = data.alignment}) - - fits_consumed := 0 + append(&l, Tuple {indentation = data.indentation, mode = .Flat, document = v.document, alignment = data.alignment}) + if data.mode == .Fit { append(list, Tuple {indentation = data.indentation, mode = .Fit, document = v.document, alignment = data.alignment}) } - else if fits(width-consumed, &l, &fits_consumed) && v.mode != .Break { + else if fits(width-consumed, &l) && v.mode != .Break { append(list, Tuple {indentation = data.indentation, mode = .Flat, document = v.document, alignment = data.alignment}) } else { if v.mode == .Fit { @@ -339,6 +369,8 @@ format :: proc(width: int, list: ^[dynamic]Tuple, builder: ^strings.Builder, p: 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 } } } diff --git a/src/odin/printer/printer.odin b/src/odin/printer/printer.odin index 5e1cb63..6f39c7c 100644 --- a/src/odin/printer/printer.odin +++ b/src/odin/printer/printer.odin @@ -22,8 +22,10 @@ Printer :: struct { indentation: string, newline: string, indentation_count: int, + indentation_width: int, disabled_lines: map[int]Disabled_Info, disabled_until_line: int, + group_modes: map[string]Document_Group_Mode, src: string, } @@ -37,6 +39,7 @@ Config :: struct { 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, @@ -77,6 +80,7 @@ when ODIN_OS == .Windows { newline_limit = 2, convert_do = false, tabs = true, + tabs_width = 4, brace_style = ._1TBS, indent_cases = false, newline_style = .CRLF, @@ -88,6 +92,7 @@ when ODIN_OS == .Windows { newline_limit = 2, convert_do = false, tabs = true, + tabs_width = 4, brace_style = ._1TBS, indent_cases = false, newline_style = .LF, @@ -164,9 +169,11 @@ print_file :: proc(p: ^Printer, file: ^ast.File) -> string { if p.config.tabs { p.indentation = "\t" p.indentation_count = 1 + p.indentation_width = p.config.tabs_width } else { p.indentation_count = p.config.spaces p.indentation = " " + p.indentation_width = 1 } if p.config.newline_style == .CRLF { diff --git a/src/odin/printer/visit.odin b/src/odin/printer/visit.odin index 411a6b4..bc5d57c 100644 --- a/src/odin/printer/visit.odin +++ b/src/odin/printer/visit.odin @@ -309,7 +309,11 @@ visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) -> ^Do if len(v.values) > 0 { if is_values_nestable_assign(v.values) { - return cons(document, nest(p.indentation_count, group(cons_with_opl(group(lhs), group(rhs))))) + return cons(document, group(nest(p.indentation_count, cons_with_opl(lhs, group(rhs))))) + } else if is_values_nestable_if_break_assign(v.values) { + assignments := cons(lhs, group(nest(p.indentation_count, break_with_space()), Document_Group_Options { id = "assignments"})) + assignments = cons(assignments, nest_if_break(p.indentation_count, group(rhs), "assignments")) + return cons(document, group(assignments)) } else { return cons(document, group(cons_with_nopl(group(lhs), group(rhs)))) } @@ -327,7 +331,19 @@ visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) -> ^Do 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.Call_Expr, ^ast.Ternary_If_Expr, ^ast.Ternary_When_Expr, ^ast.Or_Else_Expr, ^ast.Or_Return_Expr: + case ^ast.Ident, ^ast.Binary_Expr, ^ast.Index_Expr, ^ast.Ternary_If_Expr, ^ast.Ternary_When_Expr, ^ast.Or_Else_Expr, ^ast.Or_Return_Expr: + return true + } + } + return false +} + + +@(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: return true } } @@ -343,7 +359,6 @@ visit_exprs :: proc(p: ^Printer, list: []^ast.Expr, options := List_Options{}, c document := empty() for expr, i in list { - p.source_position = expr.pos if .Enforce_Newline in options { @@ -704,15 +719,18 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener document = cons_with_nopl(document, visit_stmt(p, v.tag)) document = cons_with_nopl(document, visit_stmt(p, v.body, .Switch_Stmt)) case ^Assign_Stmt: - assign_document := group(cons_with_nopl(visit_exprs(p, v.lhs, {.Add_Comma, .Glue}), text(v.op.text))) + assign_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(p.indentation_count, cons_with_opl(assign_document, group(rhs)))) + } else if is_values_nestable_if_break_assign(v.rhs) { + document = cons(assign_document, group(nest(p.indentation_count, break_with_space()), Document_Group_Options { id = "assignments"})) + document = cons(document, nest_if_break(p.indentation_count, group(rhs), "assignments")) + document = group(document) } else { - document = group(cons_with_nopl(assign_document, group(rhs))) + document = group(cons_with_opl(assign_document, group(rhs))) } - case ^Expr_Stmt: document = cons(document, visit_expr(p, v.expr)) case ^For_Stmt: |