From e0e6bba865440c5a3630ac7cb84ec5edd4fb0c34 Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Sun, 11 Apr 2021 19:47:33 +0200 Subject: [PATCH 01/49] start new prototype --- core/odin/printer/printer.odin | 0 core/odin/printer/visit.odin | 1345 ++++++++++++++++++++++++++++++++ 2 files changed, 1345 insertions(+) create mode 100644 core/odin/printer/printer.odin create mode 100644 core/odin/printer/visit.odin diff --git a/core/odin/printer/printer.odin b/core/odin/printer/printer.odin new file mode 100644 index 000000000..e69de29bb diff --git a/core/odin/printer/visit.odin b/core/odin/printer/visit.odin new file mode 100644 index 000000000..2b02ae0a5 --- /dev/null +++ b/core/odin/printer/visit.odin @@ -0,0 +1,1345 @@ +package odin_printer + +import "core:odin/ast" +import "core:odin/tokenizer" +import "core:strings" +import "core:runtime" +import "core:fmt" +import "core:unicode/utf8" +import "core:mem" + +@(private) +push_format_token :: proc(p: ^Printer, line: int, kind: tokenizer.Token_Kind, text: string, spaces_before: int) { + + if len(p.lines) <= line { + return; + } + + p.lines[line].used = true; + + format_token := Format_Token { + spaces_before = spaces_before, + kind = kind, + text = text, + }; + + append(&p.lines[line].format_tokens, format_token); +} + +set_source_position :: proc(p: ^Printer, pos: tokenizer.Pos) { + p.source_position = pos; +} + +/* + + +print_expr :: proc(p: ^Printer, expr: ^ast.Expr) { + + using ast; + + if expr == nil { + return; + } + + set_source_position(p, expr.pos); + + switch v in expr.derived { + case Inline_Asm_Expr: + //TEMP + //this is probably not fully done, but need more examples + /* + Inline_Asm_Expr :: struct { + using node: Expr, + tok: tokenizer.Token, + param_types: []^Expr, + return_type: ^Expr, + has_side_effects: bool, + is_align_stack: bool, + dialect: Inline_Asm_Dialect, + open: tokenizer.Pos, + constraints_string: ^Expr, + asm_string: ^Expr, + close: tokenizer.Pos, + } + */ + + /* + cpuid :: proc(ax, cx: u32) -> (eax, ebc, ecx, edx: u32) { + return expand_to_tuple(asm(u32, u32) -> struct{eax, ebc, ecx, edx: u32} { + "cpuid", + "={ax},={bx},={cx},={dx},{ax},{cx}", + }(ax, cx)); + } + */ + + print(p, v.tok, space, lparen); + print_exprs(p, v.param_types, ", "); + print(p, rparen, space); + + print(p, "->", space); + + print_expr(p, v.return_type); + + print(p, space); + + print(p, lbrace); + print_expr(p, v.asm_string); + print(p, ", "); + print_expr(p, v.constraints_string); + print(p, rbrace); + + case Undef: + print(p, "---"); + case Auto_Cast: + print(p, v.op, space); + print_expr(p, v.expr); + case Ternary_Expr: + print_expr(p, v.cond); + print(p, space, v.op1, space); + print_expr(p, v.x); + print(p, space, v.op2, space); + print_expr(p, v.y); + case Ternary_If_Expr: + print_expr(p, v.x); + print(p, space, v.op1, space); + print_expr(p, v.cond); + print(p, space, v.op2, space); + print_expr(p, v.y); + case Ternary_When_Expr: + print_expr(p, v.x); + print(p, space, v.op1, space); + print_expr(p, v.cond); + print(p, space, v.op2, space); + print_expr(p, v.y); + case Selector_Call_Expr: + print_expr(p, v.call.expr); + print(p, lparen); + print_exprs(p, v.call.args, ", "); + print(p, rparen); + case Ellipsis: + print(p, ".."); + print_expr(p, v.expr); + case Relative_Type: + print_expr(p, v.tag); + print(p, space); + print_expr(p, v.type); + case Slice_Expr: + print_expr(p, v.expr); + print(p, lbracket); + print_expr(p, v.low); + print(p, v.interval); + print_expr(p, v.high); + print(p, rbracket); + case Ident: + print(p, v); + case Deref_Expr: + print_expr(p, v.expr); + print(p, v.op); + case Type_Cast: + print(p, v.tok, lparen); + print_expr(p, v.type); + print(p, rparen); + print_expr(p, v.expr); + case Basic_Directive: + print(p, v.tok, v.name); + case Distinct_Type: + print(p, "distinct", space); + print_expr(p, v.type); + case Dynamic_Array_Type: + print_expr(p, v.tag); + print(p, lbracket, "dynamic", rbracket); + print_expr(p, v.elem); + case Bit_Set_Type: + print(p, "bit_set", lbracket); + print_expr(p, v.elem); + + if v.underlying != nil { + print(p, semicolon, space); + print_expr(p, v.underlying); + } + + print(p, rbracket); + case Union_Type: + print(p, "union"); + + if v.poly_params != nil { + print(p, lparen); + print_field_list(p, v.poly_params, ", "); + print(p, rparen); + } + + if v.is_maybe { + print(p, space, "#maybe"); + } + + if v.variants != nil && (len(v.variants) == 0 || v.pos.line == v.end.line) { + print(p, space, lbrace); + set_source_position(p, v.variants[len(v.variants) - 1].pos); + print_exprs(p, v.variants, ", "); + print(p, rbrace); + } else { + print_begin_brace(p, v.pos, .Generic); + print(p, newline); + set_source_position(p, v.variants[len(v.variants) - 1].pos); + print_exprs(p, v.variants, ",", true); + print_end_brace(p, v.end); + } + case Enum_Type: + print(p, "enum"); + + if v.base_type != nil { + print(p, space); + print_expr(p, v.base_type); + } + + if v.fields != nil && (len(v.fields) == 0 || v.pos.line == v.end.line) { + print(p, space, lbrace); + set_source_position(p, v.fields[len(v.fields) - 1].pos); + print_exprs(p, v.fields, ", "); + print(p, rbrace); + } else { + print_begin_brace(p, v.pos, .Generic); + print(p, newline); + set_source_position(p, v.fields[len(v.fields) - 1].pos); + print_enum_fields(p, v.fields, ","); + print_end_brace(p, v.end); + } + + set_source_position(p, v.end); + case Struct_Type: + print(p, "struct"); + + if v.is_packed { + print(p, space, "#packed"); + } + + if v.is_raw_union { + print(p, space, "#raw_union"); + } + + if v.align != nil { + print(p, space, "#align", space); + print_expr(p, v.align); + } + + if v.poly_params != nil { + print(p, lparen); + print_field_list(p, v.poly_params, ", "); + print(p, rparen); + } + + if v.fields != nil && (len(v.fields.list) == 0 || v.pos.line == v.end.line) { + print(p, space, lbrace); + set_source_position(p, v.fields.pos); + print_field_list(p, v.fields, ", "); + print(p, rbrace); + } else { + print_begin_brace(p, v.pos, .Generic); + print(p, newline); + set_source_position(p, v.fields.pos); + print_struct_field_list(p, v.fields, ","); + print_end_brace(p, v.end); + } + + set_source_position(p, v.end); + case Proc_Lit: + + if v.inlining == .Inline { + print(p, "#force_inline", space); + } + + print_proc_type(p, v.type^); + + if v.where_clauses != nil { + print(p, space); + newline_until_pos(p, v.where_clauses[0].pos); + print(p, "where", space); + print_exprs(p, v.where_clauses, ", "); + } + + if v.body != nil { + set_source_position(p, v.body.pos); + print_stmt(p, v.body, .Proc); + } else { + print(p, space, "---"); + } + case Proc_Type: + print_proc_type(p, v); + case Basic_Lit: + print(p, v.tok); + case Binary_Expr: + print_binary_expr(p, v); + case Implicit_Selector_Expr: + print(p, dot, v.field^); + case Call_Expr: + print_expr(p, v.expr); + print(p, lparen); + + padding := get_length_of_names({v.expr}); + + print_call_exprs(p, v.args, ", ", v.ellipsis.kind == .Ellipsis, padding); + print(p, rparen); + case Typeid_Type: + print(p, "typeid"); + if v.specialization != nil { + print(p, "/"); + print_expr(p, v.specialization); + } + case Selector_Expr: + print_expr(p, v.expr); + print(p, v.op); + print_expr(p, v.field); + case Paren_Expr: + print(p, lparen); + print_expr(p, v.expr); + print(p, rparen); + case Index_Expr: + print_expr(p, v.expr); + print(p, lbracket); + print_expr(p, v.index); + print(p, rbracket); + case Proc_Group: + + print(p, v.tok); + + if len(v.args) != 0 && v.pos.line != v.args[len(v.args) - 1].pos.line { + print_begin_brace(p, v.pos, .Generic); + print(p, newline); + set_source_position(p, v.args[len(v.args) - 1].pos); + print_exprs(p, v.args, ",", true); + print_end_brace(p, v.end); + } else { + print(p, space, lbrace); + print_exprs(p, v.args, ", "); + print(p, rbrace); + } + case Comp_Lit: + + if v.type != nil { + print_expr(p, v.type); + print(p, space); + } + + if len(v.elems) != 0 && v.pos.line != v.elems[len(v.elems) - 1].pos.line { + print_begin_brace(p, v.pos, .Comp_Lit); + print(p, newline); + set_source_position(p, v.elems[len(v.elems) - 1].pos); + print_exprs(p, v.elems, ",", true); + print_end_brace(p, v.end); + } else { + print(p, lbrace); + print_exprs(p, v.elems, ", "); + print(p, rbrace); + } + case Unary_Expr: + print(p, v.op); + print_expr(p, v.expr); + case Field_Value: + print_expr(p, v.field); + print(p, space, "=", space); + print_expr(p, v.value); + case Type_Assertion: + print_expr(p, v.expr); + + if unary, ok := v.type.derived.(Unary_Expr); ok && unary.op.text == "?" { + print(p, dot); + print_expr(p, v.type); + } else { + print(p, dot, lparen); + print_expr(p, v.type); + print(p, rparen); + } + + case Pointer_Type: + print(p, "^"); + print_expr(p, v.elem); + case Implicit: + print(p, v.tok); + case Poly_Type: + print(p, "$"); + print_expr(p, v.type); + + if v.specialization != nil { + print(p, "/"); + print_expr(p, v.specialization); + } + case Array_Type: + print_expr(p, v.tag); + print(p, lbracket); + print_expr(p, v.len); + print(p, rbracket); + print_expr(p, v.elem); + case Map_Type: + print(p, "map", lbracket); + print_expr(p, v.key); + print(p, rbracket); + print_expr(p, v.value); + case Helper_Type: + print_expr(p, v.type); + case: + panic(fmt.aprint(expr.derived)); + } +} + +print_proc_type :: proc(p: ^Printer, proc_type: ast.Proc_Type) { + + print(p, "proc"); //TOOD(ast is missing proc token) + + if proc_type.calling_convention != .Odin { + print(p, space); + } + + switch proc_type.calling_convention { + case .Odin: + case .Contextless: + print(p, "\"contextless\"", space); + case .C_Decl: + print(p, "\"c\"", space); + case .Std_Call: + print(p, "\"std\"", space); + case .Fast_Call: + print(p, "\"fast\"", space); + case .None: + //nothing i guess + case .Invalid: + //nothing i guess + case .Foreign_Block_Default: + } + + print(p, lparen); + print_signature_list(p, proc_type.params, ", ", false); + print(p, rparen); + + if proc_type.results != nil { + print(p, space, "->", space); + + use_parens := false; + use_named := false; + + if len(proc_type.results.list) > 1 { + use_parens = true; + } else if len(proc_type.results.list) == 1 { + + for name in proc_type.results.list[0].names { + if ident, ok := name.derived.(ast.Ident); ok { + if ident.name != "_" { + use_parens = true; + } + } + } + } + + if use_parens { + print(p, lparen); + print_signature_list(p, proc_type.results, ", "); + print(p, rparen); + } else { + print_signature_list(p, proc_type.results, ", "); + } + } +} + +print_enum_fields :: proc(p: ^Printer, list: []^ast.Expr, sep := " ") { + + //print enum fields is like print_exprs, but it can contain fields that can be aligned. + + if len(list) == 0 { + return; + } + + if list[0].pos.line == list[len(list) - 1].pos.line { + //if everything is on one line, then it can be treated the same way as print_exprs + print_exprs(p, list, sep); + return; + } + + largest := 0; + last_field_value := 0; + + //first find all the field values and find the largest name + for expr, i in list { + + if field_value, ok := expr.derived.(ast.Field_Value); ok { + + if ident, ok := field_value.field.derived.(ast.Ident); ok { + largest = max(largest, strings.rune_count(ident.name)); + } + } + } + + for expr, i in list { + + newline_until_pos_limit(p, expr.pos, 1); + + if field_value, ok := expr.derived.(ast.Field_Value); ok && p.config.align_assignments { + + if ident, ok := field_value.field.derived.(ast.Ident); ok { + print_expr(p, field_value.field); + print_space_padding(p, largest - strings.rune_count(ident.name) + 1); + print(p, "=", space); + print_expr(p, field_value.value); + } else { + print_expr(p, expr); + } + } else { + print_expr(p, expr); + } + + if i != len(list) - 1 { + print(p, sep); + } else { + print(p, strings.trim_space(sep)); + } + } +} + +print_call_exprs :: proc(p: ^Printer, list: []^ast.Expr, sep := " ", ellipsis := false, padding := 0) { + + if len(list) == 0 { + return; + } + + //all the expression are on the line + if list[0].pos.line == list[len(list) - 1].pos.line { + + for expr, i in list { + + if i == len(list) - 1 && ellipsis { + print(p, ".."); + } + + print_expr(p, expr); + + if i != len(list) - 1 { + print(p, sep); + } + } + } else { + + for expr, i in list { + + //we have to newline the expressions to respect the source + if newline_until_pos_limit(p, expr.pos, 1) { + print_space_padding(p, padding); + } + + if i == len(list) - 1 && ellipsis { + print(p, ".."); + } + + print_expr(p, expr); + + if i != len(list) - 1 { + print(p, sep); + } + } + } +} + +print_exprs :: proc(p: ^Printer, list: []^ast.Expr, sep := " ", trailing := false) { + + if len(list) == 0 { + return; + } + + //we have to newline the expressions to respect the source + for expr, i in list { + + newline_until_pos_limit(p, expr.pos, 1); + + print_expr(p, expr); + + if i != len(list) - 1 { + print(p, sep); + } else if trailing { + print(p, strings.trim_space(sep)); + } + } +} + +print_binary_expr :: proc(p: ^Printer, binary: ast.Binary_Expr) { + + newline_until_pos(p, binary.left.pos); + + if v, ok := binary.left.derived.(ast.Binary_Expr); ok { + print_binary_expr(p, v); + } else { + print_expr(p, binary.left); + } + + if binary.op.kind == .Ellipsis || binary.op.kind == .Range_Half { + print(p, binary.op); + } else { + print(p, space, binary.op, space); + } + + newline_until_pos(p, binary.right.pos); + + if v, ok := binary.right.derived.(ast.Binary_Expr); ok { + print_binary_expr(p, v); + } else { + print_expr(p, binary.right); + } +} + +print_struct_field_list :: proc(p: ^Printer, list: ^ast.Field_List, sep := "") { + + if list.list == nil { + return; + } + + largest := 0; + using_size := len("using "); + + //NOTE(Daniel): Is there any other variables than using in structs? + + for field, i in list.list { + if .Using in field.flags { + largest = max(largest, get_length_of_names(field.names) + using_size); + } else { + largest = max(largest, get_length_of_names(field.names)); + } + } + + for field, i in list.list { + + newline_until_pos_limit(p, field.pos, 1); + + if .Using in field.flags { + print(p, "using", space); + } + + print_exprs(p, field.names, ", "); + + if len(field.names) != 0 { + print(p, ": "); + } + + if field.type == nil { + panic("struct field has to have types"); + } + + if .Using in field.flags { + print_space_padding(p, largest - get_length_of_names(field.names) - using_size); + } else { + print_space_padding(p, largest - get_length_of_names(field.names)); + } + + print_expr(p, field.type); + + if field.tag.text != "" { + print(p, space, field.tag); + } + + if i != len(list.list) - 1 { + print(p, sep); + } else { + print(p, strings.trim_space(sep)); + } + } +} + +print_field_list :: proc(p: ^Printer, list: ^ast.Field_List, sep := "") { + + if list.list == nil { + return; + } + + for field, i in list.list { + + newline_until_pos_limit(p, field.pos, 1); + + if .Using in field.flags { + print(p, "using", space); + } + + print_exprs(p, field.names, ", "); + + if len(field.names) != 0 { + print(p, ": "); + } + + if field.type != nil { + print_expr(p, field.type); + } else { + print(p, ":= "); + print_expr(p, field.default_value); + } + + if field.tag.text != "" { + print(p, space, field.tag); + } + + if i != len(list.list) - 1 { + print(p, sep); + } + } +} + +print_signature_list :: proc(p: ^Printer, list: ^ast.Field_List, sep := "", remove_blank := true) { + + if list.list == nil { + return; + } + + for field, i in list.list { + + newline_until_pos_limit(p, field.pos, 1); + + if .Using in field.flags { + print(p, "using", space); + } + + named := false; + + for name in field.names { + if ident, ok := name.derived.(ast.Ident); ok { + //for some reason the parser uses _ to mean empty + if ident.name != "_" || !remove_blank { + named = true; + } + } else { + //alternative is poly names + named = true; + } + } + + if named { + print_exprs(p, field.names, ", "); + + if len(field.names) != 0 && field.type != nil { + print(p, ": "); + } else { + print(p, space); + } + } + + if field.type != nil && field.default_value != nil { + print_expr(p, field.type); + print(p, space, "=", space); + print_expr(p, field.default_value); + } else if field.type != nil { + print_expr(p, field.type); + } else { + print(p, ":= "); + print_expr(p, field.default_value); + } + + if i != len(list.list) - 1 { + print(p, sep); + } + } +} + +print_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Generic, empty_block := false, block_stmt := false) { + + using ast; + + if stmt == nil { + return; + } + + switch v in stmt.derived { + case Value_Decl: + print_decl(p, cast(^Decl)stmt, true); + return; + case Foreign_Import_Decl: + print_decl(p, cast(^Decl)stmt, true); + return; + case Foreign_Block_Decl: + print_decl(p, cast(^Decl)stmt, true); + return; + } + + switch v in stmt.derived { + case Using_Stmt: + newline_until_pos(p, v.pos); + print(p, "using", space); + print_exprs(p, v.list, ", "); + + if p.config.semicolons { + print(p, semicolon); + } + case Block_Stmt: + newline_until_pos(p, v.pos); + + if v.pos.line == v.end.line && len(v.stmts) > 1 && p.config.split_multiple_stmts { + + if !empty_block { + print_begin_brace(p, v.pos, block_type); + } + + set_source_position(p, v.pos); + + print_block_stmts(p, v.stmts, true); + + set_source_position(p, v.end); + + if !empty_block { + print_end_brace(p, v.end); + } + } else if v.pos.line == v.end.line { + if !empty_block { + print(p, lbrace); + } + + set_source_position(p, v.pos); + + print_block_stmts(p, v.stmts); + + set_source_position(p, v.end); + + if !empty_block { + print(p, rbrace); + } + } else { + if !empty_block { + print_begin_brace(p, v.pos, block_type); + } + + set_source_position(p, v.pos); + + print_block_stmts(p, v.stmts); + + set_source_position(p, v.end); + + if !empty_block { + print_end_brace(p, v.end); + } + } + case If_Stmt: + newline_until_pos(p, v.pos); + + if v.label != nil { + print_expr(p, v.label); + print(p, ":", space); + } + + print(p, "if", space); + + if v.init != nil { + p.skip_semicolon = true; + print_stmt(p, v.init); + p.skip_semicolon = false; + print(p, semicolon, space); + } + + print_expr(p, v.cond); + + uses_do := false; + + if check_stmt, ok := v.body.derived.(Block_Stmt); ok && check_stmt.uses_do { + uses_do = true; + } + + if uses_do && !p.config.convert_do { + print(p, space, "do", space); + print_stmt(p, v.body, .If_Stmt, true); + } else { + if uses_do { + print(p, newline); + } + + print_stmt(p, v.body, .If_Stmt); + } + + if v.else_stmt != nil { + + if p.config.brace_style == .Allman || p.config.brace_style == .Stroustrup { + print(p, newline); + } else { + print(p, space); + } + + print(p, "else"); + + if if_stmt, ok := v.else_stmt.derived.(ast.If_Stmt); ok { + print(p, space); + } + + set_source_position(p, v.else_stmt.pos); + + print_stmt(p, v.else_stmt); + } + case Switch_Stmt: + newline_until_pos(p, v.pos); + + if v.label != nil { + print_expr(p, v.label); + print(p, ":", space); + } + + if v.partial { + print(p, "#partial", space); + } + + print(p, "switch"); + + if v.init != nil || v.cond != nil { + print(p, space); + } + + if v.init != nil { + p.skip_semicolon = true; + print_stmt(p, v.init); + p.skip_semicolon = false; + } + + if v.init != nil && v.cond != nil { + print(p, semicolon, space); + } + + print_expr(p, v.cond); + print_stmt(p, v.body); + case Case_Clause: + newline_until_pos(p, v.pos); + + if !p.config.indent_cases { + print(p, unindent); + } + + print(p, "case", indent); + + if v.list != nil { + print(p, space); + print_exprs(p, v.list, ","); + } + + print(p, v.terminator); + + print_block_stmts(p, v.body); + + print(p, unindent); + + if !p.config.indent_cases { + print(p, indent); + } + case Type_Switch_Stmt: + newline_until_pos(p, v.pos); + + if v.label != nil { + print_expr(p, v.label); + print(p, ":", space); + } + + if v.partial { + print(p, "#partial", space); + } + + print(p, "switch", space); + + print_stmt(p, v.tag); + print_stmt(p, v.body); + case Assign_Stmt: + newline_until_pos(p, v.pos); + + /* + if len(v.lhs) == 1 { + + if ident, ok := v.lhs[0].derived.(Ident); ok && ident.name == "_" { + print(p, v.op, space); + print_exprs(p, v.rhs, ", "); + return; + } + + } + */ + + print_exprs(p, v.lhs, ", "); + + if p.config.align_assignments && p.align_info.assign_aligned_begin_line <= v.pos.line && v.pos.line <= p.align_info.assign_aligned_end_line { + print_space_padding(p, p.align_info.assign_aligned_padding - get_length_of_names(v.lhs)); + } + + print(p, space, v.op, space); + + print_exprs(p, v.rhs, ", "); + + if block_stmt && p.config.semicolons { + print(p, semicolon); + } + case Expr_Stmt: + newline_until_pos(p, v.pos); + print_expr(p, v.expr); + if block_stmt && p.config.semicolons { + print(p, semicolon); + } + case For_Stmt: + //this should be simplified + newline_until_pos(p, v.pos); + + if v.label != nil { + print_expr(p, v.label); + print(p, ":", space); + } + + print(p, "for"); + + if v.init != nil || v.cond != nil || v.post != nil { + print(p, space); + } + + if v.init != nil { + p.skip_semicolon = true; + print_stmt(p, v.init); + p.skip_semicolon = false; + print(p, semicolon, space); + } else if v.post != nil { + print(p, semicolon, space); + } + + if v.cond != nil { + print_expr(p, v.cond); + } + + if v.post != nil { + print(p, semicolon); + print(p, space); + print_stmt(p, v.post); + } else if v.post == nil && v.cond != nil && v.init != nil { + print(p, semicolon); + } + + print_stmt(p, v.body); + case Inline_Range_Stmt: + + newline_until_pos(p, v.pos); + + if v.label != nil { + print_expr(p, v.label); + print(p, ":", space); + } + + print(p, "#unroll", space); + + print(p, "for", space); + print_expr(p, v.val0); + + if v.val1 != nil { + print(p, ",", space); + print_expr(p, v.val1); + print(p, space); + } + + print(p, "in", space); + print_expr(p, v.expr); + + print_stmt(p, v.body); + case Range_Stmt: + + newline_until_pos(p, v.pos); + + if v.label != nil { + print_expr(p, v.label); + print(p, ":", space); + } + + print(p, "for", space); + + if len(v.vals) >= 1 { + print_expr(p, v.vals[0]); + } + + if len(v.vals) >= 2 { + print(p, ",", space); + print_expr(p, v.vals[1]); + print(p, space); + } else { + print(p, space); + } + + print(p, "in", space); + print_expr(p, v.expr); + + print_stmt(p, v.body); + case Return_Stmt: + newline_until_pos(p, v.pos); + print(p, "return"); + + if v.results != nil { + print(p, space); + print_exprs(p, v.results, ", "); + } + + if block_stmt && p.config.semicolons { + print(p, semicolon); + } + case Defer_Stmt: + newline_until_pos(p, v.pos); + print(p, "defer"); + + if block, ok := v.stmt.derived.(ast.Block_Stmt); !ok { + print(p, space); + } + + print_stmt(p, v.stmt); + + if p.config.semicolons { + print(p, semicolon); + } + case When_Stmt: + newline_until_pos(p, v.pos); + print(p, "when", space); + print_expr(p, v.cond); + + print_stmt(p, v.body); + + if v.else_stmt != nil { + + if p.config.brace_style == .Allman { + print(p, newline); + } else { + print(p, space); + } + + print(p, "else"); + + if when_stmt, ok := v.else_stmt.derived.(ast.When_Stmt); ok { + print(p, space); + } + + set_source_position(p, v.else_stmt.pos); + + print_stmt(p, v.else_stmt); + } + + case Branch_Stmt: + + newline_until_pos(p, v.pos); + + print(p, v.tok); + + if v.label != nil { + print(p, space); + print_expr(p, v.label); + } + + if p.config.semicolons { + print(p, semicolon); + } + case: + panic(fmt.aprint(stmt.derived)); + } + + set_source_position(p, stmt.end); +} + +print_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) { + + using ast; + + if decl == nil { + return; + } + + switch v in decl.derived { + case Expr_Stmt: + newline_until_pos(p, decl.pos); + print_expr(p, v.expr); + if p.config.semicolons { + print(p, semicolon); + } + case When_Stmt: + print_stmt(p, cast(^Stmt)decl); + case Foreign_Import_Decl: + if len(v.attributes) > 0 { + newline_until_pos(p, v.attributes[0].pos); + } else { + newline_until_pos(p, decl.pos); + } + + print_attributes(p, v.attributes); + + if v.name != nil { + print(p, v.foreign_tok, space, v.import_tok, space, v.name^, space); + } else { + print(p, v.foreign_tok, space, v.import_tok, space); + } + + for path in v.fullpaths { + print(p, path); + } + case Foreign_Block_Decl: + + if len(v.attributes) > 0 { + newline_until_pos(p, v.attributes[0].pos); + } else { + newline_until_pos(p, decl.pos); + } + + print_attributes(p, v.attributes); + + print(p, newline, "foreign", space); + print_expr(p, v.foreign_library); + print_stmt(p, v.body); + case Import_Decl: + newline_until_pos(p, decl.pos); + + if v.name.text != "" { + print(p, v.import_tok, " ", v.name, " ", v.fullpath); + } else { + print(p, v.import_tok, " ", v.fullpath); + } + + case Value_Decl: + if len(v.attributes) > 0 { + newline_until_pos(p, v.attributes[0].pos); + print_attributes(p, v.attributes); + } + + newline_until_pos(p, decl.pos); + + if v.is_using { + print(p, "using", space); + } + + print_exprs(p, v.names, ", "); + + seperator := ":"; + + if !v.is_mutable && v.type == nil { + seperator = ":: "; + } else if !v.is_mutable && v.type != nil { + seperator = " :"; + } + + if in_value_decl_alignment(p, v) && p.config.align_style == .Align_On_Colon_And_Equals { + print_space_padding(p, p.align_info.value_decl_aligned_padding - get_length_of_names(v.names)); + } + + if v.type != nil { + print(p, seperator, space); + + if in_value_decl_alignment(p, v) && p.config.align_style == .Align_On_Type_And_Equals { + print_space_padding(p, p.align_info.value_decl_aligned_padding - get_length_of_names(v.names)); + } else if in_value_decl_alignment(p, v) && p.config.align_style == .Align_On_Colon_And_Equals { + print_space_padding(p, p.align_info.value_decl_aligned_type_padding - (v.type.end.column - v.type.pos.column)); + } + + print_expr(p, v.type); + + if in_value_decl_alignment(p, v) && p.config.align_style == .Align_On_Type_And_Equals && len(v.values) != 0 { + print_space_padding(p, p.align_info.value_decl_aligned_type_padding - (v.type.end.column - v.type.pos.column)); + } + } else { + if in_value_decl_alignment(p, v) && p.config.align_style == .Align_On_Type_And_Equals { + print_space_padding(p, p.align_info.value_decl_aligned_padding - get_length_of_names(v.names)); + } + print(p, space, seperator); + } + + if v.is_mutable && v.type != nil && len(v.values) != 0 { + print(p, space, "=", space); + } else if v.is_mutable && v.type == nil && len(v.values) != 0 { + print(p, "=", space); + } else if !v.is_mutable && v.type != nil { + print(p, space, ":", space); + } + + print_exprs(p, v.values, ", "); + + add_semicolon := true; + + for value in v.values { + switch a in value.derived { + case Proc_Lit,Union_Type,Enum_Type,Struct_Type: + add_semicolon = false || called_in_stmt; + } + } + + if add_semicolon && p.config.semicolons && !p.skip_semicolon { + print(p, semicolon); + } + + case: + panic(fmt.aprint(decl.derived)); + } +} + +print_attributes :: proc(p: ^Printer, attributes: [dynamic]^ast.Attribute) { + + if len(attributes) == 0 { + return; + } + + for attribute, i in attributes { + + print(p, "@", lparen); + print_exprs(p, attribute.elems, ", "); + print(p, rparen); + + if len(attributes) - 1 != i { + print(p, newline); + } + } +} + +print_file :: proc(p: ^Printer, file: ^ast.File) { + + p.comments = file.comments; + p.file = file; + + newline_until_pos(p, file.pkg_token.pos); + + print(p, file.pkg_token, space, file.pkg_name); + + for decl, i in file.decls { + + if value_decl, ok := decl.derived.(ast.Value_Decl); ok { + set_value_decl_alignment_padding(p, value_decl, file.decls[i + 1:]); + } + + print_decl(p, cast(^ast.Decl)decl); + } + + //todo(probably check if there already is a newline, but there really shouldn't be) + print(p, newline); //finish document with newline + write_whitespaces(p, p.current_whitespace); +} + +print_begin_brace :: proc(p: ^Printer, begin: tokenizer.Pos, type: Block_Type) { + + set_source_position(p, begin); + + newline_braced := p.config.brace_style == .Allman; + newline_braced |= p.config.brace_style == .K_And_R && type == .Proc; + newline_braced &= p.config.brace_style != ._1TBS; + + if newline_braced { + print(p, newline); + print(p, lbrace); + print(p, indent); + } else { + + if type != .Comp_Lit && p.last_out_position.line == (p.out_position.line + get_current_newlines(p)) { + print(p, space); + } + print(p, lbrace); + print(p, indent); + } +} + +print_end_brace :: proc(p: ^Printer, end: tokenizer.Pos) { + set_source_position(p, end); + print(p, newline, unindent, rbrace); +} + +print_block_stmts :: proc(p: ^Printer, stmts: []^ast.Stmt, newline_each := false) { + for stmt, i in stmts { + + if newline_each { + print(p, newline); + } + + if value_decl, ok := stmt.derived.(ast.Value_Decl); ok { + set_value_decl_alignment_padding(p, value_decl, stmts[i + 1:]); + } else if assignment_stmt, ok := stmt.derived.(ast.Assign_Stmt); ok { + set_assign_alignment_padding(p, assignment_stmt, stmts[i + 1:]); + } + + print_stmt(p, stmt, .Generic, false, true); + } +} +*/ + + From 9139ca4673bb0de6acc95ef4ad87676d96887fc3 Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Mon, 12 Apr 2021 17:01:43 +0200 Subject: [PATCH 02/49] more work on fmt --- core/odin/printer/printer.odin | 143 +++ core/odin/printer/visit.odin | 1898 ++++++++++++++++---------------- 2 files changed, 1117 insertions(+), 924 deletions(-) diff --git a/core/odin/printer/printer.odin b/core/odin/printer/printer.odin index e69de29bb..d783bfb48 100644 --- a/core/odin/printer/printer.odin +++ b/core/odin/printer/printer.odin @@ -0,0 +1,143 @@ +package odin_printer + +import "core:odin/ast" +import "core:odin/tokenizer" +import "core:strings" +import "core:runtime" +import "core:fmt" +import "core:unicode/utf8" +import "core:mem" + +Line :: struct { + format_tokens: [dynamic] Format_Token, + finalized: bool, + used: bool, + depth: int, +} + +Format_Token :: struct { + kind: tokenizer.Token_Kind, + text: string, + spaces_before: int, +} + +Printer :: struct { + string_builder: strings.Builder, + config: Config, + depth: int, //the identation depth + comments: [dynamic]^ast.Comment_Group, + allocator: mem.Allocator, + file: ^ast.File, + source_position: tokenizer.Pos, + lines: map [int]^Line, + skip_semicolon: bool, + current_line: ^Line, + current_line_index: int, + last_token: ^Format_Token, +} + +Config :: struct { + spaces: int, //Spaces per indentation + newline_limit: int, //The limit of newlines between statements and declarations. + tabs: bool, //Enable or disable tabs + convert_do: bool, //Convert all do statements to brace blocks + semicolons: bool, //Enable semicolons + split_multiple_stmts: bool, + brace_style: Brace_Style, + align_assignments: bool, + align_style: Alignment_Style, + indent_cases: bool, +} + +Brace_Style :: enum { + _1TBS, + Allman, + Stroustrup, + K_And_R, +} + +Block_Type :: enum { + None, + If_Stmt, + Proc, + Generic, + Comp_Lit, +} + +Alignment_Style :: enum { + Align_On_Colon_And_Equals, + Align_On_Type_And_Equals, +} + +default_style := Config { + spaces = 4, + newline_limit = 2, + convert_do = false, + semicolons = true, + tabs = true, + brace_style = ._1TBS, + split_multiple_stmts = true, + align_assignments = true, + align_style = .Align_On_Type_And_Equals, + indent_cases = false, +}; + +make_printer :: proc(config: Config, allocator := context.allocator) -> Printer { + return { + config = config, + allocator = allocator, + }; +} + +print :: proc(p: ^Printer, file: ^ast.File) -> string { + + for decl in file.decls { + visit_stmt(p, decl); + } + + fix_lines(p); + + builder := strings.make_builder(p.allocator); + + last_line := 0; + + for key, value in p.lines { + diff_line := min(key - last_line, p.config.newline_limit); + + 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, ' '); + } + + for format_token in value.format_tokens { + + for i := 0; i < format_token.spaces_before; i += 1 { + strings.write_byte(&builder, ' '); + } + + strings.write_string(&builder, format_token.text); + } + + last_line = key; + } + + return strings.to_string(builder); +} + +fix_lines :: proc(p: ^Printer) { + + for key, value in p.lines { + + if len(value.format_tokens) <= 0 { + continue; + } + + + + } + + +} diff --git a/core/odin/printer/visit.odin b/core/odin/printer/visit.odin index 2b02ae0a5..12f7da301 100644 --- a/core/odin/printer/visit.odin +++ b/core/odin/printer/visit.odin @@ -8,32 +8,639 @@ import "core:fmt" import "core:unicode/utf8" import "core:mem" -@(private) -push_format_token :: proc(p: ^Printer, line: int, kind: tokenizer.Token_Kind, text: string, spaces_before: int) { - if len(p.lines) <= line { - return; - } - - p.lines[line].used = true; +@(private) +append_format_token :: proc(p: ^Printer, unwrapped_line: ^Line, format_token: Format_Token) -> ^Format_Token { + + format_token := format_token; + + if p.last_token != nil && (p.last_token.kind == .Ellipsis || p.last_token.kind == .Range_Half || + p.last_token.kind == .Open_Paren || p.last_token.kind == .Period || + p.last_token.kind == .Open_Brace) { + format_token.spaces_before = 0; + } + + if len(unwrapped_line.format_tokens) == 0 && format_token.spaces_before == 1 { + format_token.spaces_before = 0; + } + + append(&unwrapped_line.format_tokens, format_token); + return &unwrapped_line.format_tokens[len(unwrapped_line.format_tokens)-1]; +} + +@(private) +push_generic_token :: proc(p: ^Printer, kind: tokenizer.Token_Kind, spaces_before: int, value := "") { + + unwrapped_line := p.current_line; + unwrapped_line.used = true; + unwrapped_line.depth = p.depth; format_token := Format_Token { spaces_before = spaces_before, kind = kind, + text = tokenizer.tokens[kind], + }; + + if value != "" { + format_token.text = value; + } + + p.last_token = append_format_token(p, unwrapped_line, format_token); +} + +@(private) +push_string_token :: proc(p: ^Printer, text: string, spaces_before: int) { + unwrapped_line := p.current_line; + unwrapped_line.used = true; + unwrapped_line.depth = p.depth; + + format_token := Format_Token { + spaces_before = spaces_before, + kind = .String, text = text, }; - append(&p.lines[line].format_tokens, format_token); + p.last_token = append_format_token(p, unwrapped_line, format_token); } +@(private) +push_ident_token :: proc(p: ^Printer, text: string, spaces_before: int) { + + unwrapped_line := p.current_line; + unwrapped_line.used = true; + unwrapped_line.depth = p.depth; + + format_token := Format_Token { + spaces_before = spaces_before, + kind = .Ident, + text = text, + }; + + p.last_token = append_format_token(p, unwrapped_line, format_token); +} + +@(private) set_source_position :: proc(p: ^Printer, pos: tokenizer.Pos) { p.source_position = pos; } -/* +@(private) +move_line :: proc(p: ^Printer, pos: tokenizer.Pos) { + move_line_limit(p, pos, p.config.newline_limit); +} + +@(private) +move_line_limit :: proc(p: ^Printer, pos: tokenizer.Pos, limit: int) -> bool { + lines := min(pos.line - p.source_position.line, limit); + p.source_position = pos; + p.current_line_index += lines; + set_line(p, p.current_line_index); + return lines > 0; +} + +@(private) +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; + } else { + unwrapped_line = p.lines[line]; + } + + p.current_line = unwrapped_line; + + return unwrapped_line; +} + +@(private) +newline_source_position :: proc(p: ^Printer, count: int) { + p.current_line_index += count; + set_line(p, p.current_line_index); +} + +@(private) +indent :: proc(p: ^Printer) { + p.depth += 1; +} + +@(private) +unindent :: proc(p: ^Printer) { + p.depth -= 1; +} + +@(private) +visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) { + + using ast; + + if decl == nil { + return; + } + + switch v in decl.derived { + case Expr_Stmt: + move_line(p, decl.pos); + visit_expr(p, v.expr); + if p.config.semicolons { + push_generic_token(p, .Semicolon, 0); + } + case When_Stmt: + visit_stmt(p, cast(^Stmt)decl); + case Foreign_Import_Decl: + if len(v.attributes) > 0 { + move_line(p, v.attributes[0].pos); + } else { + move_line(p, decl.pos); + } + + visit_attributes(p, v.attributes); + + push_generic_token(p, v.foreign_tok.kind, 0); + push_generic_token(p, v.import_tok.kind, 1); + + if v.name != nil { + push_ident_token(p, v.name.name, 1); + } + + for path in v.fullpaths { + push_ident_token(p, path, 0); + } + case Foreign_Block_Decl: + + if len(v.attributes) > 0 { + move_line(p, v.attributes[0].pos); + } else { + move_line(p, decl.pos); + } + + visit_attributes(p, v.attributes); + + push_generic_token(p, .Foreign, 0); + + visit_expr(p, v.foreign_library); + visit_stmt(p, v.body); + case Import_Decl: + move_line(p, decl.pos); + + if v.name.text != "" { + push_generic_token(p, v.import_tok.kind, 1); + push_generic_token(p, v.name.kind, 1); + push_ident_token(p, v.fullpath, 0); + } else { + push_generic_token(p, v.import_tok.kind, 1); + push_ident_token(p, v.fullpath, 0); + } + + case Value_Decl: + if len(v.attributes) > 0 { + move_line(p, v.attributes[0].pos); + visit_attributes(p, v.attributes); + } + + move_line(p, decl.pos); + + if v.is_using { + push_generic_token(p, .Using, 0); + } + + visit_exprs(p, v.names, true); + + if v.type != nil { + if !v.is_mutable && v.type != nil { + push_generic_token(p, .Colon, 1); + } else { + push_generic_token(p, .Colon, 1); + } + + visit_expr(p, v.type); + } else { + if !v.is_mutable && v.type == nil { + push_generic_token(p, .Colon, 1); + push_generic_token(p, .Colon, 0); + } else { + push_generic_token(p, .Colon, 1); + } + } + + if v.is_mutable && v.type != nil && len(v.values) != 0 { + push_generic_token(p, .Eq, 0); + } else if v.is_mutable && v.type == nil && len(v.values) != 0 { + push_generic_token(p, .Eq, 0); + } else if !v.is_mutable && v.type != nil { + push_generic_token(p, .Semicolon, 0); + } + + visit_exprs(p, v.values, true); + + add_semicolon := true; + + for value in v.values { + switch a in value.derived { + case Proc_Lit,Union_Type,Enum_Type,Struct_Type: + add_semicolon = false || called_in_stmt; + } + } + + if add_semicolon && p.config.semicolons && !p.skip_semicolon { + push_generic_token(p, .Semicolon, 0); + } + + case: + panic(fmt.aprint(decl.derived)); + } +} + +@(private) +visit_exprs :: proc(p: ^Printer, list: []^ast.Expr, add_comma := false, trailing := false) { + + if len(list) == 0 { + return; + } + + //we have to newline the expressions to respect the source + for expr, i in list { + + move_line_limit(p, expr.pos, 1); + + visit_expr(p, expr); + + if i != len(list) - 1 && add_comma { + push_generic_token(p, .Comma, 0); + } else if trailing && add_comma { + //print(p, strings.trim_space(sep)); + } + } +} + +@(private) +visit_attributes :: proc(p: ^Printer, attributes: [dynamic]^ast.Attribute) { + +} + +@(private) +visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Generic, empty_block := false, block_stmt := false) { + + using ast; + + if stmt == nil { + return; + } + + switch v in stmt.derived { + case Value_Decl: + visit_decl(p, cast(^Decl)stmt, true); + return; + case Foreign_Import_Decl: + visit_decl(p, cast(^Decl)stmt, true); + return; + case Foreign_Block_Decl: + visit_decl(p, cast(^Decl)stmt, true); + return; + } + + switch v in stmt.derived { + case Using_Stmt: + move_line(p, v.pos); + + push_generic_token(p, .Using, 1); + + visit_exprs(p, v.list, true); + + if p.config.semicolons { + push_generic_token(p, .Semicolon, 0); + } + case Block_Stmt: + move_line(p, v.pos); + + 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); + } + + set_source_position(p, v.pos); + + visit_block_stmts(p, v.stmts, true); + + set_source_position(p, v.end); + + if !empty_block { + visit_end_brace(p, v.end); + } + } else if v.pos.line == v.end.line { + if !empty_block { + push_generic_token(p, .Open_Brace, 0); + } + + set_source_position(p, v.pos); + + visit_block_stmts(p, v.stmts); + + set_source_position(p, v.end); + + if !empty_block { + push_generic_token(p, .Close_Brace, 0); + } + } else { + if !empty_block { + visit_begin_brace(p, v.pos, block_type); + } + + set_source_position(p, v.pos); + + visit_block_stmts(p, v.stmts); + + set_source_position(p, v.end); + + if !empty_block { + visit_end_brace(p, v.end); + } + } + case If_Stmt: + move_line(p, v.pos); + + if v.label != nil { + visit_expr(p, v.label); + push_generic_token(p, .Colon, 0); + } + + push_generic_token(p, .If, 1); + + if v.init != nil { + p.skip_semicolon = true; + visit_stmt(p, v.init); + p.skip_semicolon = false; + push_generic_token(p, .Semicolon, 0); + } + + visit_expr(p, v.cond); + + uses_do := false; + + if check_stmt, ok := v.body.derived.(Block_Stmt); ok && check_stmt.uses_do { + uses_do = true; + } + + if uses_do && !p.config.convert_do { + push_generic_token(p, .Do, 1); + visit_stmt(p, v.body, .If_Stmt, true); + } else { + if uses_do { + newline_source_position(p, 1); + } + + visit_stmt(p, v.body, .If_Stmt); + } + + if v.else_stmt != nil { + + if p.config.brace_style == .Allman || p.config.brace_style == .Stroustrup { + newline_source_position(p, 1); + } + + push_generic_token(p, .Else, 1); + + set_source_position(p, v.else_stmt.pos); + + visit_stmt(p, v.else_stmt); + } + case Switch_Stmt: + move_line(p, v.pos); + + if v.label != nil { + visit_expr(p, v.label); + push_generic_token(p, .Colon, 0); + } + + if v.partial { + push_ident_token(p, "#partial", 0); + } + + push_generic_token(p, .Switch, 0); + + if v.init != nil { + p.skip_semicolon = true; + visit_stmt(p, v.init); + p.skip_semicolon = false; + } + + if v.init != nil && v.cond != nil { + push_generic_token(p, .Semicolon, 0); + } + + visit_expr(p, v.cond); + visit_stmt(p, v.body); + case Case_Clause: + move_line(p, v.pos); + + if !p.config.indent_cases { + unindent(p); + } + + push_generic_token(p, .Case, 0); + + if v.list != nil { + visit_exprs(p, v.list, true); + } + + push_generic_token(p, v.terminator.kind, 0); + + indent(p); + + visit_block_stmts(p, v.body); + + unindent(p); + + if !p.config.indent_cases { + indent(p); + } + case Type_Switch_Stmt: + move_line(p, v.pos); + + if v.label != nil { + visit_expr(p, v.label); + push_generic_token(p, .Colon, 0); + } + + if v.partial { + push_ident_token(p, "partial", 0); + } + + push_generic_token(p, .Switch, 0); + + visit_stmt(p, v.tag); + visit_stmt(p, v.body); + case Assign_Stmt: + move_line(p, v.pos); + + visit_exprs(p, v.lhs, true); + + push_generic_token(p, v.op.kind, 1); + + visit_exprs(p, v.rhs, true); + + if block_stmt && p.config.semicolons { + push_generic_token(p, .Semicolon, 0); + } + case Expr_Stmt: + move_line(p, v.pos); + visit_expr(p, v.expr); + if block_stmt && p.config.semicolons { + push_generic_token(p, .Semicolon, 0); + } + case For_Stmt: + //this should be simplified + move_line(p, v.pos); + + if v.label != nil { + visit_expr(p, v.label); + push_generic_token(p, .Colon, 1); + } + + push_generic_token(p, .For, 0); + + //if v.init != nil || v.cond != nil || v.post != nil { + // print(p, space); + //} + + if v.init != nil { + p.skip_semicolon = true; + visit_stmt(p, v.init); + p.skip_semicolon = false; + push_generic_token(p, .Semicolon, 0); + } else if v.post != nil { + push_generic_token(p, .Semicolon, 0); + } + + if v.cond != nil { + visit_expr(p, v.cond); + } + + if v.post != nil { + push_generic_token(p, .Semicolon, 0); + //print(p, space); + visit_stmt(p, v.post); + } else if v.post == nil && v.cond != nil && v.init != nil { + push_generic_token(p, .Semicolon, 0); + } + + visit_stmt(p, v.body); + case Inline_Range_Stmt: + + move_line(p, v.pos); + + if v.label != nil { + visit_expr(p, v.label); + push_generic_token(p, .Colon, 1); + } + + push_ident_token(p, "#unroll", 0); + + push_generic_token(p, .For, 0); + visit_expr(p, v.val0); + + if v.val1 != nil { + push_generic_token(p, .Comma, 0); + visit_expr(p, v.val1); + } + + push_generic_token(p, .In, 1); + + visit_expr(p, v.expr); + visit_stmt(p, v.body); + case Range_Stmt: + + move_line(p, v.pos); + + if v.label != nil { + visit_expr(p, v.label); + push_generic_token(p, .Colon, 1); + } + + push_generic_token(p, .For, 0); + + if len(v.vals) >= 1 { + visit_expr(p, v.vals[0]); + } + + if len(v.vals) >= 2 { + push_generic_token(p, .Comma, 0); + visit_expr(p, v.vals[1]); + } + + push_generic_token(p, .In, 1); + + visit_expr(p, v.expr); + + visit_stmt(p, v.body); + case Return_Stmt: + move_line(p, v.pos); + + push_generic_token(p, .Return, 0); + + if v.results != nil { + visit_exprs(p, v.results, true); + } + + if block_stmt && p.config.semicolons { + push_generic_token(p, .Semicolon, 0); + } + case Defer_Stmt: + move_line(p, v.pos); + push_generic_token(p, .Defer, 0); + + visit_stmt(p, v.stmt); + + if p.config.semicolons { + push_generic_token(p, .Semicolon, 0); + } + case When_Stmt: + move_line(p, v.pos); + push_generic_token(p, .When, 0); + visit_expr(p, v.cond); + + visit_stmt(p, v.body); + + if v.else_stmt != nil { + + if p.config.brace_style == .Allman { + newline_source_position(p, 1); + } + + push_generic_token(p, .Else, 0); + + set_source_position(p, v.else_stmt.pos); + + visit_stmt(p, v.else_stmt); + } + + case Branch_Stmt: + + move_line(p, v.pos); + + push_generic_token(p, v.tok.kind, 0); + + if v.label != nil { + visit_expr(p, v.label); + } + + if p.config.semicolons { + push_generic_token(p, .Semicolon, 0); + } + case: + panic(fmt.aprint(stmt.derived)); + } + + set_source_position(p, stmt.end); +} -print_expr :: proc(p: ^Printer, expr: ^ast.Expr) { +@(private) +visit_expr :: proc(p: ^Printer, expr: ^ast.Expr) { using ast; @@ -45,360 +652,417 @@ print_expr :: proc(p: ^Printer, expr: ^ast.Expr) { switch v in expr.derived { case Inline_Asm_Expr: - //TEMP - //this is probably not fully done, but need more examples - /* - Inline_Asm_Expr :: struct { - using node: Expr, - tok: tokenizer.Token, - param_types: []^Expr, - return_type: ^Expr, - has_side_effects: bool, - is_align_stack: bool, - dialect: Inline_Asm_Dialect, - open: tokenizer.Pos, - constraints_string: ^Expr, - asm_string: ^Expr, - close: tokenizer.Pos, - } - */ - - /* - cpuid :: proc(ax, cx: u32) -> (eax, ebc, ecx, edx: u32) { - return expand_to_tuple(asm(u32, u32) -> struct{eax, ebc, ecx, edx: u32} { - "cpuid", - "={ax},={bx},={cx},={dx},{ax},{cx}", - }(ax, cx)); - } - */ - + /* print(p, v.tok, space, lparen); - print_exprs(p, v.param_types, ", "); + visit_exprs(p, v.param_types, ", "); print(p, rparen, space); print(p, "->", space); - print_expr(p, v.return_type); + visit_expr(p, v.return_type); print(p, space); print(p, lbrace); - print_expr(p, v.asm_string); + visit_expr(p, v.asm_string); print(p, ", "); - print_expr(p, v.constraints_string); + visit_expr(p, v.constraints_string); print(p, rbrace); - + */ case Undef: - print(p, "---"); + push_generic_token(p, .Undef, 1); case Auto_Cast: - print(p, v.op, space); - print_expr(p, v.expr); + push_generic_token(p, v.op.kind, 1); + visit_expr(p, v.expr); case Ternary_Expr: - print_expr(p, v.cond); - print(p, space, v.op1, space); - print_expr(p, v.x); - print(p, space, v.op2, space); - print_expr(p, v.y); + visit_expr(p, v.cond); + push_generic_token(p, v.op1.kind, 1); + visit_expr(p, v.x); + push_generic_token(p, v.op2.kind, 1); + visit_expr(p, v.y); case Ternary_If_Expr: - print_expr(p, v.x); - print(p, space, v.op1, space); - print_expr(p, v.cond); - print(p, space, v.op2, space); - print_expr(p, v.y); + visit_expr(p, v.x); + push_generic_token(p, v.op1.kind, 1); + visit_expr(p, v.cond); + push_generic_token(p, v.op2.kind, 1); + visit_expr(p, v.y); case Ternary_When_Expr: - print_expr(p, v.x); - print(p, space, v.op1, space); - print_expr(p, v.cond); - print(p, space, v.op2, space); - print_expr(p, v.y); + visit_expr(p, v.x); + push_generic_token(p, v.op1.kind, 1); + visit_expr(p, v.cond); + push_generic_token(p, v.op2.kind, 1); + visit_expr(p, v.y); case Selector_Call_Expr: - print_expr(p, v.call.expr); - print(p, lparen); - print_exprs(p, v.call.args, ", "); - print(p, rparen); + visit_expr(p, v.call.expr); + push_generic_token(p, .Open_Paren, 1); + visit_exprs(p, v.call.args, true); + push_generic_token(p, .Close_Paren, 0); case Ellipsis: - print(p, ".."); - print_expr(p, v.expr); + push_generic_token(p, .Ellipsis, 1); + visit_expr(p, v.expr); case Relative_Type: - print_expr(p, v.tag); - print(p, space); - print_expr(p, v.type); + visit_expr(p, v.tag); + visit_expr(p, v.type); case Slice_Expr: - print_expr(p, v.expr); - print(p, lbracket); - print_expr(p, v.low); - print(p, v.interval); - print_expr(p, v.high); - print(p, rbracket); + visit_expr(p, v.expr); + push_generic_token(p, .Open_Bracket, 1); + visit_expr(p, v.low); + push_generic_token(p, v.interval.kind, 0); + visit_expr(p, v.high); + push_generic_token(p, .Close_Bracket, 0); case Ident: - print(p, v); + push_ident_token(p, v.name, 1); case Deref_Expr: - print_expr(p, v.expr); - print(p, v.op); + visit_expr(p, v.expr); + push_generic_token(p, v.op.kind, 0); case Type_Cast: - print(p, v.tok, lparen); - print_expr(p, v.type); - print(p, rparen); - print_expr(p, v.expr); + push_generic_token(p, v.tok.kind, 0); + push_generic_token(p, .Open_Paren, 1); + visit_expr(p, v.type); + push_generic_token(p, .Close_Paren, 0); + visit_expr(p, v.expr); case Basic_Directive: - print(p, v.tok, v.name); + push_generic_token(p, v.tok.kind, 0); + push_ident_token(p, v.name, 0); case Distinct_Type: - print(p, "distinct", space); - print_expr(p, v.type); + push_generic_token(p, .Distinct, 0); + visit_expr(p, v.type); case Dynamic_Array_Type: - print_expr(p, v.tag); - print(p, lbracket, "dynamic", rbracket); - print_expr(p, v.elem); + visit_expr(p, v.tag); + push_generic_token(p, .Open_Bracket, 1); + push_generic_token(p, .Dynamic, 0); + push_generic_token(p, .Close_Bracket, 0); + visit_expr(p, v.elem); case Bit_Set_Type: - print(p, "bit_set", lbracket); - print_expr(p, v.elem); + push_generic_token(p, .Bit_Set, 0); + push_generic_token(p, .Open_Bracket, 0); + + visit_expr(p, v.elem); if v.underlying != nil { - print(p, semicolon, space); - print_expr(p, v.underlying); + push_generic_token(p, .Semicolon, 0); + visit_expr(p, v.underlying); } - print(p, rbracket); + push_generic_token(p, .Close_Bracket, 0); case Union_Type: - print(p, "union"); + push_generic_token(p, .Union, 0); if v.poly_params != nil { - print(p, lparen); - print_field_list(p, v.poly_params, ", "); - print(p, rparen); + push_generic_token(p, .Open_Paren, 0); + visit_field_list(p, v.poly_params, ", "); + push_generic_token(p, .Close_Paren, 0); } if v.is_maybe { - print(p, space, "#maybe"); + push_ident_token(p, "#maybe", 1); } if v.variants != nil && (len(v.variants) == 0 || v.pos.line == v.end.line) { - print(p, space, lbrace); + push_generic_token(p, .Open_Brace, 1); set_source_position(p, v.variants[len(v.variants) - 1].pos); - print_exprs(p, v.variants, ", "); - print(p, rbrace); + visit_exprs(p, v.variants, true); + push_generic_token(p, .Close_Brace, 0); } else { - print_begin_brace(p, v.pos, .Generic); - print(p, newline); + visit_begin_brace(p, v.pos, .Generic); + newline_source_position(p, 1); set_source_position(p, v.variants[len(v.variants) - 1].pos); - print_exprs(p, v.variants, ",", true); - print_end_brace(p, v.end); + visit_exprs(p, v.variants, true, true); + visit_end_brace(p, v.end); } case Enum_Type: - print(p, "enum"); + push_generic_token(p, .Enum, 0); if v.base_type != nil { - print(p, space); - print_expr(p, v.base_type); + visit_expr(p, v.base_type); } if v.fields != nil && (len(v.fields) == 0 || v.pos.line == v.end.line) { - print(p, space, lbrace); + push_generic_token(p, .Open_Brace, 1); set_source_position(p, v.fields[len(v.fields) - 1].pos); - print_exprs(p, v.fields, ", "); - print(p, rbrace); + visit_exprs(p, v.fields, true); + push_generic_token(p, .Close_Brace, 0); } else { - print_begin_brace(p, v.pos, .Generic); - print(p, newline); + visit_begin_brace(p, v.pos, .Generic); + newline_source_position(p, 1); set_source_position(p, v.fields[len(v.fields) - 1].pos); - print_enum_fields(p, v.fields, ","); - print_end_brace(p, v.end); + //visit_enum_fields(p, v.fields, ","); + visit_exprs(p, v.fields, true); + visit_end_brace(p, v.end); } set_source_position(p, v.end); case Struct_Type: - print(p, "struct"); + push_generic_token(p, .Struct, 0); if v.is_packed { - print(p, space, "#packed"); + push_ident_token(p, "#packed", 1); } if v.is_raw_union { - print(p, space, "#raw_union"); + push_ident_token(p, "#raw_union", 1); } if v.align != nil { - print(p, space, "#align", space); - print_expr(p, v.align); + push_ident_token(p, "#align", 1); + visit_expr(p, v.align); } if v.poly_params != nil { - print(p, lparen); - print_field_list(p, v.poly_params, ", "); - print(p, rparen); + push_generic_token(p, .Open_Paren, 0); + visit_field_list(p, v.poly_params, ", "); + push_generic_token(p, .Close_Paren, 0); } if v.fields != nil && (len(v.fields.list) == 0 || v.pos.line == v.end.line) { - print(p, space, lbrace); + push_generic_token(p, .Open_Brace, 1); set_source_position(p, v.fields.pos); - print_field_list(p, v.fields, ", "); - print(p, rbrace); + visit_field_list(p, v.fields, ", "); + push_generic_token(p, .Close_Brace, 0); } else { - print_begin_brace(p, v.pos, .Generic); - print(p, newline); + visit_begin_brace(p, v.pos, .Generic); + newline_source_position(p, 1); set_source_position(p, v.fields.pos); - print_struct_field_list(p, v.fields, ","); - print_end_brace(p, v.end); + visit_field_list(p, v.fields, ", "); + //visit_struct_field_list(p, v.fields, ","); + visit_end_brace(p, v.end); } set_source_position(p, v.end); case Proc_Lit: if v.inlining == .Inline { - print(p, "#force_inline", space); + push_ident_token(p, "#force_inline", 0); } - print_proc_type(p, v.type^); + visit_proc_type(p, v.type^); if v.where_clauses != nil { - print(p, space); - newline_until_pos(p, v.where_clauses[0].pos); - print(p, "where", space); - print_exprs(p, v.where_clauses, ", "); + move_line(p, v.where_clauses[0].pos); + push_generic_token(p, .Where, 1); + visit_exprs(p, v.where_clauses, true); } if v.body != nil { set_source_position(p, v.body.pos); - print_stmt(p, v.body, .Proc); + visit_stmt(p, v.body, .Proc); } else { - print(p, space, "---"); + push_generic_token(p, .Ellipsis, 1); } case Proc_Type: - print_proc_type(p, v); + visit_proc_type(p, v); case Basic_Lit: - print(p, v.tok); + push_generic_token(p, v.tok.kind, 1, v.tok.text); case Binary_Expr: - print_binary_expr(p, v); + visit_binary_expr(p, v); case Implicit_Selector_Expr: - print(p, dot, v.field^); + push_generic_token(p, .Period, 0); + push_ident_token(p, v.field.name, 0); case Call_Expr: - print_expr(p, v.expr); - print(p, lparen); - - padding := get_length_of_names({v.expr}); - - print_call_exprs(p, v.args, ", ", v.ellipsis.kind == .Ellipsis, padding); - print(p, rparen); + visit_expr(p, v.expr); + push_generic_token(p, .Open_Paren, 0); + visit_call_exprs(p, v.args, v.ellipsis.kind == .Ellipsis); + push_generic_token(p, .Close_Paren, 0); case Typeid_Type: - print(p, "typeid"); + push_generic_token(p, .Typeid, 0); + if v.specialization != nil { - print(p, "/"); - print_expr(p, v.specialization); + push_generic_token(p, .Quo, 0); + visit_expr(p, v.specialization); } case Selector_Expr: - print_expr(p, v.expr); - print(p, v.op); - print_expr(p, v.field); + visit_expr(p, v.expr); + push_generic_token(p, v.op.kind, 0); + visit_expr(p, v.field); case Paren_Expr: - print(p, lparen); - print_expr(p, v.expr); - print(p, rparen); + push_generic_token(p, .Open_Paren, 1); + visit_expr(p, v.expr); + push_generic_token(p, .Close_Paren, 0); case Index_Expr: - print_expr(p, v.expr); - print(p, lbracket); - print_expr(p, v.index); - print(p, rbracket); + visit_expr(p, v.expr); + push_generic_token(p, .Open_Bracket, 1); + visit_expr(p, v.index); + push_generic_token(p, .Close_Bracket, 0); case Proc_Group: - - print(p, v.tok); + + push_generic_token(p, v.tok.kind, 0); if len(v.args) != 0 && v.pos.line != v.args[len(v.args) - 1].pos.line { - print_begin_brace(p, v.pos, .Generic); - print(p, newline); + visit_begin_brace(p, v.pos, .Generic); + newline_source_position(p, 1); set_source_position(p, v.args[len(v.args) - 1].pos); - print_exprs(p, v.args, ",", true); - print_end_brace(p, v.end); + visit_exprs(p, v.args, true, true); + visit_end_brace(p, v.end); } else { - print(p, space, lbrace); - print_exprs(p, v.args, ", "); - print(p, rbrace); + push_generic_token(p, .Open_Brace, 0); + visit_exprs(p, v.args, true); + push_generic_token(p, .Close_Brace, 0); } + case Comp_Lit: - + if v.type != nil { - print_expr(p, v.type); - print(p, space); + visit_expr(p, v.type); } if len(v.elems) != 0 && v.pos.line != v.elems[len(v.elems) - 1].pos.line { - print_begin_brace(p, v.pos, .Comp_Lit); - print(p, newline); + visit_begin_brace(p, v.pos, .Comp_Lit); + newline_source_position(p, 1); set_source_position(p, v.elems[len(v.elems) - 1].pos); - print_exprs(p, v.elems, ",", true); - print_end_brace(p, v.end); + visit_exprs(p, v.elems, true, true); + visit_end_brace(p, v.end); } else { - print(p, lbrace); - print_exprs(p, v.elems, ", "); - print(p, rbrace); + push_generic_token(p, .Open_Brace, 0); + visit_exprs(p, v.elems, true); + push_generic_token(p, .Close_Brace, 0); } + case Unary_Expr: - print(p, v.op); - print_expr(p, v.expr); + push_generic_token(p, v.op.kind, 0); + visit_expr(p, v.expr); case Field_Value: - print_expr(p, v.field); - print(p, space, "=", space); - print_expr(p, v.value); + visit_expr(p, v.field); + push_generic_token(p, .Eq, 1); + visit_expr(p, v.value); case Type_Assertion: - print_expr(p, v.expr); + visit_expr(p, v.expr); if unary, ok := v.type.derived.(Unary_Expr); ok && unary.op.text == "?" { - print(p, dot); - print_expr(p, v.type); + push_generic_token(p, .Period, 0); + visit_expr(p, v.type); } else { - print(p, dot, lparen); - print_expr(p, v.type); - print(p, rparen); + push_generic_token(p, .Period, 0); + push_generic_token(p, .Open_Paren, 0); + visit_expr(p, v.type); + push_generic_token(p, .Close_Paren, 0); } case Pointer_Type: - print(p, "^"); - print_expr(p, v.elem); + push_generic_token(p, .Pointer, 0); + visit_expr(p, v.elem); case Implicit: - print(p, v.tok); + push_generic_token(p, v.tok.kind, 0); case Poly_Type: - print(p, "$"); - print_expr(p, v.type); + push_generic_token(p, .Dollar, 0); + + visit_expr(p, v.type); if v.specialization != nil { - print(p, "/"); - print_expr(p, v.specialization); + push_generic_token(p, .Quo, 0); + visit_expr(p, v.specialization); } case Array_Type: - print_expr(p, v.tag); - print(p, lbracket); - print_expr(p, v.len); - print(p, rbracket); - print_expr(p, v.elem); + visit_expr(p, v.tag); + push_generic_token(p, .Open_Bracket, 1); + visit_expr(p, v.len); + push_generic_token(p, .Close_Bracket, 0); + visit_expr(p, v.elem); case Map_Type: - print(p, "map", lbracket); - print_expr(p, v.key); - print(p, rbracket); - print_expr(p, v.value); + push_generic_token(p, .Map, 0); + push_generic_token(p, .Open_Bracket, 0); + visit_expr(p, v.key); + push_generic_token(p, .Close_Bracket, 0); + visit_expr(p, v.value); case Helper_Type: - print_expr(p, v.type); + visit_expr(p, v.type); case: panic(fmt.aprint(expr.derived)); } } -print_proc_type :: proc(p: ^Printer, proc_type: ast.Proc_Type) { - print(p, "proc"); //TOOD(ast is missing proc token) +visit_begin_brace :: proc(p: ^Printer, begin: tokenizer.Pos, type: Block_Type) { + + set_source_position(p, begin); + + newline_braced := p.config.brace_style == .Allman; + newline_braced |= p.config.brace_style == .K_And_R && type == .Proc; + newline_braced &= p.config.brace_style != ._1TBS; + + if newline_braced { + newline_source_position(p, 1); + push_generic_token(p, .Open_Brace, 0); + indent(p); + } else { + push_generic_token(p, .Open_Brace, 1); + indent(p); + } +} + +visit_end_brace :: proc(p: ^Printer, end: tokenizer.Pos) { + set_source_position(p, end); + newline_source_position(p, 1); + unindent(p); + push_generic_token(p, .Close_Brace, 0); +} + +visit_block_stmts :: proc(p: ^Printer, stmts: []^ast.Stmt, newline_each := false) { + for stmt, i in stmts { + + if newline_each { + newline_source_position(p, 1); + } + + visit_stmt(p, stmt, .Generic, false, true); + } +} + +visit_field_list :: proc(p: ^Printer, list: ^ast.Field_List, sep := "") { + + if list.list == nil { + return; + } + + for field, i in list.list { + + move_line_limit(p, field.pos, 1); + + if .Using in field.flags { + push_generic_token(p, .Using, 0); + } + + visit_exprs(p, field.names, true); + + if len(field.names) != 0 { + push_generic_token(p, .Colon, 0); + } + + if field.type != nil { + visit_expr(p, field.type); + } else { + push_generic_token(p, .Colon, 0); + push_generic_token(p, .Eq, 0); + visit_expr(p, field.default_value); + } + + if field.tag.text != "" { + push_generic_token(p, field.tag.kind, 1); + } + + if i != len(list.list) - 1 { + //print(p, sep); + } + } +} + +visit_proc_type :: proc(p: ^Printer, proc_type: ast.Proc_Type) { + + push_generic_token(p, .Proc, 1); if proc_type.calling_convention != .Odin { - print(p, space); + //print(p, space); } switch proc_type.calling_convention { case .Odin: case .Contextless: - print(p, "\"contextless\"", space); + push_string_token(p, "\"contextless\"", 0); case .C_Decl: - print(p, "\"c\"", space); + push_string_token(p, "\"c\"", 0); case .Std_Call: - print(p, "\"std\"", space); + push_string_token(p, "\"std\"", 0); case .Fast_Call: - print(p, "\"fast\"", space); + push_string_token(p, "\"fast\"", 0); case .None: //nothing i guess case .Invalid: @@ -406,10 +1070,13 @@ print_proc_type :: proc(p: ^Printer, proc_type: ast.Proc_Type) { case .Foreign_Block_Default: } - print(p, lparen); - print_signature_list(p, proc_type.params, ", ", false); - print(p, rparen); + push_generic_token(p, .Open_Paren, 0); + //visit_signature_list(p, proc_type.params, ", ", false); + + push_generic_token(p, .Close_Paren, 0); + + /* if proc_type.results != nil { print(p, space, "->", space); @@ -437,19 +1104,88 @@ print_proc_type :: proc(p: ^Printer, proc_type: ast.Proc_Type) { print_signature_list(p, proc_type.results, ", "); } } + */ } +visit_binary_expr :: proc(p: ^Printer, binary: ast.Binary_Expr) { + + move_line(p, binary.left.pos); + + if v, ok := binary.left.derived.(ast.Binary_Expr); ok { + visit_binary_expr(p, v); + } else { + visit_expr(p, binary.left); + } + + if binary.op.kind == .Ellipsis || binary.op.kind == .Range_Half { + push_generic_token(p, binary.op.kind, 0); + } else { + push_generic_token(p, binary.op.kind, 1); + } + + move_line(p, binary.right.pos); + + if v, ok := binary.right.derived.(ast.Binary_Expr); ok { + visit_binary_expr(p, v); + } else { + visit_expr(p, binary.right); + } + +} + +visit_call_exprs :: proc(p: ^Printer, list: []^ast.Expr, ellipsis := false) { + + if len(list) == 0 { + return; + } + + //all the expression are on the line + if list[0].pos.line == list[len(list) - 1].pos.line { + for expr, i in list { + + if i == len(list) - 1 && ellipsis { + push_generic_token(p, .Ellipsis, 0); + } + + visit_expr(p, expr); + + if i != len(list) - 1 { + push_generic_token(p, .Comma, 0); + } + } + } else { + for expr, i in list { + + //we have to newline the expressions to respect the source + move_line_limit(p, expr.pos, 1); + + + if i == len(list) - 1 && ellipsis { + push_generic_token(p, .Ellipsis, 0); + } + + visit_expr(p, expr); + + if i != len(list) - 1 { + push_generic_token(p, .Comma, 0); + } + } + } +} + +/* + print_enum_fields :: proc(p: ^Printer, list: []^ast.Expr, sep := " ") { - //print enum fields is like print_exprs, but it can contain fields that can be aligned. + //print enum fields is like visit_exprs, but it can contain fields that can be aligned. if len(list) == 0 { return; } if list[0].pos.line == list[len(list) - 1].pos.line { - //if everything is on one line, then it can be treated the same way as print_exprs - print_exprs(p, list, sep); + //if everything is on one line, then it can be treated the same way as visit_exprs + visit_exprs(p, list, sep); return; } @@ -469,20 +1205,20 @@ print_enum_fields :: proc(p: ^Printer, list: []^ast.Expr, sep := " ") { for expr, i in list { - newline_until_pos_limit(p, expr.pos, 1); + move_line_limit(p, expr.pos, 1); if field_value, ok := expr.derived.(ast.Field_Value); ok && p.config.align_assignments { if ident, ok := field_value.field.derived.(ast.Ident); ok { - print_expr(p, field_value.field); + visit_expr(p, field_value.field); print_space_padding(p, largest - strings.rune_count(ident.name) + 1); print(p, "=", space); - print_expr(p, field_value.value); + visit_expr(p, field_value.value); } else { - print_expr(p, expr); + visit_expr(p, expr); } } else { - print_expr(p, expr); + visit_expr(p, expr); } if i != len(list) - 1 { @@ -493,94 +1229,11 @@ print_enum_fields :: proc(p: ^Printer, list: []^ast.Expr, sep := " ") { } } -print_call_exprs :: proc(p: ^Printer, list: []^ast.Expr, sep := " ", ellipsis := false, padding := 0) { - if len(list) == 0 { - return; - } - //all the expression are on the line - if list[0].pos.line == list[len(list) - 1].pos.line { - for expr, i in list { - if i == len(list) - 1 && ellipsis { - print(p, ".."); - } - print_expr(p, expr); - - if i != len(list) - 1 { - print(p, sep); - } - } - } else { - - for expr, i in list { - - //we have to newline the expressions to respect the source - if newline_until_pos_limit(p, expr.pos, 1) { - print_space_padding(p, padding); - } - - if i == len(list) - 1 && ellipsis { - print(p, ".."); - } - - print_expr(p, expr); - - if i != len(list) - 1 { - print(p, sep); - } - } - } -} - -print_exprs :: proc(p: ^Printer, list: []^ast.Expr, sep := " ", trailing := false) { - - if len(list) == 0 { - return; - } - - //we have to newline the expressions to respect the source - for expr, i in list { - - newline_until_pos_limit(p, expr.pos, 1); - - print_expr(p, expr); - - if i != len(list) - 1 { - print(p, sep); - } else if trailing { - print(p, strings.trim_space(sep)); - } - } -} - -print_binary_expr :: proc(p: ^Printer, binary: ast.Binary_Expr) { - - newline_until_pos(p, binary.left.pos); - - if v, ok := binary.left.derived.(ast.Binary_Expr); ok { - print_binary_expr(p, v); - } else { - print_expr(p, binary.left); - } - - if binary.op.kind == .Ellipsis || binary.op.kind == .Range_Half { - print(p, binary.op); - } else { - print(p, space, binary.op, space); - } - - newline_until_pos(p, binary.right.pos); - - if v, ok := binary.right.derived.(ast.Binary_Expr); ok { - print_binary_expr(p, v); - } else { - print_expr(p, binary.right); - } -} print_struct_field_list :: proc(p: ^Printer, list: ^ast.Field_List, sep := "") { @@ -603,13 +1256,13 @@ print_struct_field_list :: proc(p: ^Printer, list: ^ast.Field_List, sep := "") { for field, i in list.list { - newline_until_pos_limit(p, field.pos, 1); + move_line_limit(p, field.pos, 1); if .Using in field.flags { print(p, "using", space); } - print_exprs(p, field.names, ", "); + visit_exprs(p, field.names, ", "); if len(field.names) != 0 { print(p, ": "); @@ -625,7 +1278,7 @@ print_struct_field_list :: proc(p: ^Printer, list: ^ast.Field_List, sep := "") { print_space_padding(p, largest - get_length_of_names(field.names)); } - print_expr(p, field.type); + visit_expr(p, field.type); if field.tag.text != "" { print(p, space, field.tag); @@ -639,43 +1292,6 @@ print_struct_field_list :: proc(p: ^Printer, list: ^ast.Field_List, sep := "") { } } -print_field_list :: proc(p: ^Printer, list: ^ast.Field_List, sep := "") { - - if list.list == nil { - return; - } - - for field, i in list.list { - - newline_until_pos_limit(p, field.pos, 1); - - if .Using in field.flags { - print(p, "using", space); - } - - print_exprs(p, field.names, ", "); - - if len(field.names) != 0 { - print(p, ": "); - } - - if field.type != nil { - print_expr(p, field.type); - } else { - print(p, ":= "); - print_expr(p, field.default_value); - } - - if field.tag.text != "" { - print(p, space, field.tag); - } - - if i != len(list.list) - 1 { - print(p, sep); - } - } -} - print_signature_list :: proc(p: ^Printer, list: ^ast.Field_List, sep := "", remove_blank := true) { if list.list == nil { @@ -684,7 +1300,7 @@ print_signature_list :: proc(p: ^Printer, list: ^ast.Field_List, sep := "", remo for field, i in list.list { - newline_until_pos_limit(p, field.pos, 1); + move_line_limit(p, field.pos, 1); if .Using in field.flags { print(p, "using", space); @@ -705,7 +1321,7 @@ print_signature_list :: proc(p: ^Printer, list: ^ast.Field_List, sep := "", remo } if named { - print_exprs(p, field.names, ", "); + visit_exprs(p, field.names, ", "); if len(field.names) != 0 && field.type != nil { print(p, ": "); @@ -715,14 +1331,14 @@ print_signature_list :: proc(p: ^Printer, list: ^ast.Field_List, sep := "", remo } if field.type != nil && field.default_value != nil { - print_expr(p, field.type); + visit_expr(p, field.type); print(p, space, "=", space); - print_expr(p, field.default_value); + visit_expr(p, field.default_value); } else if field.type != nil { - print_expr(p, field.type); + visit_expr(p, field.type); } else { print(p, ":= "); - print_expr(p, field.default_value); + visit_expr(p, field.default_value); } if i != len(list.list) - 1 { @@ -731,530 +1347,7 @@ print_signature_list :: proc(p: ^Printer, list: ^ast.Field_List, sep := "", remo } } -print_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Generic, empty_block := false, block_stmt := false) { - using ast; - - if stmt == nil { - return; - } - - switch v in stmt.derived { - case Value_Decl: - print_decl(p, cast(^Decl)stmt, true); - return; - case Foreign_Import_Decl: - print_decl(p, cast(^Decl)stmt, true); - return; - case Foreign_Block_Decl: - print_decl(p, cast(^Decl)stmt, true); - return; - } - - switch v in stmt.derived { - case Using_Stmt: - newline_until_pos(p, v.pos); - print(p, "using", space); - print_exprs(p, v.list, ", "); - - if p.config.semicolons { - print(p, semicolon); - } - case Block_Stmt: - newline_until_pos(p, v.pos); - - if v.pos.line == v.end.line && len(v.stmts) > 1 && p.config.split_multiple_stmts { - - if !empty_block { - print_begin_brace(p, v.pos, block_type); - } - - set_source_position(p, v.pos); - - print_block_stmts(p, v.stmts, true); - - set_source_position(p, v.end); - - if !empty_block { - print_end_brace(p, v.end); - } - } else if v.pos.line == v.end.line { - if !empty_block { - print(p, lbrace); - } - - set_source_position(p, v.pos); - - print_block_stmts(p, v.stmts); - - set_source_position(p, v.end); - - if !empty_block { - print(p, rbrace); - } - } else { - if !empty_block { - print_begin_brace(p, v.pos, block_type); - } - - set_source_position(p, v.pos); - - print_block_stmts(p, v.stmts); - - set_source_position(p, v.end); - - if !empty_block { - print_end_brace(p, v.end); - } - } - case If_Stmt: - newline_until_pos(p, v.pos); - - if v.label != nil { - print_expr(p, v.label); - print(p, ":", space); - } - - print(p, "if", space); - - if v.init != nil { - p.skip_semicolon = true; - print_stmt(p, v.init); - p.skip_semicolon = false; - print(p, semicolon, space); - } - - print_expr(p, v.cond); - - uses_do := false; - - if check_stmt, ok := v.body.derived.(Block_Stmt); ok && check_stmt.uses_do { - uses_do = true; - } - - if uses_do && !p.config.convert_do { - print(p, space, "do", space); - print_stmt(p, v.body, .If_Stmt, true); - } else { - if uses_do { - print(p, newline); - } - - print_stmt(p, v.body, .If_Stmt); - } - - if v.else_stmt != nil { - - if p.config.brace_style == .Allman || p.config.brace_style == .Stroustrup { - print(p, newline); - } else { - print(p, space); - } - - print(p, "else"); - - if if_stmt, ok := v.else_stmt.derived.(ast.If_Stmt); ok { - print(p, space); - } - - set_source_position(p, v.else_stmt.pos); - - print_stmt(p, v.else_stmt); - } - case Switch_Stmt: - newline_until_pos(p, v.pos); - - if v.label != nil { - print_expr(p, v.label); - print(p, ":", space); - } - - if v.partial { - print(p, "#partial", space); - } - - print(p, "switch"); - - if v.init != nil || v.cond != nil { - print(p, space); - } - - if v.init != nil { - p.skip_semicolon = true; - print_stmt(p, v.init); - p.skip_semicolon = false; - } - - if v.init != nil && v.cond != nil { - print(p, semicolon, space); - } - - print_expr(p, v.cond); - print_stmt(p, v.body); - case Case_Clause: - newline_until_pos(p, v.pos); - - if !p.config.indent_cases { - print(p, unindent); - } - - print(p, "case", indent); - - if v.list != nil { - print(p, space); - print_exprs(p, v.list, ","); - } - - print(p, v.terminator); - - print_block_stmts(p, v.body); - - print(p, unindent); - - if !p.config.indent_cases { - print(p, indent); - } - case Type_Switch_Stmt: - newline_until_pos(p, v.pos); - - if v.label != nil { - print_expr(p, v.label); - print(p, ":", space); - } - - if v.partial { - print(p, "#partial", space); - } - - print(p, "switch", space); - - print_stmt(p, v.tag); - print_stmt(p, v.body); - case Assign_Stmt: - newline_until_pos(p, v.pos); - - /* - if len(v.lhs) == 1 { - - if ident, ok := v.lhs[0].derived.(Ident); ok && ident.name == "_" { - print(p, v.op, space); - print_exprs(p, v.rhs, ", "); - return; - } - - } - */ - - print_exprs(p, v.lhs, ", "); - - if p.config.align_assignments && p.align_info.assign_aligned_begin_line <= v.pos.line && v.pos.line <= p.align_info.assign_aligned_end_line { - print_space_padding(p, p.align_info.assign_aligned_padding - get_length_of_names(v.lhs)); - } - - print(p, space, v.op, space); - - print_exprs(p, v.rhs, ", "); - - if block_stmt && p.config.semicolons { - print(p, semicolon); - } - case Expr_Stmt: - newline_until_pos(p, v.pos); - print_expr(p, v.expr); - if block_stmt && p.config.semicolons { - print(p, semicolon); - } - case For_Stmt: - //this should be simplified - newline_until_pos(p, v.pos); - - if v.label != nil { - print_expr(p, v.label); - print(p, ":", space); - } - - print(p, "for"); - - if v.init != nil || v.cond != nil || v.post != nil { - print(p, space); - } - - if v.init != nil { - p.skip_semicolon = true; - print_stmt(p, v.init); - p.skip_semicolon = false; - print(p, semicolon, space); - } else if v.post != nil { - print(p, semicolon, space); - } - - if v.cond != nil { - print_expr(p, v.cond); - } - - if v.post != nil { - print(p, semicolon); - print(p, space); - print_stmt(p, v.post); - } else if v.post == nil && v.cond != nil && v.init != nil { - print(p, semicolon); - } - - print_stmt(p, v.body); - case Inline_Range_Stmt: - - newline_until_pos(p, v.pos); - - if v.label != nil { - print_expr(p, v.label); - print(p, ":", space); - } - - print(p, "#unroll", space); - - print(p, "for", space); - print_expr(p, v.val0); - - if v.val1 != nil { - print(p, ",", space); - print_expr(p, v.val1); - print(p, space); - } - - print(p, "in", space); - print_expr(p, v.expr); - - print_stmt(p, v.body); - case Range_Stmt: - - newline_until_pos(p, v.pos); - - if v.label != nil { - print_expr(p, v.label); - print(p, ":", space); - } - - print(p, "for", space); - - if len(v.vals) >= 1 { - print_expr(p, v.vals[0]); - } - - if len(v.vals) >= 2 { - print(p, ",", space); - print_expr(p, v.vals[1]); - print(p, space); - } else { - print(p, space); - } - - print(p, "in", space); - print_expr(p, v.expr); - - print_stmt(p, v.body); - case Return_Stmt: - newline_until_pos(p, v.pos); - print(p, "return"); - - if v.results != nil { - print(p, space); - print_exprs(p, v.results, ", "); - } - - if block_stmt && p.config.semicolons { - print(p, semicolon); - } - case Defer_Stmt: - newline_until_pos(p, v.pos); - print(p, "defer"); - - if block, ok := v.stmt.derived.(ast.Block_Stmt); !ok { - print(p, space); - } - - print_stmt(p, v.stmt); - - if p.config.semicolons { - print(p, semicolon); - } - case When_Stmt: - newline_until_pos(p, v.pos); - print(p, "when", space); - print_expr(p, v.cond); - - print_stmt(p, v.body); - - if v.else_stmt != nil { - - if p.config.brace_style == .Allman { - print(p, newline); - } else { - print(p, space); - } - - print(p, "else"); - - if when_stmt, ok := v.else_stmt.derived.(ast.When_Stmt); ok { - print(p, space); - } - - set_source_position(p, v.else_stmt.pos); - - print_stmt(p, v.else_stmt); - } - - case Branch_Stmt: - - newline_until_pos(p, v.pos); - - print(p, v.tok); - - if v.label != nil { - print(p, space); - print_expr(p, v.label); - } - - if p.config.semicolons { - print(p, semicolon); - } - case: - panic(fmt.aprint(stmt.derived)); - } - - set_source_position(p, stmt.end); -} - -print_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) { - - using ast; - - if decl == nil { - return; - } - - switch v in decl.derived { - case Expr_Stmt: - newline_until_pos(p, decl.pos); - print_expr(p, v.expr); - if p.config.semicolons { - print(p, semicolon); - } - case When_Stmt: - print_stmt(p, cast(^Stmt)decl); - case Foreign_Import_Decl: - if len(v.attributes) > 0 { - newline_until_pos(p, v.attributes[0].pos); - } else { - newline_until_pos(p, decl.pos); - } - - print_attributes(p, v.attributes); - - if v.name != nil { - print(p, v.foreign_tok, space, v.import_tok, space, v.name^, space); - } else { - print(p, v.foreign_tok, space, v.import_tok, space); - } - - for path in v.fullpaths { - print(p, path); - } - case Foreign_Block_Decl: - - if len(v.attributes) > 0 { - newline_until_pos(p, v.attributes[0].pos); - } else { - newline_until_pos(p, decl.pos); - } - - print_attributes(p, v.attributes); - - print(p, newline, "foreign", space); - print_expr(p, v.foreign_library); - print_stmt(p, v.body); - case Import_Decl: - newline_until_pos(p, decl.pos); - - if v.name.text != "" { - print(p, v.import_tok, " ", v.name, " ", v.fullpath); - } else { - print(p, v.import_tok, " ", v.fullpath); - } - - case Value_Decl: - if len(v.attributes) > 0 { - newline_until_pos(p, v.attributes[0].pos); - print_attributes(p, v.attributes); - } - - newline_until_pos(p, decl.pos); - - if v.is_using { - print(p, "using", space); - } - - print_exprs(p, v.names, ", "); - - seperator := ":"; - - if !v.is_mutable && v.type == nil { - seperator = ":: "; - } else if !v.is_mutable && v.type != nil { - seperator = " :"; - } - - if in_value_decl_alignment(p, v) && p.config.align_style == .Align_On_Colon_And_Equals { - print_space_padding(p, p.align_info.value_decl_aligned_padding - get_length_of_names(v.names)); - } - - if v.type != nil { - print(p, seperator, space); - - if in_value_decl_alignment(p, v) && p.config.align_style == .Align_On_Type_And_Equals { - print_space_padding(p, p.align_info.value_decl_aligned_padding - get_length_of_names(v.names)); - } else if in_value_decl_alignment(p, v) && p.config.align_style == .Align_On_Colon_And_Equals { - print_space_padding(p, p.align_info.value_decl_aligned_type_padding - (v.type.end.column - v.type.pos.column)); - } - - print_expr(p, v.type); - - if in_value_decl_alignment(p, v) && p.config.align_style == .Align_On_Type_And_Equals && len(v.values) != 0 { - print_space_padding(p, p.align_info.value_decl_aligned_type_padding - (v.type.end.column - v.type.pos.column)); - } - } else { - if in_value_decl_alignment(p, v) && p.config.align_style == .Align_On_Type_And_Equals { - print_space_padding(p, p.align_info.value_decl_aligned_padding - get_length_of_names(v.names)); - } - print(p, space, seperator); - } - - if v.is_mutable && v.type != nil && len(v.values) != 0 { - print(p, space, "=", space); - } else if v.is_mutable && v.type == nil && len(v.values) != 0 { - print(p, "=", space); - } else if !v.is_mutable && v.type != nil { - print(p, space, ":", space); - } - - print_exprs(p, v.values, ", "); - - add_semicolon := true; - - for value in v.values { - switch a in value.derived { - case Proc_Lit,Union_Type,Enum_Type,Struct_Type: - add_semicolon = false || called_in_stmt; - } - } - - if add_semicolon && p.config.semicolons && !p.skip_semicolon { - print(p, semicolon); - } - - case: - panic(fmt.aprint(decl.derived)); - } -} print_attributes :: proc(p: ^Printer, attributes: [dynamic]^ast.Attribute) { @@ -1265,7 +1358,7 @@ print_attributes :: proc(p: ^Printer, attributes: [dynamic]^ast.Attribute) { for attribute, i in attributes { print(p, "@", lparen); - print_exprs(p, attribute.elems, ", "); + visit_exprs(p, attribute.elems, ", "); print(p, rparen); if len(attributes) - 1 != i { @@ -1279,7 +1372,7 @@ print_file :: proc(p: ^Printer, file: ^ast.File) { p.comments = file.comments; p.file = file; - newline_until_pos(p, file.pkg_token.pos); + move_line(p, file.pkg_token.pos); print(p, file.pkg_token, space, file.pkg_name); @@ -1297,49 +1390,6 @@ print_file :: proc(p: ^Printer, file: ^ast.File) { write_whitespaces(p, p.current_whitespace); } -print_begin_brace :: proc(p: ^Printer, begin: tokenizer.Pos, type: Block_Type) { - - set_source_position(p, begin); - - newline_braced := p.config.brace_style == .Allman; - newline_braced |= p.config.brace_style == .K_And_R && type == .Proc; - newline_braced &= p.config.brace_style != ._1TBS; - - if newline_braced { - print(p, newline); - print(p, lbrace); - print(p, indent); - } else { - - if type != .Comp_Lit && p.last_out_position.line == (p.out_position.line + get_current_newlines(p)) { - print(p, space); - } - print(p, lbrace); - print(p, indent); - } -} - -print_end_brace :: proc(p: ^Printer, end: tokenizer.Pos) { - set_source_position(p, end); - print(p, newline, unindent, rbrace); -} - -print_block_stmts :: proc(p: ^Printer, stmts: []^ast.Stmt, newline_each := false) { - for stmt, i in stmts { - - if newline_each { - print(p, newline); - } - - if value_decl, ok := stmt.derived.(ast.Value_Decl); ok { - set_value_decl_alignment_padding(p, value_decl, stmts[i + 1:]); - } else if assignment_stmt, ok := stmt.derived.(ast.Assign_Stmt); ok { - set_assign_alignment_padding(p, assignment_stmt, stmts[i + 1:]); - } - - print_stmt(p, stmt, .Generic, false, true); - } -} */ From 1d3458cadbda0d2d01edf5817e11b4664eeb708a Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Mon, 12 Apr 2021 22:35:26 +0200 Subject: [PATCH 03/49] single line comments work --- core/odin/printer/printer.odin | 16 +- core/odin/printer/visit.odin | 423 +++++++++++++++------------------ 2 files changed, 201 insertions(+), 238 deletions(-) diff --git a/core/odin/printer/printer.odin b/core/odin/printer/printer.odin index d783bfb48..691369421 100644 --- a/core/odin/printer/printer.odin +++ b/core/odin/printer/printer.odin @@ -26,14 +26,19 @@ Printer :: struct { config: Config, depth: int, //the identation depth comments: [dynamic]^ast.Comment_Group, + latest_comment_index: int, allocator: mem.Allocator, file: ^ast.File, source_position: tokenizer.Pos, + last_source_position: tokenizer.Pos, lines: map [int]^Line, skip_semicolon: bool, current_line: ^Line, current_line_index: int, + last_line_index: int, last_token: ^Format_Token, + merge_next_token: bool, + debug: bool, } Config :: struct { @@ -86,13 +91,16 @@ make_printer :: proc(config: Config, allocator := context.allocator) -> Printer return { config = config, allocator = allocator, + debug = false, }; } print :: proc(p: ^Printer, file: ^ast.File) -> string { + p.comments = file.comments; + for decl in file.decls { - visit_stmt(p, decl); + visit_decl(p, cast(^ast.Decl)decl); } fix_lines(p); @@ -102,7 +110,7 @@ print :: proc(p: ^Printer, file: ^ast.File) -> string { last_line := 0; for key, value in p.lines { - diff_line := min(key - last_line, p.config.newline_limit); + diff_line := key - last_line; for i := 0; i < diff_line; i += 1 { strings.write_byte(&builder, '\n'); @@ -112,6 +120,10 @@ print :: proc(p: ^Printer, file: ^ast.File) -> string { strings.write_byte(&builder, ' '); } + if p.debug { + strings.write_string(&builder, fmt.tprintf("line %v: ", key)); + } + for format_token in value.format_tokens { for i := 0; i < format_token.spaces_before; i += 1 { diff --git a/core/odin/printer/visit.odin b/core/odin/printer/visit.odin index 12f7da301..dcacef825 100644 --- a/core/odin/printer/visit.odin +++ b/core/odin/printer/visit.odin @@ -8,21 +8,104 @@ import "core:fmt" import "core:unicode/utf8" import "core:mem" - + @(private) -append_format_token :: proc(p: ^Printer, unwrapped_line: ^Line, format_token: Format_Token) -> ^Format_Token { +comment_before_position :: proc(p: ^Printer, pos: tokenizer.Pos) -> bool { + + if len(p.comments) <= p.latest_comment_index { + return false; + } + + comment := p.comments[p.latest_comment_index]; + + return comment.pos.offset < pos.offset; +} + +@(private) +next_comment_group :: proc(p: ^Printer) { + p.latest_comment_index += 1; +} + +@(private) +write_comment :: proc(p: ^Printer, comment: tokenizer.Token) { + + if len(comment.text) == 0 { + return; + } + + if comment.text[0] == '/' && comment.text[1] == '/' { + format_token := Format_Token { + spaces_before = 1, + kind = .Comment, + text = comment.text, + }; + + if len(p.current_line.format_tokens) == 0 { + format_token.spaces_before = 0; + } + + append(&p.current_line.format_tokens, format_token); + p.last_token = &p.current_line.format_tokens[len(p.current_line.format_tokens)-1]; + } +} + +@(private) +write_comments :: proc(p: ^Printer, pos: tokenizer.Pos, format_token: Format_Token) { + + prev_comment: ^tokenizer.Token; + + for comment_before_position(p, pos) { + + comment_group := p.comments[p.latest_comment_index]; + lines := comment_group.pos.line - p.last_source_position.line; + + set_line(p, p.last_line_index + min(p.config.newline_limit, lines)); + + for comment, i in comment_group.list { + + if prev_comment != nil && p.last_source_position.line != comment.pos.line { + newline_position(p, comment.pos.line - prev_comment.pos.line); + } + + write_comment(p, comment); + + prev_comment = &comment_group.list[i]; + } + + next_comment_group(p); + } + + if prev_comment != nil { + newline_position(p, min(p.config.newline_limit, p.source_position.line - prev_comment.pos.line)); + } +} + +@(private) +append_format_token :: proc(p: ^Printer, format_token: Format_Token) -> ^Format_Token { format_token := format_token; - if p.last_token != nil && (p.last_token.kind == .Ellipsis || p.last_token.kind == .Range_Half || + if p.last_token != nil && (p.last_token.kind == .Ellipsis || p.last_token.kind == .Range_Half || p.last_token.kind == .Open_Paren || p.last_token.kind == .Period || - p.last_token.kind == .Open_Brace) { + p.last_token.kind == .Open_Brace || p.last_token.kind == .Open_Bracket) { format_token.spaces_before = 0; + } else if p.merge_next_token { + format_token.spaces_before = 0; + p.merge_next_token = false; } + write_comments(p, p.source_position, format_token); + + unwrapped_line := p.current_line; + 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; } + + p.last_source_position = p.source_position; + p.last_line_index = p.current_line_index; append(&unwrapped_line.format_tokens, format_token); return &unwrapped_line.format_tokens[len(unwrapped_line.format_tokens)-1]; @@ -31,10 +114,6 @@ append_format_token :: proc(p: ^Printer, unwrapped_line: ^Line, format_token: Fo @(private) push_generic_token :: proc(p: ^Printer, kind: tokenizer.Token_Kind, spaces_before: int, value := "") { - unwrapped_line := p.current_line; - unwrapped_line.used = true; - unwrapped_line.depth = p.depth; - format_token := Format_Token { spaces_before = spaces_before, kind = kind, @@ -45,38 +124,31 @@ push_generic_token :: proc(p: ^Printer, kind: tokenizer.Token_Kind, spaces_befor format_token.text = value; } - p.last_token = append_format_token(p, unwrapped_line, format_token); + p.last_token = append_format_token(p, format_token); } @(private) push_string_token :: proc(p: ^Printer, text: string, spaces_before: int) { - unwrapped_line := p.current_line; - unwrapped_line.used = true; - unwrapped_line.depth = p.depth; - + format_token := Format_Token { spaces_before = spaces_before, kind = .String, text = text, }; - p.last_token = append_format_token(p, unwrapped_line, format_token); + p.last_token = append_format_token(p, format_token); } @(private) push_ident_token :: proc(p: ^Printer, text: string, spaces_before: int) { - unwrapped_line := p.current_line; - unwrapped_line.used = true; - unwrapped_line.depth = p.depth; - format_token := Format_Token { spaces_before = spaces_before, kind = .Ident, text = text, }; - p.last_token = append_format_token(p, unwrapped_line, format_token); + p.last_token = append_format_token(p, format_token); } @(private) @@ -112,12 +184,13 @@ set_line :: proc(p: ^Printer, line: int) -> ^Line { } p.current_line = unwrapped_line; + p.current_line_index = line; return unwrapped_line; } @(private) -newline_source_position :: proc(p: ^Printer, count: int) { +newline_position :: proc(p: ^Printer, count: int) { p.current_line_index += count; set_line(p, p.current_line_index); } @@ -132,6 +205,10 @@ unindent :: proc(p: ^Printer) { p.depth -= 1; } +merge_next_token :: proc(p: ^Printer) { + p.merge_next_token = true; +} + @(private) visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) { @@ -231,7 +308,7 @@ visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) { } else if v.is_mutable && v.type == nil && len(v.values) != 0 { push_generic_token(p, .Eq, 0); } else if !v.is_mutable && v.type != nil { - push_generic_token(p, .Semicolon, 0); + push_generic_token(p, .Colon, 0); } visit_exprs(p, v.values, true); @@ -240,7 +317,7 @@ visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) { for value in v.values { switch a in value.derived { - case Proc_Lit,Union_Type,Enum_Type,Struct_Type: + case Proc_Lit, Union_Type, Enum_Type, Struct_Type: add_semicolon = false || called_in_stmt; } } @@ -268,17 +345,32 @@ visit_exprs :: proc(p: ^Printer, list: []^ast.Expr, add_comma := false, trailing visit_expr(p, expr); - if i != len(list) - 1 && add_comma { + if (i != len(list) - 1 || trailing) && add_comma { push_generic_token(p, .Comma, 0); - } else if trailing && add_comma { - //print(p, strings.trim_space(sep)); - } + } } } @(private) visit_attributes :: proc(p: ^Printer, attributes: [dynamic]^ast.Attribute) { + if len(attributes) == 0 { + return; + } + + for attribute, i in attributes { + + push_generic_token(p, .At, 0); + push_generic_token(p, .Open_Paren, 0); + + visit_exprs(p, attribute.elems, true); + + push_generic_token(p, .Close_Paren, 0); + + if len(attributes) - 1 != i { + newline_position(p, 1); + } + } } @(private) @@ -390,7 +482,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener visit_stmt(p, v.body, .If_Stmt, true); } else { if uses_do { - newline_source_position(p, 1); + newline_position(p, 1); } visit_stmt(p, v.body, .If_Stmt); @@ -399,7 +491,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener if v.else_stmt != nil { if p.config.brace_style == .Allman || p.config.brace_style == .Stroustrup { - newline_source_position(p, 1); + newline_position(p, 1); } push_generic_token(p, .Else, 1); @@ -498,14 +590,10 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener if v.label != nil { visit_expr(p, v.label); - push_generic_token(p, .Colon, 1); + push_generic_token(p, .Colon, 0); } - push_generic_token(p, .For, 0); - - //if v.init != nil || v.cond != nil || v.post != nil { - // print(p, space); - //} + push_generic_token(p, .For, 1); if v.init != nil { p.skip_semicolon = true; @@ -522,7 +610,6 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener if v.post != nil { push_generic_token(p, .Semicolon, 0); - //print(p, space); visit_stmt(p, v.post); } else if v.post == nil && v.cond != nil && v.init != nil { push_generic_token(p, .Semicolon, 0); @@ -540,7 +627,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener push_ident_token(p, "#unroll", 0); - push_generic_token(p, .For, 0); + push_generic_token(p, .For, 1); visit_expr(p, v.val0); if v.val1 != nil { @@ -561,7 +648,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener push_generic_token(p, .Colon, 1); } - push_generic_token(p, .For, 0); + push_generic_token(p, .For, 1); if len(v.vals) >= 1 { visit_expr(p, v.vals[0]); @@ -580,7 +667,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener case Return_Stmt: move_line(p, v.pos); - push_generic_token(p, .Return, 0); + push_generic_token(p, .Return, 1); if v.results != nil { visit_exprs(p, v.results, true); @@ -600,7 +687,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener } case When_Stmt: move_line(p, v.pos); - push_generic_token(p, .When, 0); + push_generic_token(p, .When, 1); visit_expr(p, v.cond); visit_stmt(p, v.body); @@ -608,10 +695,10 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener if v.else_stmt != nil { if p.config.brace_style == .Allman { - newline_source_position(p, 1); + newline_position(p, 1); } - push_generic_token(p, .Else, 0); + push_generic_token(p, .Else, 1); set_source_position(p, v.else_stmt.pos); @@ -734,7 +821,7 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr) { push_generic_token(p, .Close_Bracket, 0); visit_expr(p, v.elem); case Bit_Set_Type: - push_generic_token(p, .Bit_Set, 0); + push_generic_token(p, .Bit_Set, 1); push_generic_token(p, .Open_Bracket, 0); visit_expr(p, v.elem); @@ -750,7 +837,7 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr) { if v.poly_params != nil { push_generic_token(p, .Open_Paren, 0); - visit_field_list(p, v.poly_params, ", "); + visit_field_list(p, v.poly_params, true, true); push_generic_token(p, .Close_Paren, 0); } @@ -760,18 +847,17 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr) { if v.variants != nil && (len(v.variants) == 0 || v.pos.line == v.end.line) { push_generic_token(p, .Open_Brace, 1); - set_source_position(p, v.variants[len(v.variants) - 1].pos); visit_exprs(p, v.variants, true); push_generic_token(p, .Close_Brace, 0); } else { visit_begin_brace(p, v.pos, .Generic); - newline_source_position(p, 1); - set_source_position(p, v.variants[len(v.variants) - 1].pos); + newline_position(p, 1); + set_source_position(p, v.variants[0].pos); visit_exprs(p, v.variants, true, true); visit_end_brace(p, v.end); } case Enum_Type: - push_generic_token(p, .Enum, 0); + push_generic_token(p, .Enum, 1); if v.base_type != nil { visit_expr(p, v.base_type); @@ -779,21 +865,19 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr) { if v.fields != nil && (len(v.fields) == 0 || v.pos.line == v.end.line) { push_generic_token(p, .Open_Brace, 1); - set_source_position(p, v.fields[len(v.fields) - 1].pos); visit_exprs(p, v.fields, true); push_generic_token(p, .Close_Brace, 0); } else { visit_begin_brace(p, v.pos, .Generic); - newline_source_position(p, 1); - set_source_position(p, v.fields[len(v.fields) - 1].pos); - //visit_enum_fields(p, v.fields, ","); - visit_exprs(p, v.fields, true); + newline_position(p, 1); + set_source_position(p, v.fields[0].pos); + visit_exprs(p, v.fields, true, true); visit_end_brace(p, v.end); } set_source_position(p, v.end); case Struct_Type: - push_generic_token(p, .Struct, 0); + push_generic_token(p, .Struct, 1); if v.is_packed { push_ident_token(p, "#packed", 1); @@ -810,21 +894,20 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr) { if v.poly_params != nil { push_generic_token(p, .Open_Paren, 0); - visit_field_list(p, v.poly_params, ", "); + visit_field_list(p, v.poly_params, true, true); push_generic_token(p, .Close_Paren, 0); } if v.fields != nil && (len(v.fields.list) == 0 || v.pos.line == v.end.line) { push_generic_token(p, .Open_Brace, 1); set_source_position(p, v.fields.pos); - visit_field_list(p, v.fields, ", "); + visit_field_list(p, v.fields, true); push_generic_token(p, .Close_Brace, 0); } else { visit_begin_brace(p, v.pos, .Generic); - newline_source_position(p, 1); + newline_position(p, 1); set_source_position(p, v.fields.pos); - visit_field_list(p, v.fields, ", "); - //visit_struct_field_list(p, v.fields, ","); + visit_field_list(p, v.fields, true, true); visit_end_brace(p, v.end); } @@ -880,7 +963,7 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr) { push_generic_token(p, .Close_Paren, 0); case Index_Expr: visit_expr(p, v.expr); - push_generic_token(p, .Open_Bracket, 1); + push_generic_token(p, .Open_Bracket, 0); visit_expr(p, v.index); push_generic_token(p, .Close_Bracket, 0); case Proc_Group: @@ -889,8 +972,8 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr) { if len(v.args) != 0 && v.pos.line != v.args[len(v.args) - 1].pos.line { visit_begin_brace(p, v.pos, .Generic); - newline_source_position(p, 1); - set_source_position(p, v.args[len(v.args) - 1].pos); + newline_position(p, 1); + set_source_position(p, v.args[0].pos); visit_exprs(p, v.args, true, true); visit_end_brace(p, v.end); } else { @@ -907,8 +990,8 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr) { if len(v.elems) != 0 && v.pos.line != v.elems[len(v.elems) - 1].pos.line { visit_begin_brace(p, v.pos, .Comp_Lit); - newline_source_position(p, 1); - set_source_position(p, v.elems[len(v.elems) - 1].pos); + newline_position(p, 1); + set_source_position(p, v.elems[0].pos); visit_exprs(p, v.elems, true, true); visit_end_brace(p, v.end); } else { @@ -919,6 +1002,7 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr) { case Unary_Expr: push_generic_token(p, v.op.kind, 0); + merge_next_token(p); visit_expr(p, v.expr); case Field_Value: visit_expr(p, v.field); @@ -939,6 +1023,7 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr) { case Pointer_Type: push_generic_token(p, .Pointer, 0); + merge_next_token(p); visit_expr(p, v.elem); case Implicit: push_generic_token(p, v.tok.kind, 0); @@ -958,7 +1043,7 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr) { push_generic_token(p, .Close_Bracket, 0); visit_expr(p, v.elem); case Map_Type: - push_generic_token(p, .Map, 0); + push_generic_token(p, .Map, 1); push_generic_token(p, .Open_Bracket, 0); visit_expr(p, v.key); push_generic_token(p, .Close_Bracket, 0); @@ -980,7 +1065,7 @@ visit_begin_brace :: proc(p: ^Printer, begin: tokenizer.Pos, type: Block_Type) { newline_braced &= p.config.brace_style != ._1TBS; if newline_braced { - newline_source_position(p, 1); + newline_position(p, 1); push_generic_token(p, .Open_Brace, 0); indent(p); } else { @@ -991,7 +1076,7 @@ visit_begin_brace :: proc(p: ^Printer, begin: tokenizer.Pos, type: Block_Type) { visit_end_brace :: proc(p: ^Printer, end: tokenizer.Pos) { set_source_position(p, end); - newline_source_position(p, 1); + newline_position(p, 1); unindent(p); push_generic_token(p, .Close_Brace, 0); } @@ -1000,14 +1085,14 @@ visit_block_stmts :: proc(p: ^Printer, stmts: []^ast.Stmt, newline_each := false for stmt, i in stmts { if newline_each { - newline_source_position(p, 1); + newline_position(p, 1); } visit_stmt(p, stmt, .Generic, false, true); } } -visit_field_list :: proc(p: ^Printer, list: ^ast.Field_List, sep := "") { +visit_field_list :: proc(p: ^Printer, list: ^ast.Field_List, add_comma := false, trailing := false) { if list.list == nil { return; @@ -1039,8 +1124,8 @@ visit_field_list :: proc(p: ^Printer, list: ^ast.Field_List, sep := "") { push_generic_token(p, field.tag.kind, 1); } - if i != len(list.list) - 1 { - //print(p, sep); + if (i != len(list.list) - 1 || trailing) && add_comma { + push_generic_token(p, .Comma, 0); } } } @@ -1049,20 +1134,22 @@ visit_proc_type :: proc(p: ^Printer, proc_type: ast.Proc_Type) { push_generic_token(p, .Proc, 1); - if proc_type.calling_convention != .Odin { - //print(p, space); - } + explicit_calling := false; switch proc_type.calling_convention { case .Odin: case .Contextless: - push_string_token(p, "\"contextless\"", 0); + push_string_token(p, "\"contextless\"", 1); + explicit_calling = true; case .C_Decl: - push_string_token(p, "\"c\"", 0); + push_string_token(p, "\"c\"", 1); + explicit_calling = true; case .Std_Call: - push_string_token(p, "\"std\"", 0); + push_string_token(p, "\"std\"", 1); + explicit_calling = true; case .Fast_Call: - push_string_token(p, "\"fast\"", 0); + push_string_token(p, "\"fast\"", 1); + explicit_calling = true; case .None: //nothing i guess case .Invalid: @@ -1070,15 +1157,19 @@ visit_proc_type :: proc(p: ^Printer, proc_type: ast.Proc_Type) { case .Foreign_Block_Default: } - push_generic_token(p, .Open_Paren, 0); + if explicit_calling { + push_generic_token(p, .Open_Paren, 1); + } else { + push_generic_token(p, .Open_Paren, 0); + } - //visit_signature_list(p, proc_type.params, ", ", false); + visit_signature_list(p, proc_type.params, false); push_generic_token(p, .Close_Paren, 0); - /* if proc_type.results != nil { - print(p, space, "->", space); + push_generic_token(p, .Sub, 1); + push_generic_token(p, .Gt, 0); use_parens := false; use_named := false; @@ -1097,14 +1188,14 @@ visit_proc_type :: proc(p: ^Printer, proc_type: ast.Proc_Type) { } if use_parens { - print(p, lparen); - print_signature_list(p, proc_type.results, ", "); - print(p, rparen); + push_generic_token(p, .Open_Paren, 1); + visit_signature_list(p, proc_type.results); + push_generic_token(p, .Close_Paren, 0); } else { - print_signature_list(p, proc_type.results, ", "); + visit_signature_list(p, proc_type.results); } } - */ + } visit_binary_expr :: proc(p: ^Printer, binary: ast.Binary_Expr) { @@ -1173,126 +1264,8 @@ visit_call_exprs :: proc(p: ^Printer, list: []^ast.Expr, ellipsis := false) { } } -/* -print_enum_fields :: proc(p: ^Printer, list: []^ast.Expr, sep := " ") { - - //print enum fields is like visit_exprs, but it can contain fields that can be aligned. - - if len(list) == 0 { - return; - } - - if list[0].pos.line == list[len(list) - 1].pos.line { - //if everything is on one line, then it can be treated the same way as visit_exprs - visit_exprs(p, list, sep); - return; - } - - largest := 0; - last_field_value := 0; - - //first find all the field values and find the largest name - for expr, i in list { - - if field_value, ok := expr.derived.(ast.Field_Value); ok { - - if ident, ok := field_value.field.derived.(ast.Ident); ok { - largest = max(largest, strings.rune_count(ident.name)); - } - } - } - - for expr, i in list { - - move_line_limit(p, expr.pos, 1); - - if field_value, ok := expr.derived.(ast.Field_Value); ok && p.config.align_assignments { - - if ident, ok := field_value.field.derived.(ast.Ident); ok { - visit_expr(p, field_value.field); - print_space_padding(p, largest - strings.rune_count(ident.name) + 1); - print(p, "=", space); - visit_expr(p, field_value.value); - } else { - visit_expr(p, expr); - } - } else { - visit_expr(p, expr); - } - - if i != len(list) - 1 { - print(p, sep); - } else { - print(p, strings.trim_space(sep)); - } - } -} - - - - - - - -print_struct_field_list :: proc(p: ^Printer, list: ^ast.Field_List, sep := "") { - - if list.list == nil { - return; - } - - largest := 0; - using_size := len("using "); - - //NOTE(Daniel): Is there any other variables than using in structs? - - for field, i in list.list { - if .Using in field.flags { - largest = max(largest, get_length_of_names(field.names) + using_size); - } else { - largest = max(largest, get_length_of_names(field.names)); - } - } - - for field, i in list.list { - - move_line_limit(p, field.pos, 1); - - if .Using in field.flags { - print(p, "using", space); - } - - visit_exprs(p, field.names, ", "); - - if len(field.names) != 0 { - print(p, ": "); - } - - if field.type == nil { - panic("struct field has to have types"); - } - - if .Using in field.flags { - print_space_padding(p, largest - get_length_of_names(field.names) - using_size); - } else { - print_space_padding(p, largest - get_length_of_names(field.names)); - } - - visit_expr(p, field.type); - - if field.tag.text != "" { - print(p, space, field.tag); - } - - if i != len(list.list) - 1 { - print(p, sep); - } else { - print(p, strings.trim_space(sep)); - } - } -} - -print_signature_list :: proc(p: ^Printer, list: ^ast.Field_List, sep := "", remove_blank := true) { +visit_signature_list :: proc(p: ^Printer, list: ^ast.Field_List, remove_blank := true) { if list.list == nil { return; @@ -1303,7 +1276,7 @@ print_signature_list :: proc(p: ^Printer, list: ^ast.Field_List, sep := "", remo move_line_limit(p, field.pos, 1); if .Using in field.flags { - print(p, "using", space); + push_generic_token(p, .Using, 0); } named := false; @@ -1321,34 +1294,33 @@ print_signature_list :: proc(p: ^Printer, list: ^ast.Field_List, sep := "", remo } if named { - visit_exprs(p, field.names, ", "); + visit_exprs(p, field.names, true); if len(field.names) != 0 && field.type != nil { - print(p, ": "); - } else { - print(p, space); - } + push_generic_token(p, .Colon, 0); + } } if field.type != nil && field.default_value != nil { visit_expr(p, field.type); - print(p, space, "=", space); + push_generic_token(p, .Eq, 0); visit_expr(p, field.default_value); } else if field.type != nil { visit_expr(p, field.type); } else { - print(p, ":= "); + push_generic_token(p, .Colon, 1); + push_generic_token(p, .Eq, 0); visit_expr(p, field.default_value); } if i != len(list.list) - 1 { - print(p, sep); + push_generic_token(p, .Comma, 0); } } } - +/* print_attributes :: proc(p: ^Printer, attributes: [dynamic]^ast.Attribute) { if len(attributes) == 0 { @@ -1367,28 +1339,7 @@ print_attributes :: proc(p: ^Printer, attributes: [dynamic]^ast.Attribute) { } } -print_file :: proc(p: ^Printer, file: ^ast.File) { - p.comments = file.comments; - p.file = file; - - move_line(p, file.pkg_token.pos); - - print(p, file.pkg_token, space, file.pkg_name); - - for decl, i in file.decls { - - if value_decl, ok := decl.derived.(ast.Value_Decl); ok { - set_value_decl_alignment_padding(p, value_decl, file.decls[i + 1:]); - } - - print_decl(p, cast(^ast.Decl)decl); - } - - //todo(probably check if there already is a newline, but there really shouldn't be) - print(p, newline); //finish document with newline - write_whitespaces(p, p.current_whitespace); -} */ From 2e8da35851af9b60499b47c68a54c387a984be09 Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Tue, 13 Apr 2021 15:27:04 +0200 Subject: [PATCH 04/49] multiline comments work --- core/odin/printer/visit.odin | 153 ++++++++++++++++++++++++----------- 1 file changed, 107 insertions(+), 46 deletions(-) diff --git a/core/odin/printer/visit.odin b/core/odin/printer/visit.odin index dcacef825..71c125e93 100644 --- a/core/odin/printer/visit.odin +++ b/core/odin/printer/visit.odin @@ -27,10 +27,10 @@ next_comment_group :: proc(p: ^Printer) { } @(private) -write_comment :: proc(p: ^Printer, comment: tokenizer.Token) { +write_comment :: proc(p: ^Printer, comment: tokenizer.Token) -> int { if len(comment.text) == 0 { - return; + return 0; } if comment.text[0] == '/' && comment.text[1] == '/' { @@ -44,8 +44,90 @@ write_comment :: proc(p: ^Printer, comment: tokenizer.Token) { format_token.spaces_before = 0; } + p.current_line.used = true; + p.current_line.depth = p.depth; + append(&p.current_line.format_tokens, format_token); p.last_token = &p.current_line.format_tokens[len(p.current_line.format_tokens)-1]; + + return 0; + } else { + + builder := strings.make_builder(context.temp_allocator); + + c_len := len(comment.text); + trim_space := true; + + multilines: [dynamic] string; + + for i := 0; i < len(comment.text); i += 1 { + + c := comment.text[i]; + + if c != ' ' && c != '\t' { + trim_space = false; + } + + if (c == ' ' || c == '\t' || c == '\n') && trim_space { + continue; + } else if c == 13 && comment.text[min(c_len - 1, i + 1)] == 10 { + append(&multilines, strings.to_string(builder)); + builder = strings.make_builder(context.temp_allocator); + trim_space = true; + i += 1; + } else if c == 10 { + append(&multilines, strings.to_string(builder)); + builder = strings.make_builder(context.temp_allocator); + trim_space = true; + } else if c == '/' && comment.text[min(c_len - 1, i + 1)] == '*' { + strings.write_string(&builder, "/*"); + trim_space = true; + p.depth += 1; + i += 1; + } else if c == '*' && comment.text[min(c_len - 1, i + 1)] == '/' { + p.depth -= 1; + trim_space = true; + strings.write_string(&builder, "*/"); + i += 1; + } else { + strings.write_byte(&builder, c); + } + + } + + if strings.builder_len(builder) > 0 { + append(&multilines, strings.to_string(builder)); + } + + for line in multilines { + format_token := Format_Token { + spaces_before = 1, + kind = .Comment, + text = line, + }; + + if len(p.current_line.format_tokens) == 0 { + format_token.spaces_before = 0; + } + + if strings.contains(line, "*/") { + unindent(p); + } + + p.current_line.used = true; + p.current_line.depth = p.depth; + + append(&p.current_line.format_tokens, format_token); + p.last_token = &p.current_line.format_tokens[len(p.current_line.format_tokens)-1]; + + if strings.contains(line, "/*") { + indent(p); + } + + newline_position(p, 1); + } + + return len(multilines); } } @@ -53,22 +135,24 @@ write_comment :: proc(p: ^Printer, comment: tokenizer.Token) { write_comments :: proc(p: ^Printer, pos: tokenizer.Pos, format_token: Format_Token) { prev_comment: ^tokenizer.Token; + prev_comment_lines: int; for comment_before_position(p, pos) { comment_group := p.comments[p.latest_comment_index]; - lines := comment_group.pos.line - p.last_source_position.line; - set_line(p, p.last_line_index + min(p.config.newline_limit, lines)); + if prev_comment == nil { + lines := comment_group.pos.line - p.last_source_position.line; + set_line(p, p.last_line_index + min(p.config.newline_limit, lines)); + } for comment, i in comment_group.list { - + if prev_comment != nil && p.last_source_position.line != comment.pos.line { - newline_position(p, comment.pos.line - prev_comment.pos.line); + newline_position(p, min(p.config.newline_limit, comment.pos.line - prev_comment.pos.line - prev_comment_lines)); } - write_comment(p, comment); - + prev_comment_lines = write_comment(p, comment); prev_comment = &comment_group.list[i]; } @@ -792,7 +876,7 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr) { visit_expr(p, v.type); case Slice_Expr: visit_expr(p, v.expr); - push_generic_token(p, .Open_Bracket, 1); + push_generic_token(p, .Open_Bracket, 0); visit_expr(p, v.low); push_generic_token(p, v.interval.kind, 0); visit_expr(p, v.high); @@ -803,7 +887,7 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr) { visit_expr(p, v.expr); push_generic_token(p, v.op.kind, 0); case Type_Cast: - push_generic_token(p, v.tok.kind, 0); + push_generic_token(p, v.tok.kind, 1); push_generic_token(p, .Open_Paren, 1); visit_expr(p, v.type); push_generic_token(p, .Close_Paren, 0); @@ -812,7 +896,7 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr) { push_generic_token(p, v.tok.kind, 0); push_ident_token(p, v.name, 0); case Distinct_Type: - push_generic_token(p, .Distinct, 0); + push_generic_token(p, .Distinct, 1); visit_expr(p, v.type); case Dynamic_Array_Type: visit_expr(p, v.tag); @@ -833,11 +917,11 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr) { push_generic_token(p, .Close_Bracket, 0); case Union_Type: - push_generic_token(p, .Union, 0); + push_generic_token(p, .Union, 1); if v.poly_params != nil { push_generic_token(p, .Open_Paren, 0); - visit_field_list(p, v.poly_params, true, true); + visit_field_list(p, v.poly_params, true, false); push_generic_token(p, .Close_Paren, 0); } @@ -894,7 +978,7 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr) { if v.poly_params != nil { push_generic_token(p, .Open_Paren, 0); - visit_field_list(p, v.poly_params, true, true); + visit_field_list(p, v.poly_params, true, false); push_generic_token(p, .Close_Paren, 0); } @@ -947,7 +1031,7 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr) { visit_call_exprs(p, v.args, v.ellipsis.kind == .Ellipsis); push_generic_token(p, .Close_Paren, 0); case Typeid_Type: - push_generic_token(p, .Typeid, 0); + push_generic_token(p, .Typeid, 1); if v.specialization != nil { push_generic_token(p, .Quo, 0); @@ -1001,7 +1085,7 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr) { } case Unary_Expr: - push_generic_token(p, v.op.kind, 0); + push_generic_token(p, v.op.kind, 1); merge_next_token(p); visit_expr(p, v.expr); case Field_Value: @@ -1022,18 +1106,19 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr) { } case Pointer_Type: - push_generic_token(p, .Pointer, 0); + push_generic_token(p, .Pointer, 1); merge_next_token(p); visit_expr(p, v.elem); case Implicit: - push_generic_token(p, v.tok.kind, 0); + push_generic_token(p, v.tok.kind, 1); case Poly_Type: - push_generic_token(p, .Dollar, 0); - + push_generic_token(p, .Dollar, 1); + merge_next_token(p); visit_expr(p, v.type); if v.specialization != nil { push_generic_token(p, .Quo, 0); + merge_next_token(p); visit_expr(p, v.specialization); } case Array_Type: @@ -1077,8 +1162,9 @@ visit_begin_brace :: proc(p: ^Printer, begin: tokenizer.Pos, type: Block_Type) { visit_end_brace :: proc(p: ^Printer, end: tokenizer.Pos) { set_source_position(p, end); newline_position(p, 1); - unindent(p); push_generic_token(p, .Close_Brace, 0); + unindent(p); + p.current_line.depth = p.depth; } visit_block_stmts :: proc(p: ^Printer, stmts: []^ast.Stmt, newline_each := false) { @@ -1319,28 +1405,3 @@ visit_signature_list :: proc(p: ^Printer, list: ^ast.Field_List, remove_blank := } } - -/* -print_attributes :: proc(p: ^Printer, attributes: [dynamic]^ast.Attribute) { - - if len(attributes) == 0 { - return; - } - - for attribute, i in attributes { - - print(p, "@", lparen); - visit_exprs(p, attribute.elems, ", "); - print(p, rparen); - - if len(attributes) - 1 != i { - print(p, newline); - } - } -} - - - -*/ - - From d046c9c07202f0e493d79eb7132cf5f077a833cc Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Tue, 13 Apr 2021 20:18:50 +0200 Subject: [PATCH 05/49] at the same point as the previous formatter now --- core/odin/printer/printer.odin | 1 + core/odin/printer/visit.odin | 51 +++++++++++++++++++++++----------- 2 files changed, 36 insertions(+), 16 deletions(-) diff --git a/core/odin/printer/printer.odin b/core/odin/printer/printer.odin index 691369421..7786de2b4 100644 --- a/core/odin/printer/printer.odin +++ b/core/odin/printer/printer.odin @@ -38,6 +38,7 @@ Printer :: struct { last_line_index: int, last_token: ^Format_Token, merge_next_token: bool, + space_next_token: bool, debug: bool, } diff --git a/core/odin/printer/visit.odin b/core/odin/printer/visit.odin index 71c125e93..ebd2a98ce 100644 --- a/core/odin/printer/visit.odin +++ b/core/odin/printer/visit.odin @@ -158,7 +158,7 @@ write_comments :: proc(p: ^Printer, pos: tokenizer.Pos, format_token: Format_Tok next_comment_group(p); } - + if prev_comment != nil { newline_position(p, min(p.config.newline_limit, p.source_position.line - prev_comment.pos.line)); } @@ -176,6 +176,9 @@ append_format_token :: proc(p: ^Printer, format_token: Format_Token) -> ^Format_ } else if p.merge_next_token { format_token.spaces_before = 0; p.merge_next_token = false; + } else if p.space_next_token { + format_token.spaces_before = 1; + p.space_next_token = false; } write_comments(p, p.source_position, format_token); @@ -289,10 +292,15 @@ unindent :: proc(p: ^Printer) { p.depth -= 1; } +@(private) merge_next_token :: proc(p: ^Printer) { p.merge_next_token = true; } +space_next_token :: proc(p: ^Printer) { + p.space_next_token = true; +} + @(private) visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) { @@ -374,7 +382,7 @@ visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) { if !v.is_mutable && v.type != nil { push_generic_token(p, .Colon, 1); } else { - push_generic_token(p, .Colon, 1); + push_generic_token(p, .Colon, 0); } visit_expr(p, v.type); @@ -388,7 +396,7 @@ visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) { } if v.is_mutable && v.type != nil && len(v.values) != 0 { - push_generic_token(p, .Eq, 0); + push_generic_token(p, .Eq, 1); } else if v.is_mutable && v.type == nil && len(v.values) != 0 { push_generic_token(p, .Eq, 0); } else if !v.is_mutable && v.type != nil { @@ -823,23 +831,22 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr) { switch v in expr.derived { case Inline_Asm_Expr: - /* - print(p, v.tok, space, lparen); - visit_exprs(p, v.param_types, ", "); - print(p, rparen, space); + push_generic_token(p, v.tok.kind, 1, v.tok.text); - print(p, "->", space); + push_generic_token(p, .Open_Paren, 1); + visit_exprs(p, v.param_types, true, false); + push_generic_token(p, .Close_Paren, 0); + + push_generic_token(p, .Sub, 1); + push_generic_token(p, .Gt, 0); visit_expr(p, v.return_type); - print(p, space); - - print(p, lbrace); + push_generic_token(p, .Open_Brace, 1); visit_expr(p, v.asm_string); - print(p, ", "); + push_generic_token(p, .Comma, 0); visit_expr(p, v.constraints_string); - print(p, rbrace); - */ + push_generic_token(p, .Close_Brace, 0); case Undef: push_generic_token(p, .Undef, 1); case Auto_Cast: @@ -893,7 +900,7 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr) { push_generic_token(p, .Close_Paren, 0); visit_expr(p, v.expr); case Basic_Directive: - push_generic_token(p, v.tok.kind, 0); + push_generic_token(p, v.tok.kind, 1); push_ident_token(p, v.name, 0); case Distinct_Type: push_generic_token(p, .Distinct, 1); @@ -924,11 +931,17 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr) { visit_field_list(p, v.poly_params, true, false); push_generic_token(p, .Close_Paren, 0); } - + if v.is_maybe { push_ident_token(p, "#maybe", 1); } + if v.where_clauses != nil { + move_line(p, v.where_clauses[0].pos); + push_generic_token(p, .Where, 1); + visit_exprs(p, v.where_clauses, true); + } + if v.variants != nil && (len(v.variants) == 0 || v.pos.line == v.end.line) { push_generic_token(p, .Open_Brace, 1); visit_exprs(p, v.variants, true); @@ -982,6 +995,12 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr) { push_generic_token(p, .Close_Paren, 0); } + if v.where_clauses != nil { + move_line(p, v.where_clauses[0].pos); + push_generic_token(p, .Where, 1); + visit_exprs(p, v.where_clauses, true); + } + if v.fields != nil && (len(v.fields.list) == 0 || v.pos.line == v.end.line) { push_generic_token(p, .Open_Brace, 1); set_source_position(p, v.fields.pos); From b09e53d7fe2256e976c38d089312606ea3b5a76f Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Tue, 13 Apr 2021 23:42:58 +0200 Subject: [PATCH 06/49] now aligning comments --- core/odin/printer/printer.odin | 118 +++++++++++++++++++++++++++++---- core/odin/printer/visit.odin | 29 +++++--- 2 files changed, 125 insertions(+), 22 deletions(-) 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) { From 2001384ae64039dbab3d9704cdd94843ac8919d3 Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Tue, 13 Apr 2021 23:52:23 +0200 Subject: [PATCH 07/49] make sure to print comments at the end of the file --- core/odin/printer/printer.odin | 15 +++++++++++++++ core/odin/printer/visit.odin | 4 ++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/core/odin/printer/printer.odin b/core/odin/printer/printer.odin index 67b494f2c..fd62f96f0 100644 --- a/core/odin/printer/printer.odin +++ b/core/odin/printer/printer.odin @@ -118,6 +118,12 @@ print :: proc(p: ^Printer, file: ^ast.File) -> string { visit_decl(p, cast(^ast.Decl)decl); } + if len(p.comments) > 0 { + infinite := p.comments[len(p.comments)-1].end; + infinite.offset = 9999999; + push_comments(p, infinite); + } + fix_lines(p); builder := strings.make_builder(p.allocator); @@ -163,12 +169,17 @@ print :: proc(p: ^Printer, file: ^ast.File) -> string { fix_lines :: proc(p: ^Printer) { align_comments(p); align_var_decls(p); + align_blocks(p); } align_var_decls :: proc(p: ^Printer) { } +align_blocks :: proc(p: ^Printer) { + +} + align_comments :: proc(p: ^Printer) { Comment_Align_Info :: struct { @@ -222,6 +233,10 @@ align_comments :: proc(p: ^Printer) { for info in comment_infos { + if info.begin == info.end { + continue; + } + for i := info.begin; i <= info.end; i += 1 { l := p.lines[i]; diff --git a/core/odin/printer/visit.odin b/core/odin/printer/visit.odin index f9a2b59d6..419cc09c5 100644 --- a/core/odin/printer/visit.odin +++ b/core/odin/printer/visit.odin @@ -134,7 +134,7 @@ push_comment :: proc(p: ^Printer, comment: tokenizer.Token) -> int { } @(private) -push_comments :: proc(p: ^Printer, pos: tokenizer.Pos, format_token: Format_Token) { +push_comments :: proc(p: ^Printer, pos: tokenizer.Pos) { prev_comment: ^tokenizer.Token; prev_comment_lines: int; @@ -183,7 +183,7 @@ append_format_token :: proc(p: ^Printer, format_token: Format_Token) -> ^Format_ p.space_next_token = false; } - push_comments(p, p.source_position, format_token); + push_comments(p, p.source_position); unwrapped_line := p.current_line; unwrapped_line.used = true; From 3157467e4becbdf0225df4f5d0004e2ddf98ea75 Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Tue, 13 Apr 2021 23:59:40 +0200 Subject: [PATCH 08/49] bring over the odinfmt code --- core/odin/format/format.odin | 35 ++++++ tools/odinfmt/flag/flag.odin | 232 +++++++++++++++++++++++++++++++++++ tools/odinfmt/main.odin | 140 +++++++++++++++++++++ 3 files changed, 407 insertions(+) create mode 100644 core/odin/format/format.odin create mode 100644 tools/odinfmt/flag/flag.odin create mode 100644 tools/odinfmt/main.odin diff --git a/core/odin/format/format.odin b/core/odin/format/format.odin new file mode 100644 index 000000000..d86808669 --- /dev/null +++ b/core/odin/format/format.odin @@ -0,0 +1,35 @@ +package odin_format + +import "core:odin/printer" +import "core:odin/parser" +import "core:odin/ast" + +default_style := printer.default_style; + +simplify :: proc(file: ^ast.File) { + +} + +format :: proc(source: [] u8, config: printer.Config, allocator := context.allocator) -> ([] u8, bool) { + + pkg := ast.Package { + kind = .Normal, + }; + + file := ast.File { + pkg = &pkg, + src = source, + }; + + p := parser.default_parser(); + + ok := parser.parse_file(&p, &file); + + if !ok || file.syntax_error_count > 0 { + return {}, false; + } + + prnt := printer.make_printer(config, allocator); + + return transmute([]u8) printer.print(&prnt, &file), true; +} \ No newline at end of file diff --git a/tools/odinfmt/flag/flag.odin b/tools/odinfmt/flag/flag.odin new file mode 100644 index 000000000..543438678 --- /dev/null +++ b/tools/odinfmt/flag/flag.odin @@ -0,0 +1,232 @@ +package flag + +import "core:runtime" +import "core:strings" +import "core:reflect" +import "core:fmt" +import "core:mem" +import "core:strconv" + +Flag_Error :: enum { + None, + No_Base_Struct, + Arg_Error, + Arg_Unsupported_Field_Type, + Arg_Not_Defined, + Arg_Non_Optional, + Value_Parse_Error, + Tag_Error, +} + +Flag :: struct { + optional: bool, + type: ^runtime.Type_Info, + data: rawptr, + tag_ptr: rawptr, + parsed: bool, +} + +Flag_Context :: struct { + seen_flags: map [string] Flag, +} + +parse_args :: proc(ctx: ^Flag_Context, args: []string) -> Flag_Error { + + using runtime; + + args := args; + + for true { + + if len(args) == 0 { + return .None; + } + + arg := args[0]; + + if len(arg) < 2 || arg[0] != '-' { + return .Arg_Error; + } + + minus_count := 1; + + if arg[1] == '-' { + minus_count += 1; + + if len(arg) == 2 { + return .Arg_Error; + } + } + + name := arg[minus_count:]; + + if len(name) == 0 { + return .Arg_Error; + } + + args = args[1:]; + + assign_index := strings.index(name, "="); + + value := ""; + + if assign_index > 0 { + value = name[assign_index + 1:]; + name = name[0:assign_index]; + } + + flag := &ctx.seen_flags[name]; + + if flag == nil { + return .Arg_Not_Defined; + } + + if reflect.is_boolean(flag.type) { + tmp := true; + mem.copy(flag.data, &tmp, flag.type.size); + flag.parsed = true; + continue; + } + + //must be in the next argument + else if value == "" { + + if len(args) == 0 { + return .Arg_Error; + } + + value = args[0]; + args = args[1:]; + } + + #partial switch in flag.type.variant { + case Type_Info_Integer: + if v, ok := strconv.parse_int(value); ok { + mem.copy(flag.data, &v, flag.type.size); + } + else { + return .Value_Parse_Error; + } + case Type_Info_String: + raw_string := cast(^mem.Raw_String)flag.data; + raw_string.data = strings.ptr_from_string(value); + raw_string.len = len(value); + case Type_Info_Float: + switch flag.type.size { + case 32: + if v, ok := strconv.parse_f32(value); ok { + mem.copy(flag.data, &v, flag.type.size); + } + else { + return .Value_Parse_Error; + } + case 64: + if v, ok := strconv.parse_f64(value); ok { + mem.copy(flag.data, &v, flag.type.size); + } + else { + return .Value_Parse_Error; + } + } + } + + flag.parsed = true; + } + + + + return .None; +} + +reflect_args_structure :: proc(ctx: ^Flag_Context, v: any) -> Flag_Error { + using runtime; + + if !reflect.is_struct(type_info_of(v.id)) { + return .No_Base_Struct; + } + + names := reflect.struct_field_names(v.id); + types := reflect.struct_field_types(v.id); + offsets := reflect.struct_field_offsets(v.id); + tags := reflect.struct_field_tags(v.id); + + for name, i in names { + + flag: Flag; + + type := types[i]; + + if named_type, ok := type.variant.(Type_Info_Named); ok { + + if union_type, ok := named_type.base.variant.(Type_Info_Union); ok && union_type.maybe && len(union_type.variants) == 1 { + flag.optional = true; + flag.tag_ptr = rawptr(uintptr(union_type.tag_offset) + uintptr(v.data) + uintptr(offsets[i])); + type = union_type.variants[0]; + } + + else { + return .Arg_Unsupported_Field_Type; + } + + } + + #partial switch in type.variant { + case Type_Info_Integer, Type_Info_String, Type_Info_Boolean, Type_Info_Float: + flag.type = type; + flag.data = rawptr(uintptr(v.data) + uintptr(offsets[i])); + case: + return .Arg_Unsupported_Field_Type; + } + + flag_name: string; + + if value, ok := reflect.struct_tag_lookup(tags[i], "flag"); ok { + flag_name = cast(string)value; + } + + else { + return .Tag_Error; + } + + ctx.seen_flags[flag_name] = flag; + } + + return .None; +} + +parse :: proc(v: any, args: []string) -> Flag_Error { + + if v == nil { + return .None; + } + + ctx: Flag_Context; + + if res := reflect_args_structure(&ctx, v); res != .None { + return res; + } + + if res := parse_args(&ctx, args); res != .None { + return res; + } + + //validate that the required flags were actually set + for k, v in ctx.seen_flags { + + if v.optional && v.parsed { + tag_value : i32 = 1; + mem.copy(v.tag_ptr, &tag_value, 4); //4 constant is probably not portable, but it works for me currently + } + + else if !v.parsed && !v.optional { + return .Arg_Non_Optional; + } + + } + + return .None; +} + +usage :: proc(v: any) -> string { + return "failed"; +} \ No newline at end of file diff --git a/tools/odinfmt/main.odin b/tools/odinfmt/main.odin new file mode 100644 index 000000000..78624bd94 --- /dev/null +++ b/tools/odinfmt/main.odin @@ -0,0 +1,140 @@ +package odinfmt + +import "core:os" +import "core:odin/format" +import "core:fmt" +import "core:strings" +import "core:path/filepath" + +import "flag" + +Args :: struct { + write: Maybe(bool) `flag:"w" usage:"write the new format to file"`, +} + +print_help :: proc() { + +} + +print_arg_error :: proc(error: flag.Flag_Error) { + fmt.println(error); +} + +format_file :: proc(filepath: string) -> ([] u8, bool) { + + if data, ok := os.read_entire_file(filepath); ok { + return format.format(data, format.default_style); + } + + else { + return {}, false; + } + +} + +files: [dynamic] string; + +walk_files :: proc(info: os.File_Info, in_err: os.Errno) -> (err: os.Errno, skip_dir: bool) { + + if info.is_dir { + return 0, false; + } + + if filepath.ext(info.name) != ".odin" { + return 0, false; + } + + append(&files, strings.clone(info.fullpath)); + + return 0, false; +} + +main :: proc() { + + args: Args; + + if len(os.args) < 2 { + print_help(); + os.exit(1); + } + + if res := flag.parse(args, os.args[1:len(os.args)-1]); res != .None { + print_arg_error(res); + os.exit(1); + } + + path := os.args[len(os.args)-1]; + + if os.is_file(path) { + + if _, ok := args.write.(bool); ok { + + backup_path := strings.concatenate({path, "_bk"}, context.temp_allocator); + + if data, ok := format_file(path); ok { + + os.rename(path, backup_path); + + if os.write_entire_file(path, data) { + os.remove(backup_path); + } + + } + + else { + fmt.eprintf("failed to write %v", path); + } + + } + + else { + + if data, ok := format_file(path); ok { + fmt.println(transmute(string)data); + } + + } + + } + + else if os.is_dir(path) { + + filepath.walk(path, walk_files); + + for file in files { + + fmt.println(file); + + backup_path := strings.concatenate({file, "_bk"}, context.temp_allocator); + + if data, ok := format_file(file); ok { + + if _, ok := args.write.(bool); ok { + os.rename(file, backup_path); + + if os.write_entire_file(file, data) { + os.remove(backup_path); + } + } + + else { + fmt.println(transmute(string)data); + } + + + } + + free_all(context.temp_allocator); + } + + fmt.printf("formatted %v files", len(files)); + + } + + else{ + fmt.eprintf("%v is neither a directory nor a file \n", path); + os.exit(1); + } + + os.exit(0); +} \ No newline at end of file From c99afd04ada0ac1eba0ee279cc0f38918bb12f4e Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Wed, 14 Apr 2021 00:08:09 +0200 Subject: [PATCH 09/49] work --- core/odin/printer/visit.odin | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/core/odin/printer/visit.odin b/core/odin/printer/visit.odin index 419cc09c5..b470b7fe7 100644 --- a/core/odin/printer/visit.odin +++ b/core/odin/printer/visit.odin @@ -612,10 +612,10 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener } if v.partial { - push_ident_token(p, "#partial", 0); + push_ident_token(p, "#partial", 1); } - push_generic_token(p, .Switch, 0); + push_generic_token(p, .Switch, 1); if v.init != nil { p.skip_semicolon = true; @@ -662,10 +662,10 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener } if v.partial { - push_ident_token(p, "partial", 0); + push_ident_token(p, "#partial", 1); } - push_generic_token(p, .Switch, 0); + push_generic_token(p, .Switch, 1); visit_stmt(p, v.tag); visit_stmt(p, v.body); @@ -897,7 +897,10 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr) { push_generic_token(p, .Open_Bracket, 0); visit_expr(p, v.low); push_generic_token(p, v.interval.kind, 0); - visit_expr(p, v.high); + if v.high != nil { + merge_next_token(p); + visit_expr(p, v.high); + } push_generic_token(p, .Close_Bracket, 0); case Ident: push_ident_token(p, v.name, 1); From 1cb3a31f326708627ef6e885e914b37246544068 Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Wed, 14 Apr 2021 00:53:34 +0200 Subject: [PATCH 10/49] have to sort attributes because they are not ordered by position(maybe bug on parser) --- core/odin/printer/visit.odin | 61 +++++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 19 deletions(-) diff --git a/core/odin/printer/visit.odin b/core/odin/printer/visit.odin index b470b7fe7..9794635ef 100644 --- a/core/odin/printer/visit.odin +++ b/core/odin/printer/visit.odin @@ -7,7 +7,26 @@ import "core:runtime" import "core:fmt" import "core:unicode/utf8" import "core:mem" +import "core:sort" +@(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]; + }, + }; +} @(private) comment_before_position :: proc(p: ^Printer, pos: tokenizer.Pos) -> bool { @@ -253,6 +272,11 @@ move_line :: proc(p: ^Printer, pos: tokenizer.Pos) { @(private) move_line_limit :: proc(p: ^Printer, pos: tokenizer.Pos, limit: int) -> bool { lines := min(pos.line - p.source_position.line, limit); + + if lines < 0 { + return false; + } + p.source_position = pos; p.current_line_index += lines; set_line(p, p.current_line_index); @@ -321,7 +345,7 @@ visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) { return; } - switch v in decl.derived { + switch v in &decl.derived { case Expr_Stmt: move_line(p, decl.pos); visit_expr(p, v.expr); @@ -332,13 +356,13 @@ visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) { visit_stmt(p, cast(^Stmt)decl); case Foreign_Import_Decl: if len(v.attributes) > 0 { + sort.sort(sort_attribute(&v.attributes)); move_line(p, v.attributes[0].pos); - } else { - move_line(p, decl.pos); - } - - visit_attributes(p, v.attributes); + visit_attributes(p, v.attributes); + } + move_line(p, decl.pos); + push_generic_token(p, v.foreign_tok.kind, 0); push_generic_token(p, v.import_tok.kind, 1); @@ -352,13 +376,13 @@ visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) { case Foreign_Block_Decl: if len(v.attributes) > 0 { + sort.sort(sort_attribute(&v.attributes)); move_line(p, v.attributes[0].pos); - } else { - move_line(p, decl.pos); - } - - visit_attributes(p, v.attributes); - + visit_attributes(p, v.attributes); + } + + move_line(p, decl.pos); + push_generic_token(p, .Foreign, 0); visit_expr(p, v.foreign_library); @@ -377,6 +401,7 @@ visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) { case Value_Decl: if len(v.attributes) > 0 { + sort.sort(sort_attribute(&v.attributes)); move_line(p, v.attributes[0].pos); visit_attributes(p, v.attributes); } @@ -463,16 +488,14 @@ visit_attributes :: proc(p: ^Printer, attributes: [dynamic]^ast.Attribute) { for attribute, i in attributes { + move_line_limit(p, attribute.pos, 1); + push_generic_token(p, .At, 0); push_generic_token(p, .Open_Paren, 0); visit_exprs(p, attribute.elems, true); - push_generic_token(p, .Close_Paren, 0); - - if len(attributes) - 1 != i { - newline_position(p, 1); - } + push_generic_token(p, .Close_Paren, 0); } } @@ -1047,7 +1070,7 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr) { set_source_position(p, v.body.pos); visit_stmt(p, v.body, .Proc); } else { - push_generic_token(p, .Ellipsis, 1); + push_generic_token(p, .Undef, 1); } case Proc_Type: visit_proc_type(p, v); @@ -1240,7 +1263,7 @@ visit_field_list :: proc(p: ^Printer, list: ^ast.Field_List, add_comma := false, } if field.tag.text != "" { - push_generic_token(p, field.tag.kind, 1); + push_generic_token(p, field.tag.kind, 1, field.tag.text); } if (i != len(list.list) - 1 || trailing) && add_comma { From 411beaa3bf981ae7a8baab348a417c05c55d29cd Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Wed, 14 Apr 2021 01:15:46 +0200 Subject: [PATCH 11/49] work on comments --- core/odin/printer/printer.odin | 2 +- core/odin/printer/visit.odin | 14 +++++++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/core/odin/printer/printer.odin b/core/odin/printer/printer.odin index fd62f96f0..55a67ca70 100644 --- a/core/odin/printer/printer.odin +++ b/core/odin/printer/printer.odin @@ -233,7 +233,7 @@ align_comments :: proc(p: ^Printer) { for info in comment_infos { - if info.begin == info.end { + if info.begin == info.end || info.length == 0 { continue; } diff --git a/core/odin/printer/visit.odin b/core/odin/printer/visit.odin index 9794635ef..8899b8e5f 100644 --- a/core/odin/printer/visit.odin +++ b/core/odin/printer/visit.odin @@ -63,8 +63,10 @@ push_comment :: proc(p: ^Printer, comment: tokenizer.Token) -> int { format_token.spaces_before = 0; } - p.current_line.used = true; - p.current_line.depth = p.depth; + if !p.current_line.used { + p.current_line.used = true; + p.current_line.depth = p.depth; + } append(&p.current_line.format_tokens, format_token); p.last_token = &p.current_line.format_tokens[len(p.current_line.format_tokens)-1]; @@ -135,8 +137,10 @@ push_comment :: proc(p: ^Printer, comment: tokenizer.Token) -> int { unindent(p); } - p.current_line.used = true; - p.current_line.depth = p.depth; + if !p.current_line.used { + p.current_line.used = true; + p.current_line.depth = p.depth; + } append(&p.current_line.format_tokens, format_token); p.last_token = &p.current_line.format_tokens[len(p.current_line.format_tokens)-1]; @@ -416,7 +420,7 @@ visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) { if v.type != nil { if !v.is_mutable && v.type != nil { - push_generic_token(p, .Colon, 1); + push_generic_token(p, .Colon, 0); } else { push_generic_token(p, .Colon, 0); } From cb4b7efd3effdf2d315b95828284223c9aa06769 Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Wed, 14 Apr 2021 01:57:42 +0200 Subject: [PATCH 12/49] only align comments in same indentation blocks --- core/odin/printer/printer.odin | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/odin/printer/printer.odin b/core/odin/printer/printer.odin index 55a67ca70..dc4cb1c1a 100644 --- a/core/odin/printer/printer.odin +++ b/core/odin/printer/printer.odin @@ -186,6 +186,7 @@ align_comments :: proc(p: ^Printer) { length: int, begin: int, end: int, + depth: int, }; comment_infos := make([dynamic]Comment_Align_Info, 0, context.temp_allocator); @@ -200,7 +201,7 @@ align_comments :: proc(p: ^Printer) { if .Line_Comment in line.types { - if current_info.end + 1 != line_index { + if current_info.end + 1 != line_index || current_info.depth != line.depth { if (current_info.begin != 0 && current_info.end != 0) || current_info.length > 0 { append(&comment_infos, current_info); @@ -208,6 +209,7 @@ align_comments :: proc(p: ^Printer) { current_info.begin = line_index; current_info.end = line_index; + current_info.depth = line.depth; current_info.length = 0; } From c46317c00b04cefe83101be6bb4231e3edcd2fff Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Wed, 14 Apr 2021 02:20:05 +0200 Subject: [PATCH 13/49] fix os error --- core/odin/printer/printer.odin | 3 ++- core/os/file_windows.odin | 4 ++-- tools/odinfmt/main.odin | 10 +++++++++- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/core/odin/printer/printer.odin b/core/odin/printer/printer.odin index dc4cb1c1a..bc2a0a913 100644 --- a/core/odin/printer/printer.odin +++ b/core/odin/printer/printer.odin @@ -201,7 +201,8 @@ align_comments :: proc(p: ^Printer) { if .Line_Comment in line.types { - if current_info.end + 1 != line_index || current_info.depth != line.depth { + if current_info.end + 1 != line_index || current_info.depth != line.depth || + (current_info.begin == current_info.end && current_info.length == 0) { if (current_info.begin != 0 && current_info.end != 0) || current_info.length > 0 { append(&comment_infos, current_info); diff --git a/core/os/file_windows.odin b/core/os/file_windows.odin index 4bb4c689f..8b99ee9ee 100644 --- a/core/os/file_windows.odin +++ b/core/os/file_windows.odin @@ -273,7 +273,7 @@ is_file :: proc(path: string) -> bool { attribs := win32.GetFileAttributesW(wpath); if i32(attribs) != win32.INVALID_FILE_ATTRIBUTES { - return attribs & win32.FILE_ATTRIBUTE_DIRECTORY == win32.FILE_ATTRIBUTE_DIRECTORY; + return attribs & win32.FILE_ATTRIBUTE_DIRECTORY == 0; } return false; } @@ -283,7 +283,7 @@ is_dir :: proc(path: string) -> bool { attribs := win32.GetFileAttributesW(wpath); if i32(attribs) != win32.INVALID_FILE_ATTRIBUTES { - return attribs & win32.FILE_ATTRIBUTE_DIRECTORY != win32.FILE_ATTRIBUTE_DIRECTORY; + return attribs & win32.FILE_ATTRIBUTE_DIRECTORY != 0; } return false; } diff --git a/tools/odinfmt/main.odin b/tools/odinfmt/main.odin index 78624bd94..4040fe4c2 100644 --- a/tools/odinfmt/main.odin +++ b/tools/odinfmt/main.odin @@ -5,6 +5,8 @@ import "core:odin/format" import "core:fmt" import "core:strings" import "core:path/filepath" +import "core:time" +import "core:mem" import "flag" @@ -51,6 +53,8 @@ walk_files :: proc(info: os.File_Info, in_err: os.Errno) -> (err: os.Errno, skip main :: proc() { + init_global_temporary_allocator(mem.megabytes(100)); + args: Args; if len(os.args) < 2 { @@ -65,6 +69,8 @@ main :: proc() { path := os.args[len(os.args)-1]; + tick_time := time.tick_now(); + if os.is_file(path) { if _, ok := args.write.(bool); ok { @@ -122,12 +128,14 @@ main :: proc() { } + } else { + fmt.eprintf("failed to format %v", file); } free_all(context.temp_allocator); } - fmt.printf("formatted %v files", len(files)); + fmt.printf("formatted %v files in %vms", len(files), time.duration_milliseconds(time.tick_lap_time(&tick_time))); } From 1f563f2810e55fd2fefff6b29b64be9d2bf7d4e4 Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Wed, 14 Apr 2021 15:34:50 +0200 Subject: [PATCH 14/49] 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); } } From 7e90ece84a24d956d9bd65cbe14614ef5dcc904e Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Wed, 14 Apr 2021 16:03:36 +0200 Subject: [PATCH 15/49] more switch alignment work --- core/odin/printer/printer.odin | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/core/odin/printer/printer.odin b/core/odin/printer/printer.odin index f9610682f..c47227d42 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, Switch_Stmt}; +Line_Type_Enum :: enum{Line_Comment, Value_Decl, Switch_Stmt, Struct}; Line_Type :: bit_set[Line_Type_Enum]; @@ -17,7 +17,7 @@ Line :: struct { finalized: bool, used: bool, depth: int, - types: Line_Type, + types: Line_Type, //for performance, so you don't have to verify what types are in it by going through the tokens - might give problems when adding linebreaking } Format_Token :: struct { @@ -55,8 +55,10 @@ Config :: struct { convert_do: bool, //Convert all do statements to brace blocks semicolons: bool, //Enable semicolons split_multiple_stmts: bool, + align_switch: bool, brace_style: Brace_Style, align_assignments: bool, + align_structs: bool, align_style: Alignment_Style, indent_cases: bool, newline_style: Newline_Style, @@ -99,6 +101,8 @@ default_style := Config { align_assignments = true, align_style = .Align_On_Type_And_Equals, indent_cases = false, + align_switch = true, + align_structs = true, }; make_printer :: proc(config: Config, allocator := context.allocator) -> Printer { @@ -221,6 +225,7 @@ align_switch_smt :: proc(p: ^Printer, index: int) { } largest := 0; + case_count := 0; //find all the switch cases that are one lined for line, line_index in p.lines[brace_line+1:] { @@ -243,14 +248,22 @@ align_switch_smt :: proc(p: ^Printer, index: int) { if format_token.kind == .Case { case_found = true; + case_count += 1; } else if format_token.kind == .Colon { colon_found = true; } length += len(format_token.text) + format_token.spaces_before; } + + if case_count > brace_token.parameter_count { + break; + } + } + case_count = 0; + for line, line_index in p.lines[brace_line+1:] { case_found := false; @@ -271,16 +284,26 @@ align_switch_smt :: proc(p: ^Printer, index: int) { if format_token.kind == .Case { case_found = true; + case_count += 1; } else if format_token.kind == .Colon { colon_found = true; } length += len(format_token.text) + format_token.spaces_before; + + if case_count > brace_token.parameter_count { + break; + } + } } } +align_struct :: proc(p: ^Printer, index: int) { + +} + align_blocks :: proc(p: ^Printer) { for line, line_index in p.lines { @@ -289,8 +312,10 @@ align_blocks :: proc(p: ^Printer) { continue; } - if .Switch_Stmt in line.types { + if .Switch_Stmt in line.types && p.config.align_switch { align_switch_smt(p, line_index); + } else if .Struct in line.types && p.config.align_structs { + align_struct(p, line_index); } } From b0721f1e0c51f3f738459db9dc29534161553d4c Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Wed, 14 Apr 2021 16:31:31 +0200 Subject: [PATCH 16/49] aligning structs now work --- core/odin/printer/printer.odin | 90 ++++++++++++++++++++++++++++++++-- core/odin/printer/visit.odin | 15 +++--- 2 files changed, 96 insertions(+), 9 deletions(-) diff --git a/core/odin/printer/printer.odin b/core/odin/printer/printer.odin index c47227d42..6d591a6ae 100644 --- a/core/odin/printer/printer.odin +++ b/core/odin/printer/printer.odin @@ -208,7 +208,7 @@ align_switch_smt :: proc(p: ^Printer, index: int) { if format_token.kind == .Open_Brace && switch_found { brace_token = format_token; - brace_line = line_index; + brace_line = line_index+index; break found_switch_brace; } else if format_token.kind == .Open_Brace { break; @@ -294,7 +294,7 @@ align_switch_smt :: proc(p: ^Printer, index: int) { if case_count > brace_token.parameter_count { break; } - + } } @@ -302,6 +302,88 @@ align_switch_smt :: proc(p: ^Printer, index: int) { align_struct :: proc(p: ^Printer, index: int) { + struct_found := false; + brace_token: Format_Token; + brace_line: int; + + found_struct_brace: for line, line_index in p.lines[index:] { + + for format_token in line.format_tokens { + + if format_token.kind == .Open_Brace && struct_found { + brace_token = format_token; + brace_line = line_index+index; + break found_struct_brace; + } else if format_token.kind == .Open_Brace { + break; + } else if format_token.kind == .Struct { + struct_found = true; + } + + } + + } + + if !struct_found { + return; + } + + largest := 0; + colon_count := 0; + + + + for line, line_index in p.lines[brace_line+1:] { + + length := 0; + + for format_token in line.format_tokens { + + if format_token.kind == .Comment { + continue; + } + + if format_token.kind == .Colon { + colon_count += 1; + largest = max(length, largest); + break; + } + + length += len(format_token.text) + format_token.spaces_before; + } + + if colon_count > brace_token.parameter_count { + break; + } + } + + colon_count = 0; + + for line, line_index in p.lines[brace_line+1:] { + + length := 0; + + for format_token, i in line.format_tokens { + + if format_token.kind == .Comment { + continue; + } + + if format_token.kind == .Colon { + colon_count += 1; + line.format_tokens[i+1].spaces_before += (largest - length) - 1; + break; + } + + length += len(format_token.text) + format_token.spaces_before; + } + + if colon_count > brace_token.parameter_count { + break; + } + } + + } align_blocks :: proc(p: ^Printer) { @@ -314,7 +396,9 @@ align_blocks :: proc(p: ^Printer) { if .Switch_Stmt in line.types && p.config.align_switch { align_switch_smt(p, line_index); - } else if .Struct in line.types && p.config.align_structs { + } + + if .Struct in line.types && p.config.align_structs { align_struct(p, line_index); } diff --git a/core/odin/printer/visit.odin b/core/odin/printer/visit.odin index 6afc04a61..adbe68fb5 100644 --- a/core/odin/printer/visit.odin +++ b/core/odin/printer/visit.odin @@ -1028,6 +1028,8 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr) { case Struct_Type: push_generic_token(p, .Struct, 1); + hint_current_line(p, {.Struct}); + if v.is_packed { push_ident_token(p, "#packed", 1); } @@ -1058,11 +1060,10 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr) { set_source_position(p, v.fields.pos); visit_field_list(p, v.fields, true); push_generic_token(p, .Close_Brace, 0); - } else { - visit_begin_brace(p, v.pos, .Generic); - newline_position(p, 1); + } else if v.fields != nil { + visit_begin_brace(p, v.pos, .Generic, len(v.fields.list)); set_source_position(p, v.fields.pos); - visit_field_list(p, v.fields, true, true); + visit_field_list(p, v.fields, true, true, true); visit_end_brace(p, v.end); } @@ -1256,7 +1257,7 @@ visit_block_stmts :: proc(p: ^Printer, stmts: []^ast.Stmt, newline_each := false } } -visit_field_list :: proc(p: ^Printer, list: ^ast.Field_List, add_comma := false, trailing := false) { +visit_field_list :: proc(p: ^Printer, list: ^ast.Field_List, add_comma := false, trailing := false, enforce_newline := false) { if list.list == nil { return; @@ -1264,7 +1265,9 @@ visit_field_list :: proc(p: ^Printer, list: ^ast.Field_List, add_comma := false, for field, i in list.list { - move_line_limit(p, field.pos, 1); + if !move_line_limit(p, field.pos, 1) && enforce_newline { + newline_position(p, 1); + } if .Using in field.flags { push_generic_token(p, .Using, 0); From aded272b330cc6f751a6101bed0004845548e658 Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Wed, 14 Apr 2021 18:04:48 +0200 Subject: [PATCH 17/49] split stmts --- core/odin/printer/visit.odin | 28 ++++++---------------------- 1 file changed, 6 insertions(+), 22 deletions(-) diff --git a/core/odin/printer/visit.odin b/core/odin/printer/visit.odin index adbe68fb5..5e54368bb 100644 --- a/core/odin/printer/visit.odin +++ b/core/odin/printer/visit.odin @@ -547,29 +547,14 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener case Block_Stmt: move_line(p, v.pos); - 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, len(v.stmts)); - } - - set_source_position(p, v.pos); - - visit_block_stmts(p, v.stmts, true); - - set_source_position(p, v.end); - - if !empty_block { - visit_end_brace(p, v.end); - } - } else if v.pos.line == v.end.line { + if v.pos.line == v.end.line { if !empty_block { push_generic_token(p, .Open_Brace, 0); } set_source_position(p, v.pos); - visit_block_stmts(p, v.stmts); + visit_block_stmts(p, v.stmts, len(v.stmts) > 1 && p.config.split_multiple_stmts); set_source_position(p, v.end); @@ -583,7 +568,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener set_source_position(p, v.pos); - visit_block_stmts(p, v.stmts); + visit_block_stmts(p, v.stmts, len(v.stmts) > 1 && p.config.split_multiple_stmts); set_source_position(p, v.end); @@ -1246,14 +1231,13 @@ visit_end_brace :: proc(p: ^Printer, end: tokenizer.Pos) { p.current_line.depth = p.depth; } -visit_block_stmts :: proc(p: ^Printer, stmts: []^ast.Stmt, newline_each := false) { +visit_block_stmts :: proc(p: ^Printer, stmts: []^ast.Stmt, split := false) { for stmt, i in stmts { + visit_stmt(p, stmt, .Generic, false, true); - if newline_each { + if split && i != len(stmts)-1 && stmt.pos.line == stmts[i+1].pos.line { newline_position(p, 1); } - - visit_stmt(p, stmt, .Generic, false, true); } } From 1de928df7844e2244774cab2b42c70bddfa8698f Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Wed, 14 Apr 2021 18:43:04 +0200 Subject: [PATCH 18/49] fixed bug in parser on when --- core/odin/parser/parser.odin | 2 ++ core/odin/printer/printer.odin | 19 +++++++++---------- core/odin/printer/visit.odin | 9 ++++----- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index 2b657f76f..35fd91465 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -2226,6 +2226,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { p.expr_level = -1; where_clauses = parse_rhs_expr_list(p); p.expr_level = prev_level; + tags = parse_proc_tags(p); } if p.allow_type && p.expr_level < 0 { if where_token.kind != .Invalid { @@ -3152,6 +3153,7 @@ parse_simple_stmt :: proc(p: ^Parser, flags: Stmt_Allow_Flags) -> ^ast.Stmt { case ast.For_Stmt: n.label = label; case ast.Switch_Stmt: n.label = label; case ast.Type_Switch_Stmt: n.label = label; + case ast.Range_Stmt: n.label = label; } } diff --git a/core/odin/printer/printer.odin b/core/odin/printer/printer.odin index 6d591a6ae..21765f6f0 100644 --- a/core/odin/printer/printer.odin +++ b/core/odin/printer/printer.odin @@ -256,12 +256,14 @@ align_switch_smt :: proc(p: ^Printer, index: int) { length += len(format_token.text) + format_token.spaces_before; } - if case_count > brace_token.parameter_count { + if case_count >= brace_token.parameter_count { break; } } + fmt.println(case_count, brace_token); + case_count = 0; for line, line_index in p.lines[brace_line+1:] { @@ -291,10 +293,10 @@ align_switch_smt :: proc(p: ^Printer, index: int) { length += len(format_token.text) + format_token.spaces_before; - if case_count > brace_token.parameter_count { - break; - } + } + if case_count >= brace_token.parameter_count { + break; } } @@ -331,8 +333,6 @@ align_struct :: proc(p: ^Printer, index: int) { largest := 0; colon_count := 0; - - for line, line_index in p.lines[brace_line+1:] { length := 0; @@ -352,7 +352,7 @@ align_struct :: proc(p: ^Printer, index: int) { length += len(format_token.text) + format_token.spaces_before; } - if colon_count > brace_token.parameter_count { + if colon_count >= brace_token.parameter_count { break; } } @@ -371,19 +371,18 @@ align_struct :: proc(p: ^Printer, index: int) { if format_token.kind == .Colon { colon_count += 1; - line.format_tokens[i+1].spaces_before += (largest - length) - 1; + line.format_tokens[i+1].spaces_before = largest - length + 1; break; } length += len(format_token.text) + format_token.spaces_before; } - if colon_count > brace_token.parameter_count { + if colon_count >= brace_token.parameter_count { break; } } - } align_blocks :: proc(p: ^Printer) { diff --git a/core/odin/printer/visit.odin b/core/odin/printer/visit.odin index 5e54368bb..a00c8ec7c 100644 --- a/core/odin/printer/visit.odin +++ b/core/odin/printer/visit.odin @@ -1259,14 +1259,13 @@ visit_field_list :: proc(p: ^Printer, list: ^ast.Field_List, add_comma := false, visit_exprs(p, field.names, true); - if len(field.names) != 0 { - push_generic_token(p, .Colon, 0); - } - if field.type != nil { + if len(field.names) != 0 { + push_generic_token(p, .Colon, 0); + } visit_expr(p, field.type); } else { - push_generic_token(p, .Colon, 0); + push_generic_token(p, .Colon, 1); push_generic_token(p, .Eq, 0); visit_expr(p, field.default_value); } From bab4e5531aa13c3e3e76f22d59ce3253456276d3 Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Wed, 14 Apr 2021 21:53:11 +0200 Subject: [PATCH 19/49] remove print --- core/odin/printer/printer.odin | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/odin/printer/printer.odin b/core/odin/printer/printer.odin index 21765f6f0..b194ead26 100644 --- a/core/odin/printer/printer.odin +++ b/core/odin/printer/printer.odin @@ -103,6 +103,7 @@ default_style := Config { indent_cases = false, align_switch = true, align_structs = true, + newline_style = .LF, }; make_printer :: proc(config: Config, allocator := context.allocator) -> Printer { @@ -262,8 +263,6 @@ align_switch_smt :: proc(p: ^Printer, index: int) { } - fmt.println(case_count, brace_token); - case_count = 0; for line, line_index in p.lines[brace_line+1:] { From a09300fb0ef3c5c1fe6fa085961b7fb9f3646379 Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Thu, 15 Apr 2021 00:11:10 +0200 Subject: [PATCH 20/49] more fixes --- core/odin/printer/visit.odin | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/core/odin/printer/visit.odin b/core/odin/printer/visit.odin index a00c8ec7c..f08eae7e7 100644 --- a/core/odin/printer/visit.odin +++ b/core/odin/printer/visit.odin @@ -405,11 +405,11 @@ visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) { if v.name.text != "" { push_generic_token(p, v.import_tok.kind, 1); - push_generic_token(p, v.name.kind, 1); - push_ident_token(p, v.fullpath, 0); + push_generic_token(p, v.name.kind, 1, v.name.text); + push_ident_token(p, v.fullpath, 1); } else { push_generic_token(p, v.import_tok.kind, 1); - push_ident_token(p, v.fullpath, 0); + push_ident_token(p, v.fullpath, 1); } case Value_Decl: @@ -748,7 +748,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener if v.label != nil { visit_expr(p, v.label); - push_generic_token(p, .Colon, 1); + push_generic_token(p, .Colon, 0); } push_ident_token(p, "#unroll", 0); @@ -771,7 +771,7 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener if v.label != nil { visit_expr(p, v.label); - push_generic_token(p, .Colon, 1); + push_generic_token(p, .Colon, 0); } push_generic_token(p, .For, 1); @@ -932,9 +932,10 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr) { push_generic_token(p, v.op.kind, 0); case Type_Cast: push_generic_token(p, v.tok.kind, 1); - push_generic_token(p, .Open_Paren, 1); + push_generic_token(p, .Open_Paren, 0); visit_expr(p, v.type); push_generic_token(p, .Close_Paren, 0); + merge_next_token(p); visit_expr(p, v.expr); case Basic_Directive: push_generic_token(p, v.tok.kind, 1); @@ -1080,7 +1081,7 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr) { case Binary_Expr: visit_binary_expr(p, v); case Implicit_Selector_Expr: - push_generic_token(p, .Period, 0); + push_generic_token(p, .Period, 1); push_ident_token(p, v.field.name, 0); case Call_Expr: visit_expr(p, v.expr); From 22daa50374478d1aa98a24ed985e9ce0c9691a27 Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Thu, 15 Apr 2021 00:19:13 +0200 Subject: [PATCH 21/49] ran the odinfmt - looks good, except for multi line binary operations --- core/odin/printer/printer.odin | 638 +++++----- core/odin/printer/visit.odin | 2078 ++++++++++++++++---------------- 2 files changed, 1346 insertions(+), 1370 deletions(-) diff --git a/core/odin/printer/printer.odin b/core/odin/printer/printer.odin index b194ead26..4d8539dfa 100644 --- a/core/odin/printer/printer.odin +++ b/core/odin/printer/printer.odin @@ -8,483 +8,467 @@ import "core:fmt" import "core:unicode/utf8" import "core:mem" -Line_Type_Enum :: enum{Line_Comment, Value_Decl, Switch_Stmt, Struct}; +Line_Type_Enum :: enum {Line_Comment, Value_Decl, Switch_Stmt, Struct} Line_Type :: bit_set[Line_Type_Enum]; Line :: struct { format_tokens: [dynamic] Format_Token, - finalized: bool, - used: bool, - depth: int, - types: Line_Type, //for performance, so you don't have to verify what types are in it by going through the tokens - might give problems when adding linebreaking + finalized: bool, + used: bool, + depth: int, + types: Line_Type, //for performance, so you don't have to verify what types are in it by going through the tokens - might give problems when adding linebreaking } Format_Token :: struct { - kind: tokenizer.Token_Kind, - text: string, - spaces_before: int, - parameter_count: int, + kind: tokenizer.Token_Kind, + text: string, + spaces_before: int, + parameter_count: int, } Printer :: struct { - string_builder: strings.Builder, - config: Config, - depth: int, //the identation depth - comments: [dynamic]^ast.Comment_Group, - latest_comment_index: int, - allocator: mem.Allocator, - file: ^ast.File, + string_builder: strings.Builder, + config: Config, + depth: int, //the identation depth + comments: [dynamic] ^ast.Comment_Group, + latest_comment_index: int, + allocator: mem.Allocator, + file: ^ast.File, source_position: tokenizer.Pos, - last_source_position: tokenizer.Pos, + last_source_position: tokenizer.Pos, 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, - last_line_index: int, - last_token: ^Format_Token, - merge_next_token: bool, - space_next_token: bool, - debug: bool, + current_line: ^Line, + current_line_index: int, + last_line_index: int, + last_token: ^Format_Token, + merge_next_token: bool, + space_next_token: bool, + debug: bool, } Config :: struct { - spaces: int, //Spaces per indentation - newline_limit: int, //The limit of newlines between statements and declarations. - tabs: bool, //Enable or disable tabs - convert_do: bool, //Convert all do statements to brace blocks - semicolons: bool, //Enable semicolons - split_multiple_stmts: bool, - align_switch: bool, - brace_style: Brace_Style, - align_assignments: bool, - align_structs: bool, - align_style: Alignment_Style, - indent_cases: bool, - newline_style: Newline_Style, + spaces: int, //Spaces per indentation + newline_limit: int, //The limit of newlines between statements and declarations. + tabs: bool, //Enable or disable tabs + convert_do: bool, //Convert all do statements to brace blocks + semicolons: bool, //Enable semicolons + split_multiple_stmts: bool, + align_switch: bool, + brace_style: Brace_Style, + align_assignments: bool, + align_structs: bool, + align_style: Alignment_Style, + indent_cases: bool, + newline_style: Newline_Style, } Brace_Style :: enum { - _1TBS, - Allman, - Stroustrup, - K_And_R, + _1TBS, + Allman, + Stroustrup, + K_And_R, } Block_Type :: enum { - None, - If_Stmt, - Proc, - Generic, - Comp_Lit, - Switch_Stmt, + None, + If_Stmt, + Proc, + Generic, + Comp_Lit, + Switch_Stmt, } Alignment_Style :: enum { - Align_On_Colon_And_Equals, - Align_On_Type_And_Equals, + Align_On_Colon_And_Equals, + Align_On_Type_And_Equals, } Newline_Style :: enum { - CRLF, - LF, + CRLF, + LF, } default_style := Config { - spaces = 4, - newline_limit = 2, - convert_do = false, - semicolons = true, - tabs = false, - brace_style = ._1TBS, - split_multiple_stmts = true, - align_assignments = true, - align_style = .Align_On_Type_And_Equals, - indent_cases = false, - align_switch = true, - align_structs = true, - newline_style = .LF, + spaces = 4, + newline_limit = 2, + convert_do = false, + semicolons = true, + tabs = false, + brace_style = ._1TBS, + split_multiple_stmts = true, + align_assignments = true, + align_style = .Align_On_Type_And_Equals, + indent_cases = false, + align_switch = true, + align_structs = true, + newline_style = .CRLF, }; make_printer :: proc(config: Config, allocator := context.allocator) -> Printer { - return { - config = config, - allocator = allocator, - debug = false, - }; + return { + config = config, + allocator = allocator, + debug = false, + }; } 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); - } + p.comments = file.comments; - set_line(p, 0); + 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); + } - push_generic_token(p, .Package, 0); - push_ident_token(p, file.pkg_name, 1); + 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); } - if len(p.comments) > 0 { - infinite := p.comments[len(p.comments)-1].end; - infinite.offset = 9999999; - push_comments(p, infinite); - } + if len(p.comments) > 0 { + infinite := p.comments[len(p.comments) - 1].end; + infinite.offset = 9999999; + push_comments(p, infinite); + } - fix_lines(p); + fix_lines(p); builder := strings.make_builder(0, mem.megabytes(5), p.allocator); last_line := 0; - newline: string; + newline: string; - if p.config.newline_style == .LF { - newline = "\n"; - } else { - newline = "\r\n"; - } + 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_string(&builder, newline); - } - - 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, ' '); - } - } + for i := 0; i < diff_line; i += 1 { + strings.write_string(&builder, newline); + } - if p.debug { - strings.write_string(&builder, fmt.tprintf("line %v: ", line_index)); - } + 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, ' '); + } + } - for format_token in line.format_tokens { + if p.debug { + strings.write_string(&builder, fmt.tprintf("line %v: ", line_index)); + } - for i := 0; i < format_token.spaces_before; i += 1 { - strings.write_byte(&builder, ' '); - } + for format_token in line.format_tokens { - strings.write_string(&builder, format_token.text); - } - - last_line = line_index; + for i := 0; i < format_token.spaces_before; i += 1 { + strings.write_byte(&builder, ' '); + } + + strings.write_string(&builder, format_token.text); + } + + last_line = line_index; } return strings.to_string(builder); } fix_lines :: proc(p: ^Printer) { - align_var_decls(p); - align_blocks(p); - align_comments(p); //align them last since they rely on the other alignments + 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; + switch_found := false; + brace_token: Format_Token; + brace_line: int; - found_switch_brace: for line, line_index in p.lines[index:] { + found_switch_brace: for line, line_index in p.lines[index:] { - for format_token in line.format_tokens { + for format_token in line.format_tokens { - if format_token.kind == .Open_Brace && switch_found { - brace_token = format_token; - brace_line = line_index+index; - break found_switch_brace; - } else if format_token.kind == .Open_Brace { - break; - } else if format_token.kind == .Switch { - switch_found = true; - } + if format_token.kind == .Open_Brace && switch_found { + brace_token = format_token; + brace_line = line_index + 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; + case_count := 0; - if !switch_found { - return; - } + //find all the switch cases that are one lined + for line, line_index in p.lines[brace_line + 1:] { - largest := 0; - case_count := 0; + case_found := false; + colon_found := false; + length := 0; - //find all the switch cases that are one lined - for line, line_index in p.lines[brace_line+1:] { + for format_token in line.format_tokens { - case_found := false; - colon_found := false; - length := 0; + if format_token.kind == .Comment { + continue; + } - for format_token in line.format_tokens { + //this will only happen if the case is one lined + if case_found && colon_found { + largest = max(length, largest); + break; + } - if format_token.kind == .Comment { - continue; - } + if format_token.kind == .Case { + case_found = true; + case_count += 1; + } else if format_token.kind == .Colon { + colon_found = true; + } - //this will only happen if the case is one lined - if case_found && colon_found { - largest = max(length, largest); - break; - } + length += len(format_token.text) + format_token.spaces_before; + } - if format_token.kind == .Case { - case_found = true; - case_count += 1; - } else if format_token.kind == .Colon { - colon_found = true; - } + if case_count >= brace_token.parameter_count { + break; + } + } - length += len(format_token.text) + format_token.spaces_before; - } + case_count = 0; - if case_count >= brace_token.parameter_count { - break; - } + for line, line_index in p.lines[brace_line + 1:] { - } + case_found := false; + colon_found := false; + length := 0; - case_count = 0; + for format_token, i in line.format_tokens { - for line, line_index in p.lines[brace_line+1:] { + if format_token.kind == .Comment { + continue; + } - case_found := false; - colon_found := false; - length := 0; + //this will only happen if the case is one lined + if case_found && colon_found { + line.format_tokens[i].spaces_before += (largest - length); + break; + } - for format_token, i in line.format_tokens { + if format_token.kind == .Case { + case_found = true; + case_count += 1; + } else if format_token.kind == .Colon { + colon_found = true; + } - 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; - case_count += 1; - } else if format_token.kind == .Colon { - colon_found = true; - } - - length += len(format_token.text) + format_token.spaces_before; - - } - - if case_count >= brace_token.parameter_count { - break; - } - } + length += len(format_token.text) + format_token.spaces_before; + } + if case_count >= brace_token.parameter_count { + break; + } + } } align_struct :: proc(p: ^Printer, index: int) { - struct_found := false; - brace_token: Format_Token; - brace_line: int; + struct_found := false; + brace_token: Format_Token; + brace_line: int; - found_struct_brace: for line, line_index in p.lines[index:] { + found_struct_brace: for line, line_index in p.lines[index:] { - for format_token in line.format_tokens { + for format_token in line.format_tokens { - if format_token.kind == .Open_Brace && struct_found { - brace_token = format_token; - brace_line = line_index+index; - break found_struct_brace; - } else if format_token.kind == .Open_Brace { - break; - } else if format_token.kind == .Struct { - struct_found = true; - } + if format_token.kind == .Open_Brace && struct_found { + brace_token = format_token; + brace_line = line_index + index; + break found_struct_brace; + } else if format_token.kind == .Open_Brace { + break; + } else if format_token.kind == .Struct { + struct_found = true; + } + } + } - } + if !struct_found { + return; + } - } + largest := 0; + colon_count := 0; - if !struct_found { - return; - } + for line, line_index in p.lines[brace_line + 1:] { - largest := 0; - colon_count := 0; + length := 0; - for line, line_index in p.lines[brace_line+1:] { + for format_token in line.format_tokens { - length := 0; + if format_token.kind == .Comment { + continue; + } - for format_token in line.format_tokens { + if format_token.kind == .Colon { + colon_count += 1; + largest = max(length, largest); + break; + } - if format_token.kind == .Comment { - continue; - } + length += len(format_token.text) + format_token.spaces_before; + } - if format_token.kind == .Colon { - colon_count += 1; - largest = max(length, largest); - break; - } + if colon_count >= brace_token.parameter_count { + break; + } + } - length += len(format_token.text) + format_token.spaces_before; - } + colon_count = 0; - if colon_count >= brace_token.parameter_count { - break; - } - } + for line, line_index in p.lines[brace_line + 1:] { - colon_count = 0; + length := 0; - for line, line_index in p.lines[brace_line+1:] { + for format_token, i in line.format_tokens { - length := 0; + if format_token.kind == .Comment { + continue; + } - for format_token, i in line.format_tokens { + if format_token.kind == .Colon { + colon_count += 1; + line.format_tokens[i + 1].spaces_before = largest - length + 1; + break; + } - if format_token.kind == .Comment { - continue; - } - - if format_token.kind == .Colon { - colon_count += 1; - line.format_tokens[i+1].spaces_before = largest - length + 1; - break; - } - - length += len(format_token.text) + format_token.spaces_before; - } - - if colon_count >= brace_token.parameter_count { - break; - } - } + length += len(format_token.text) + format_token.spaces_before; + } + if colon_count >= brace_token.parameter_count { + break; + } + } } align_blocks :: proc(p: ^Printer) { - for line, line_index in p.lines { + for line, line_index in p.lines { - if len(line.format_tokens) <= 0 { - continue; - } + if len(line.format_tokens) <= 0 { + continue; + } - if .Switch_Stmt in line.types && p.config.align_switch { - align_switch_smt(p, line_index); - } - - if .Struct in line.types && p.config.align_structs { - align_struct(p, line_index); - } - - } + if .Switch_Stmt in line.types && p.config.align_switch { + align_switch_smt(p, line_index); + } + if .Struct in line.types && p.config.align_structs { + align_struct(p, line_index); + } + } } align_comments :: proc(p: ^Printer) { - - Comment_Align_Info :: struct { - length: int, - begin: int, - end: int, - depth: int, - }; - comment_infos := make([dynamic]Comment_Align_Info, 0, context.temp_allocator); + Comment_Align_Info :: struct { + length: int, + begin: int, + end: int, + depth: int, + }; - current_info: Comment_Align_Info; + comment_infos := make([dynamic] Comment_Align_Info, 0, context.temp_allocator); - for line, line_index in p.lines { + current_info: Comment_Align_Info; - if len(line.format_tokens) <= 0 { - continue; - } + for line, line_index in p.lines { - if .Line_Comment in line.types { + if len(line.format_tokens) <= 0 { + continue; + } - if current_info.end + 1 != line_index || current_info.depth != line.depth || - (current_info.begin == current_info.end && current_info.length == 0) { + if .Line_Comment in line.types { - if (current_info.begin != 0 && current_info.end != 0) || current_info.length > 0 { - append(&comment_infos, current_info); - } + if current_info.end + 1 != line_index || current_info.depth != line.depth || + (current_info.begin == current_info.end && current_info.length == 0) { - current_info.begin = line_index; - current_info.end = line_index; - current_info.depth = line.depth; - current_info.length = 0; - } + if (current_info.begin != 0 && current_info.end != 0) || current_info.length > 0 { + append(&comment_infos, current_info); + } - length := 0; + current_info.begin = line_index; + current_info.end = line_index; + current_info.depth = line.depth; + current_info.length = 0; + } - for format_token, i in line.format_tokens { + length := 0; - if format_token.kind == .Comment { - current_info.length = max(current_info.length, length); - current_info.end = line_index; - } + for format_token, i in line.format_tokens { - length += format_token.spaces_before + len(format_token.text); - } + 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); + } - if (current_info.begin != 0 && current_info.end != 0) || current_info.length > 0 { - append(&comment_infos, current_info); - } + for info in comment_infos { - for info in comment_infos { + if info.begin == info.end || info.length == 0 { + continue; + } - if info.begin == info.end || info.length == 0 { - continue; - } + for i := info.begin; i <= info.end; i += 1 { - for i := info.begin; i <= info.end; i += 1 { + l := p.lines[i]; - l := p.lines[i]; + length := 0; - length := 0; + for format_token, i in l.format_tokens { - 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); - } - - } - - } + 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 f08eae7e7..7cc856e3b 100644 --- a/core/odin/printer/visit.odin +++ b/core/odin/printer/visit.odin @@ -11,239 +11,238 @@ 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 { - 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]; - }, - }; +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]; + }, + }; } @(private) comment_before_position :: proc(p: ^Printer, pos: tokenizer.Pos) -> bool { - if len(p.comments) <= p.latest_comment_index { - return false; - } + if len(p.comments) <= p.latest_comment_index { + return false; + } - comment := p.comments[p.latest_comment_index]; + comment := p.comments[p.latest_comment_index]; - return comment.pos.offset < pos.offset; + return comment.pos.offset < pos.offset; } @(private) next_comment_group :: proc(p: ^Printer) { - p.latest_comment_index += 1; + p.latest_comment_index += 1; } - -@(private) + +@(private) push_comment :: proc(p: ^Printer, comment: tokenizer.Token) -> int { - if len(comment.text) == 0 { - return 0; - } + if len(comment.text) == 0 { + return 0; + } - if comment.text[0] == '/' && comment.text[1] == '/' { - format_token := Format_Token { - spaces_before = 1, - kind = .Comment, - text = comment.text, - }; + if comment.text[0] == '/' && comment.text[1] == '/' { + format_token := Format_Token { + spaces_before = 1, + kind = .Comment, + text = comment.text, + }; - if len(p.current_line.format_tokens) == 0 { - format_token.spaces_before = 0; - } + if len(p.current_line.format_tokens) == 0 { + format_token.spaces_before = 0; + } - if !p.current_line.used { - p.current_line.used = true; - p.current_line.depth = p.depth; - } + if !p.current_line.used { + p.current_line.used = true; + p.current_line.depth = p.depth; + } - append(&p.current_line.format_tokens, format_token); - p.last_token = &p.current_line.format_tokens[len(p.current_line.format_tokens)-1]; + 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}); + hint_current_line(p,{.Line_Comment}); - return 0; - } else { + return 0; + } else { - builder := strings.make_builder(context.temp_allocator); + builder := strings.make_builder(context.temp_allocator); - c_len := len(comment.text); - trim_space := true; + c_len := len(comment.text); + trim_space := true; - multilines: [dynamic] string; + multilines: [dynamic] string; - for i := 0; i < len(comment.text); i += 1 { + for i := 0; i < len(comment.text); i += 1 { - c := comment.text[i]; + c := comment.text[i]; - if c != ' ' && c != '\t' { - trim_space = false; - } + if c != ' ' && c != '\t' { + trim_space = false; + } - if (c == ' ' || c == '\t' || c == '\n') && trim_space { - continue; - } else if c == 13 && comment.text[min(c_len - 1, i + 1)] == 10 { - append(&multilines, strings.to_string(builder)); - builder = strings.make_builder(context.temp_allocator); - trim_space = true; - i += 1; - } else if c == 10 { - append(&multilines, strings.to_string(builder)); - builder = strings.make_builder(context.temp_allocator); - trim_space = true; - } else if c == '/' && comment.text[min(c_len - 1, i + 1)] == '*' { - strings.write_string(&builder, "/*"); - trim_space = true; - p.depth += 1; - i += 1; - } else if c == '*' && comment.text[min(c_len - 1, i + 1)] == '/' { - p.depth -= 1; - trim_space = true; - strings.write_string(&builder, "*/"); - i += 1; - } else { - strings.write_byte(&builder, c); - } + if (c == ' ' || c == '\t' || c == '\n') && trim_space { + continue; + } else if c == 13 && comment.text[min(c_len - 1, i + 1)] == 10 { + append(&multilines, strings.to_string(builder)); + builder = strings.make_builder(context.temp_allocator); + trim_space = true; + i += 1; + } else if c == 10 { + append(&multilines, strings.to_string(builder)); + builder = strings.make_builder(context.temp_allocator); + trim_space = true; + } else if c == '/' && comment.text[min(c_len - 1, i + 1)] == '*' { + strings.write_string(&builder, "/*"); + trim_space = true; + p.depth += 1; + i += 1; + } else if c == '*' && comment.text[min(c_len - 1, i + 1)] == '/' { + p.depth -= 1; + trim_space = true; + strings.write_string(&builder, "*/"); + i += 1; + } else { + strings.write_byte(&builder, c); + } + } - } + if strings.builder_len(builder) > 0 { + append(&multilines, strings.to_string(builder)); + } - if strings.builder_len(builder) > 0 { - append(&multilines, strings.to_string(builder)); - } + for line in multilines { + format_token := Format_Token { + spaces_before = 1, + kind = .Comment, + text = line, + }; - for line in multilines { - format_token := Format_Token { - spaces_before = 1, - kind = .Comment, - text = line, - }; + if len(p.current_line.format_tokens) == 0 { + format_token.spaces_before = 0; + } - if len(p.current_line.format_tokens) == 0 { - format_token.spaces_before = 0; - } + if strings.contains(line, "*/") { + unindent(p); + } - if strings.contains(line, "*/") { - unindent(p); - } + if !p.current_line.used { + p.current_line.used = true; + p.current_line.depth = p.depth; + } - if !p.current_line.used { - p.current_line.used = true; - p.current_line.depth = p.depth; - } + append(&p.current_line.format_tokens, format_token); + p.last_token = &p.current_line.format_tokens[len(p.current_line.format_tokens) - 1]; - append(&p.current_line.format_tokens, format_token); - p.last_token = &p.current_line.format_tokens[len(p.current_line.format_tokens)-1]; + if strings.contains(line, "/*") { + indent(p); + } - if strings.contains(line, "/*") { - indent(p); - } + newline_position(p, 1); + } - newline_position(p, 1); - } - - return len(multilines); - } + return len(multilines); + } } @(private) push_comments :: proc(p: ^Printer, pos: tokenizer.Pos) { - prev_comment: ^tokenizer.Token; - prev_comment_lines: int; + prev_comment: ^tokenizer.Token; + prev_comment_lines: int; - for comment_before_position(p, pos) { + for comment_before_position(p, pos) { - comment_group := p.comments[p.latest_comment_index]; + comment_group := p.comments[p.latest_comment_index]; - if prev_comment == nil { - lines := comment_group.pos.line - p.last_source_position.line; - set_line(p, p.last_line_index + min(p.config.newline_limit, lines)); - } + if prev_comment == nil { + lines := comment_group.pos.line - p.last_source_position.line; + set_line(p, p.last_line_index + min(p.config.newline_limit, lines)); + } - for comment, i in comment_group.list { + for comment, i in comment_group.list { - if prev_comment != nil && p.last_source_position.line != comment.pos.line { - newline_position(p, min(p.config.newline_limit, comment.pos.line - prev_comment.pos.line - prev_comment_lines)); - } + if prev_comment != nil && p.last_source_position.line != comment.pos.line { + newline_position(p, min(p.config.newline_limit, comment.pos.line - prev_comment.pos.line - prev_comment_lines)); + } - prev_comment_lines = push_comment(p, comment); - prev_comment = &comment_group.list[i]; - } + prev_comment_lines = push_comment(p, comment); + prev_comment = &comment_group.list[i]; + } - next_comment_group(p); - } - - if prev_comment != nil { - newline_position(p, min(p.config.newline_limit, p.source_position.line - prev_comment.pos.line)); - } + next_comment_group(p); + } + + if prev_comment != nil { + newline_position(p, min(p.config.newline_limit, p.source_position.line - prev_comment.pos.line)); + } } @(private) append_format_token :: proc(p: ^Printer, format_token: Format_Token) -> ^Format_Token { - format_token := format_token; + format_token := format_token; - if p.last_token != nil && (p.last_token.kind == .Ellipsis || p.last_token.kind == .Range_Half || - p.last_token.kind == .Open_Paren || p.last_token.kind == .Period || - p.last_token.kind == .Open_Brace || p.last_token.kind == .Open_Bracket) { - format_token.spaces_before = 0; - } else if p.merge_next_token { - format_token.spaces_before = 0; - p.merge_next_token = false; - } else if p.space_next_token { - format_token.spaces_before = 1; - p.space_next_token = false; - } + if p.last_token != nil && (p.last_token.kind == .Ellipsis || p.last_token.kind == .Range_Half || + p.last_token.kind == .Open_Paren || p.last_token.kind == .Period || + p.last_token.kind == .Open_Brace || p.last_token.kind == .Open_Bracket) { + format_token.spaces_before = 0; + } else if p.merge_next_token { + format_token.spaces_before = 0; + p.merge_next_token = false; + } else if p.space_next_token { + format_token.spaces_before = 1; + p.space_next_token = false; + } - push_comments(p, p.source_position); + push_comments(p, p.source_position); - unwrapped_line := p.current_line; + unwrapped_line := p.current_line; - if !unwrapped_line.used { - 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; - } - - p.last_source_position = p.source_position; - p.last_line_index = p.current_line_index; + if len(unwrapped_line.format_tokens) == 0 && format_token.spaces_before == 1 { + format_token.spaces_before = 0; + } - append(&unwrapped_line.format_tokens, format_token); - return &unwrapped_line.format_tokens[len(unwrapped_line.format_tokens)-1]; + p.last_source_position = p.source_position; + p.last_line_index = p.current_line_index; + + append(&unwrapped_line.format_tokens, format_token); + 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); + p.last_token = append_format_token(p, format_token); } @(private) push_generic_token :: proc(p: ^Printer, kind: tokenizer.Token_Kind, spaces_before: int, value := "") { - + format_token := Format_Token { spaces_before = spaces_before, kind = kind, text = tokenizer.tokens[kind], }; - if value != "" { - format_token.text = value; - } + if value != "" { + format_token.text = value; + } p.last_token = append_format_token(p, format_token); } @@ -269,1204 +268,1197 @@ push_ident_token :: proc(p: ^Printer, text: string, spaces_before: int) { text = text, }; - p.last_token = append_format_token(p, format_token); + p.last_token = append_format_token(p, format_token); } @(private) set_source_position :: proc(p: ^Printer, pos: tokenizer.Pos) { - p.source_position = pos; + p.source_position = pos; } @(private) move_line :: proc(p: ^Printer, pos: tokenizer.Pos) { - move_line_limit(p, pos, p.config.newline_limit); + move_line_limit(p, pos, p.config.newline_limit); } @(private) move_line_limit :: proc(p: ^Printer, pos: tokenizer.Pos, limit: int) -> bool { - lines := min(pos.line - p.source_position.line, limit); + lines := min(pos.line - p.source_position.line, limit); - if lines < 0 { - return false; - } + if lines < 0 { + return false; + } - p.source_position = pos; - p.current_line_index += lines; - set_line(p, p.current_line_index); - return lines > 0; + p.source_position = pos; + p.current_line_index += lines; + set_line(p, p.current_line_index); + return lines > 0; } @(private) set_line :: proc(p: ^Printer, line: int) -> ^Line { - unwrapped_line: ^Line; + unwrapped_line: ^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]; + 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]; } - p.current_line = unwrapped_line; - p.current_line_index = line; + p.current_line = unwrapped_line; + p.current_line_index = line; - return unwrapped_line; + return unwrapped_line; } @(private) newline_position :: proc(p: ^Printer, count: int) { - p.current_line_index += count; - set_line(p, p.current_line_index); + p.current_line_index += count; + set_line(p, p.current_line_index); } @(private) indent :: proc(p: ^Printer) { - p.depth += 1; + p.depth += 1; } @(private) unindent :: proc(p: ^Printer) { - p.depth -= 1; + p.depth -= 1; } @(private) merge_next_token :: proc(p: ^Printer) { - p.merge_next_token = true; + p.merge_next_token = true; } @(private) space_next_token :: proc(p: ^Printer) { - p.space_next_token = true; + p.space_next_token = true; } @(private) hint_current_line :: proc(p: ^Printer, hint: Line_Type) { - p.current_line.types |= hint; + p.current_line.types |= hint; } @(private) visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) { - using ast; + using ast; - if decl == nil { - return; - } + if decl == nil { + return; + } - switch v in &decl.derived { - case Expr_Stmt: - move_line(p, decl.pos); - visit_expr(p, v.expr); - if p.config.semicolons { + switch v in &decl.derived { + case Expr_Stmt: + move_line(p, decl.pos); + visit_expr(p, v.expr); + if p.config.semicolons { push_generic_token(p, .Semicolon, 0); - } - case When_Stmt: - visit_stmt(p, cast(^Stmt)decl); - case Foreign_Import_Decl: - if len(v.attributes) > 0 { - sort.sort(sort_attribute(&v.attributes)); - move_line(p, v.attributes[0].pos); - visit_attributes(p, v.attributes); - } + } + case When_Stmt: + visit_stmt(p, cast(^Stmt)decl); + case Foreign_Import_Decl: + if len(v.attributes) > 0 { + sort.sort(sort_attribute(&v.attributes)); + move_line(p, v.attributes[0].pos); + visit_attributes(p, v.attributes); + } + + move_line(p, decl.pos); - move_line(p, decl.pos); - push_generic_token(p, v.foreign_tok.kind, 0); push_generic_token(p, v.import_tok.kind, 1); - if v.name != nil { + if v.name != nil { push_ident_token(p, v.name.name, 1); - } + } - for path in v.fullpaths { + for path in v.fullpaths { push_ident_token(p, path, 0); - } - case Foreign_Block_Decl: + } + case Foreign_Block_Decl: + + if len(v.attributes) > 0 { + sort.sort(sort_attribute(&v.attributes)); + move_line(p, v.attributes[0].pos); + visit_attributes(p, v.attributes); + } + + move_line(p, decl.pos); - if len(v.attributes) > 0 { - sort.sort(sort_attribute(&v.attributes)); - move_line(p, v.attributes[0].pos); - visit_attributes(p, v.attributes); - } - - move_line(p, decl.pos); - push_generic_token(p, .Foreign, 0); - visit_expr(p, v.foreign_library); - visit_stmt(p, v.body); - case Import_Decl: - move_line(p, decl.pos); + visit_expr(p, v.foreign_library); + visit_stmt(p, v.body); + case Import_Decl: + move_line(p, decl.pos); - if v.name.text != "" { + if v.name.text != "" { push_generic_token(p, v.import_tok.kind, 1); push_generic_token(p, v.name.kind, 1, v.name.text); push_ident_token(p, v.fullpath, 1); - } else { + } else { push_generic_token(p, v.import_tok.kind, 1); push_ident_token(p, v.fullpath, 1); - } + } - case Value_Decl: - if len(v.attributes) > 0 { - sort.sort(sort_attribute(&v.attributes)); - move_line(p, v.attributes[0].pos); - visit_attributes(p, v.attributes); - } + case Value_Decl: + if len(v.attributes) > 0 { + sort.sort(sort_attribute(&v.attributes)); + move_line(p, v.attributes[0].pos); + visit_attributes(p, v.attributes); + } - move_line(p, decl.pos); + move_line(p, decl.pos); - if v.is_using { + if v.is_using { push_generic_token(p, .Using, 0); - } + } - visit_exprs(p, v.names, true); + visit_exprs(p, v.names, true); - if v.type != nil { + if v.type != nil { if !v.is_mutable && v.type != nil { push_generic_token(p, .Colon, 0); - } else { + } else { push_generic_token(p, .Colon, 0); } - visit_expr(p, v.type); - } else { + visit_expr(p, v.type); + } else { if !v.is_mutable && v.type == nil { push_generic_token(p, .Colon, 1); - push_generic_token(p, .Colon, 0); + push_generic_token(p, .Colon, 0); } else { push_generic_token(p, .Colon, 1); } - } + } - if v.is_mutable && v.type != nil && len(v.values) != 0 { + if v.is_mutable && v.type != nil && len(v.values) != 0 { push_generic_token(p, .Eq, 1); - } else if v.is_mutable && v.type == nil && len(v.values) != 0 { - push_generic_token(p, .Eq, 0); - } else if !v.is_mutable && v.type != nil { + } else if v.is_mutable && v.type == nil && len(v.values) != 0 { + push_generic_token(p, .Eq, 0); + } else if !v.is_mutable && v.type != nil { push_generic_token(p, .Colon, 0); - } + } - visit_exprs(p, v.values, true); + visit_exprs(p, v.values, true); - add_semicolon := true; + add_semicolon := true; - for value in v.values { - switch a in value.derived { - case Proc_Lit, Union_Type, Enum_Type, Struct_Type: - add_semicolon = false || called_in_stmt; - } - } + for value in v.values { + switch a in value.derived { + case Proc_Lit, Union_Type, Enum_Type, Struct_Type: + add_semicolon = false || called_in_stmt; + } + } - if add_semicolon && p.config.semicolons && !p.skip_semicolon { + if add_semicolon && p.config.semicolons && !p.skip_semicolon { push_generic_token(p, .Semicolon, 0); - } + } - case: - panic(fmt.aprint(decl.derived)); - } + case: + panic(fmt.aprint(decl.derived)); + } } @(private) -visit_exprs :: proc(p: ^Printer, list: []^ast.Expr, add_comma := false, trailing := false) { +visit_exprs :: proc(p: ^Printer, list: [] ^ast.Expr, add_comma := false, trailing := false) { - if len(list) == 0 { - return; - } + if len(list) == 0 { + return; + } - //we have to newline the expressions to respect the source - for expr, i in list { + //we have to newline the expressions to respect the source + for expr, i in list { - move_line_limit(p, expr.pos, 1); + move_line_limit(p, expr.pos, 1); - visit_expr(p, expr); + visit_expr(p, expr); - if (i != len(list) - 1 || trailing) && add_comma { - push_generic_token(p, .Comma, 0); - } - } + if (i != len(list) - 1 || trailing) && add_comma { + push_generic_token(p, .Comma, 0); + } + } } @(private) -visit_attributes :: proc(p: ^Printer, attributes: [dynamic]^ast.Attribute) { +visit_attributes :: proc(p: ^Printer, attributes: [dynamic] ^ast.Attribute) { - if len(attributes) == 0 { - return; - } + if len(attributes) == 0 { + return; + } - for attribute, i in attributes { + for attribute, i in attributes { - move_line_limit(p, attribute.pos, 1); + move_line_limit(p, attribute.pos, 1); - push_generic_token(p, .At, 0); - push_generic_token(p, .Open_Paren, 0); + push_generic_token(p, .At, 0); + push_generic_token(p, .Open_Paren, 0); - visit_exprs(p, attribute.elems, true); + visit_exprs(p, attribute.elems, true); - push_generic_token(p, .Close_Paren, 0); - } + push_generic_token(p, .Close_Paren, 0); + } } @(private) visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Generic, empty_block := false, block_stmt := false) { - using ast; + using ast; - if stmt == nil { - return; - } + if stmt == nil { + return; + } - switch v in stmt.derived { - case Value_Decl: - visit_decl(p, cast(^Decl)stmt, true); - return; - case Foreign_Import_Decl: - visit_decl(p, cast(^Decl)stmt, true); - return; - case Foreign_Block_Decl: - visit_decl(p, cast(^Decl)stmt, true); - return; - } + switch v in stmt.derived { + case Value_Decl: + visit_decl(p, cast(^Decl)stmt, true); + return; + case Foreign_Import_Decl: + visit_decl(p, cast(^Decl)stmt, true); + return; + case Foreign_Block_Decl: + visit_decl(p, cast(^Decl)stmt, true); + return; + } - switch v in stmt.derived { - case Using_Stmt: - move_line(p, v.pos); + switch v in stmt.derived { + case Using_Stmt: + move_line(p, v.pos); - push_generic_token(p, .Using, 1); + push_generic_token(p, .Using, 1); - visit_exprs(p, v.list, true); + visit_exprs(p, v.list, true); - if p.config.semicolons { - push_generic_token(p, .Semicolon, 0); - } - case Block_Stmt: - move_line(p, v.pos); + if p.config.semicolons { + push_generic_token(p, .Semicolon, 0); + } + case Block_Stmt: + move_line(p, v.pos); - if v.pos.line == v.end.line { - if !empty_block { - push_generic_token(p, .Open_Brace, 0); - } + if v.pos.line == v.end.line { + if !empty_block { + push_generic_token(p, .Open_Brace, 0); + } - set_source_position(p, v.pos); + set_source_position(p, v.pos); - visit_block_stmts(p, v.stmts, len(v.stmts) > 1 && p.config.split_multiple_stmts); + visit_block_stmts(p, v.stmts, len(v.stmts) > 1 && p.config.split_multiple_stmts); - set_source_position(p, v.end); + set_source_position(p, v.end); - if !empty_block { - push_generic_token(p, .Close_Brace, 0); - } - } else { - if !empty_block { - visit_begin_brace(p, v.pos, block_type, len(v.stmts)); - } + if !empty_block { + push_generic_token(p, .Close_Brace, 0); + } + } else { + if !empty_block { + visit_begin_brace(p, v.pos, block_type, len(v.stmts)); + } - set_source_position(p, v.pos); + set_source_position(p, v.pos); - visit_block_stmts(p, v.stmts, len(v.stmts) > 1 && p.config.split_multiple_stmts); + visit_block_stmts(p, v.stmts, len(v.stmts) > 1 && p.config.split_multiple_stmts); - set_source_position(p, v.end); + set_source_position(p, v.end); - if !empty_block { - visit_end_brace(p, v.end); - } - } - case If_Stmt: - move_line(p, v.pos); + if !empty_block { + visit_end_brace(p, v.end); + } + } + case If_Stmt: + move_line(p, v.pos); - if v.label != nil { - visit_expr(p, v.label); - push_generic_token(p, .Colon, 0); - } + if v.label != nil { + visit_expr(p, v.label); + push_generic_token(p, .Colon, 0); + } - push_generic_token(p, .If, 1); + push_generic_token(p, .If, 1); - if v.init != nil { - p.skip_semicolon = true; - visit_stmt(p, v.init); - p.skip_semicolon = false; - push_generic_token(p, .Semicolon, 0); - } + if v.init != nil { + p.skip_semicolon = true; + visit_stmt(p, v.init); + p.skip_semicolon = false; + push_generic_token(p, .Semicolon, 0); + } - visit_expr(p, v.cond); + visit_expr(p, v.cond); - uses_do := false; + uses_do := false; - if check_stmt, ok := v.body.derived.(Block_Stmt); ok && check_stmt.uses_do { - uses_do = true; - } + if check_stmt, ok := v.body.derived.(Block_Stmt); ok && check_stmt.uses_do { + uses_do = true; + } - if uses_do && !p.config.convert_do { - push_generic_token(p, .Do, 1); - visit_stmt(p, v.body, .If_Stmt, true); - } else { - if uses_do { - newline_position(p, 1); - } + if uses_do && !p.config.convert_do { + push_generic_token(p, .Do, 1); + visit_stmt(p, v.body, .If_Stmt, true); + } else { + if uses_do { + newline_position(p, 1); + } - visit_stmt(p, v.body, .If_Stmt); - } + visit_stmt(p, v.body, .If_Stmt); + } - if v.else_stmt != nil { + if v.else_stmt != nil { - if p.config.brace_style == .Allman || p.config.brace_style == .Stroustrup { - newline_position(p, 1); - } + if p.config.brace_style == .Allman || p.config.brace_style == .Stroustrup { + newline_position(p, 1); + } - push_generic_token(p, .Else, 1); + push_generic_token(p, .Else, 1); - set_source_position(p, v.else_stmt.pos); + set_source_position(p, v.else_stmt.pos); - visit_stmt(p, v.else_stmt); - } - case Switch_Stmt: - move_line(p, v.pos); + visit_stmt(p, v.else_stmt); + } + case Switch_Stmt: + move_line(p, v.pos); - if v.label != nil { - visit_expr(p, v.label); - push_generic_token(p, .Colon, 0); - } + if v.label != nil { + visit_expr(p, v.label); + push_generic_token(p, .Colon, 0); + } - if v.partial { - push_ident_token(p, "#partial", 1); - } + if v.partial { + push_ident_token(p, "#partial", 1); + } - push_generic_token(p, .Switch, 1); + push_generic_token(p, .Switch, 1); - hint_current_line(p, {.Switch_Stmt}); + hint_current_line(p,{.Switch_Stmt}); - if v.init != nil { - p.skip_semicolon = true; - visit_stmt(p, v.init); - p.skip_semicolon = false; - } + if v.init != nil { + p.skip_semicolon = true; + visit_stmt(p, v.init); + p.skip_semicolon = false; + } - if v.init != nil && v.cond != nil { - push_generic_token(p, .Semicolon, 0); - } + if v.init != nil && v.cond != nil { + push_generic_token(p, .Semicolon, 0); + } - visit_expr(p, v.cond); - visit_stmt(p, v.body); - case Case_Clause: - move_line(p, v.pos); + visit_expr(p, v.cond); + visit_stmt(p, v.body); + case Case_Clause: + move_line(p, v.pos); - if !p.config.indent_cases { - unindent(p); - } + if !p.config.indent_cases { + unindent(p); + } - push_generic_token(p, .Case, 0); + push_generic_token(p, .Case, 0); - if v.list != nil { - visit_exprs(p, v.list, true); - } + if v.list != nil { + visit_exprs(p, v.list, true); + } - push_generic_token(p, v.terminator.kind, 0); + push_generic_token(p, v.terminator.kind, 0); - indent(p); + indent(p); - visit_block_stmts(p, v.body); + visit_block_stmts(p, v.body); - unindent(p); + unindent(p); - if !p.config.indent_cases { - indent(p); - } - case Type_Switch_Stmt: - move_line(p, v.pos); + if !p.config.indent_cases { + indent(p); + } + case Type_Switch_Stmt: + move_line(p, v.pos); - if v.label != nil { - visit_expr(p, v.label); - push_generic_token(p, .Colon, 0); - } + if v.label != nil { + visit_expr(p, v.label); + push_generic_token(p, .Colon, 0); + } - if v.partial { - push_ident_token(p, "#partial", 1); - } + if v.partial { + push_ident_token(p, "#partial", 1); + } - push_generic_token(p, .Switch, 1); + push_generic_token(p, .Switch, 1); - visit_stmt(p, v.tag); - visit_stmt(p, v.body); - case Assign_Stmt: - move_line(p, v.pos); + visit_stmt(p, v.tag); + visit_stmt(p, v.body); + case Assign_Stmt: + move_line(p, v.pos); - visit_exprs(p, v.lhs, true); + visit_exprs(p, v.lhs, true); - push_generic_token(p, v.op.kind, 1); + push_generic_token(p, v.op.kind, 1); - visit_exprs(p, v.rhs, true); + visit_exprs(p, v.rhs, true); - if block_stmt && p.config.semicolons { - push_generic_token(p, .Semicolon, 0); - } - case Expr_Stmt: - move_line(p, v.pos); - visit_expr(p, v.expr); - if block_stmt && p.config.semicolons { - push_generic_token(p, .Semicolon, 0); - } - case For_Stmt: - //this should be simplified - move_line(p, v.pos); + if block_stmt && p.config.semicolons { + push_generic_token(p, .Semicolon, 0); + } + case Expr_Stmt: + move_line(p, v.pos); + visit_expr(p, v.expr); + if block_stmt && p.config.semicolons { + push_generic_token(p, .Semicolon, 0); + } + case For_Stmt: + //this should be simplified + move_line(p, v.pos); - if v.label != nil { - visit_expr(p, v.label); - push_generic_token(p, .Colon, 0); - } + if v.label != nil { + visit_expr(p, v.label); + push_generic_token(p, .Colon, 0); + } - push_generic_token(p, .For, 1); + push_generic_token(p, .For, 1); - if v.init != nil { - p.skip_semicolon = true; - visit_stmt(p, v.init); - p.skip_semicolon = false; - push_generic_token(p, .Semicolon, 0); - } else if v.post != nil { - push_generic_token(p, .Semicolon, 0); - } + if v.init != nil { + p.skip_semicolon = true; + visit_stmt(p, v.init); + p.skip_semicolon = false; + push_generic_token(p, .Semicolon, 0); + } else if v.post != nil { + push_generic_token(p, .Semicolon, 0); + } - if v.cond != nil { - visit_expr(p, v.cond); - } + if v.cond != nil { + visit_expr(p, v.cond); + } - if v.post != nil { - push_generic_token(p, .Semicolon, 0); - visit_stmt(p, v.post); - } else if v.post == nil && v.cond != nil && v.init != nil { - push_generic_token(p, .Semicolon, 0); - } + if v.post != nil { + push_generic_token(p, .Semicolon, 0); + visit_stmt(p, v.post); + } else if v.post == nil && v.cond != nil && v.init != nil { + push_generic_token(p, .Semicolon, 0); + } - visit_stmt(p, v.body); - case Inline_Range_Stmt: + visit_stmt(p, v.body); + case Inline_Range_Stmt: - move_line(p, v.pos); + move_line(p, v.pos); - if v.label != nil { - visit_expr(p, v.label); - push_generic_token(p, .Colon, 0); - } + if v.label != nil { + visit_expr(p, v.label); + push_generic_token(p, .Colon, 0); + } - push_ident_token(p, "#unroll", 0); + push_ident_token(p, "#unroll", 0); - push_generic_token(p, .For, 1); - visit_expr(p, v.val0); + push_generic_token(p, .For, 1); + visit_expr(p, v.val0); - if v.val1 != nil { - push_generic_token(p, .Comma, 0); - visit_expr(p, v.val1); - } + if v.val1 != nil { + push_generic_token(p, .Comma, 0); + visit_expr(p, v.val1); + } - push_generic_token(p, .In, 1); + push_generic_token(p, .In, 1); - visit_expr(p, v.expr); - visit_stmt(p, v.body); - case Range_Stmt: + visit_expr(p, v.expr); + visit_stmt(p, v.body); + case Range_Stmt: - move_line(p, v.pos); + move_line(p, v.pos); - if v.label != nil { - visit_expr(p, v.label); - push_generic_token(p, .Colon, 0); - } + if v.label != nil { + visit_expr(p, v.label); + push_generic_token(p, .Colon, 0); + } - push_generic_token(p, .For, 1); + push_generic_token(p, .For, 1); - if len(v.vals) >= 1 { - visit_expr(p, v.vals[0]); - } + if len(v.vals) >= 1 { + visit_expr(p, v.vals[0]); + } - if len(v.vals) >= 2 { - push_generic_token(p, .Comma, 0); - visit_expr(p, v.vals[1]); - } + if len(v.vals) >= 2 { + push_generic_token(p, .Comma, 0); + visit_expr(p, v.vals[1]); + } - push_generic_token(p, .In, 1); + push_generic_token(p, .In, 1); - visit_expr(p, v.expr); + visit_expr(p, v.expr); - visit_stmt(p, v.body); - case Return_Stmt: - move_line(p, v.pos); + visit_stmt(p, v.body); + case Return_Stmt: + move_line(p, v.pos); - push_generic_token(p, .Return, 1); + push_generic_token(p, .Return, 1); - if v.results != nil { - visit_exprs(p, v.results, true); - } + if v.results != nil { + visit_exprs(p, v.results, true); + } - if block_stmt && p.config.semicolons { - push_generic_token(p, .Semicolon, 0); - } - case Defer_Stmt: - move_line(p, v.pos); - push_generic_token(p, .Defer, 0); + if block_stmt && p.config.semicolons { + push_generic_token(p, .Semicolon, 0); + } + case Defer_Stmt: + move_line(p, v.pos); + push_generic_token(p, .Defer, 0); - visit_stmt(p, v.stmt); + visit_stmt(p, v.stmt); - if p.config.semicolons { - push_generic_token(p, .Semicolon, 0); - } - case When_Stmt: - move_line(p, v.pos); - push_generic_token(p, .When, 1); - visit_expr(p, v.cond); + if p.config.semicolons { + push_generic_token(p, .Semicolon, 0); + } + case When_Stmt: + move_line(p, v.pos); + push_generic_token(p, .When, 1); + visit_expr(p, v.cond); - visit_stmt(p, v.body); + visit_stmt(p, v.body); - if v.else_stmt != nil { + if v.else_stmt != nil { - if p.config.brace_style == .Allman { - newline_position(p, 1); - } + if p.config.brace_style == .Allman { + newline_position(p, 1); + } - push_generic_token(p, .Else, 1); + push_generic_token(p, .Else, 1); - set_source_position(p, v.else_stmt.pos); + set_source_position(p, v.else_stmt.pos); - visit_stmt(p, v.else_stmt); - } + visit_stmt(p, v.else_stmt); + } - case Branch_Stmt: + case Branch_Stmt: - move_line(p, v.pos); + move_line(p, v.pos); - push_generic_token(p, v.tok.kind, 0); + push_generic_token(p, v.tok.kind, 0); - if v.label != nil { - visit_expr(p, v.label); - } + if v.label != nil { + visit_expr(p, v.label); + } - if p.config.semicolons { - push_generic_token(p, .Semicolon, 0); - } - case: - panic(fmt.aprint(stmt.derived)); - } + if p.config.semicolons { + push_generic_token(p, .Semicolon, 0); + } + case: + panic(fmt.aprint(stmt.derived)); + } - set_source_position(p, stmt.end); + set_source_position(p, stmt.end); } - @(private) visit_expr :: proc(p: ^Printer, expr: ^ast.Expr) { - using ast; + using ast; - if expr == nil { - return; - } + if expr == nil { + return; + } - set_source_position(p, expr.pos); + set_source_position(p, expr.pos); - switch v in expr.derived { - case Inline_Asm_Expr: - push_generic_token(p, v.tok.kind, 1, v.tok.text); + switch v in expr.derived { + case Inline_Asm_Expr: + push_generic_token(p, v.tok.kind, 1, v.tok.text); - push_generic_token(p, .Open_Paren, 1); - visit_exprs(p, v.param_types, true, false); - push_generic_token(p, .Close_Paren, 0); + push_generic_token(p, .Open_Paren, 1); + visit_exprs(p, v.param_types, true, false); + push_generic_token(p, .Close_Paren, 0); - push_generic_token(p, .Sub, 1); - push_generic_token(p, .Gt, 0); + push_generic_token(p, .Sub, 1); + push_generic_token(p, .Gt, 0); - visit_expr(p, v.return_type); + visit_expr(p, v.return_type); - push_generic_token(p, .Open_Brace, 1); - visit_expr(p, v.asm_string); - push_generic_token(p, .Comma, 0); - visit_expr(p, v.constraints_string); - push_generic_token(p, .Close_Brace, 0); - case Undef: - push_generic_token(p, .Undef, 1); - case Auto_Cast: - push_generic_token(p, v.op.kind, 1); - visit_expr(p, v.expr); - case Ternary_Expr: - visit_expr(p, v.cond); - push_generic_token(p, v.op1.kind, 1); - visit_expr(p, v.x); - push_generic_token(p, v.op2.kind, 1); - visit_expr(p, v.y); - case Ternary_If_Expr: - visit_expr(p, v.x); - push_generic_token(p, v.op1.kind, 1); - visit_expr(p, v.cond); - push_generic_token(p, v.op2.kind, 1); - visit_expr(p, v.y); - case Ternary_When_Expr: - visit_expr(p, v.x); - push_generic_token(p, v.op1.kind, 1); - visit_expr(p, v.cond); - push_generic_token(p, v.op2.kind, 1); - visit_expr(p, v.y); - case Selector_Call_Expr: - visit_expr(p, v.call.expr); - push_generic_token(p, .Open_Paren, 1); - visit_exprs(p, v.call.args, true); - push_generic_token(p, .Close_Paren, 0); - case Ellipsis: - push_generic_token(p, .Ellipsis, 1); - visit_expr(p, v.expr); - case Relative_Type: - visit_expr(p, v.tag); - visit_expr(p, v.type); - case Slice_Expr: - visit_expr(p, v.expr); - push_generic_token(p, .Open_Bracket, 0); - visit_expr(p, v.low); - push_generic_token(p, v.interval.kind, 0); - if v.high != nil { - merge_next_token(p); - visit_expr(p, v.high); - } - push_generic_token(p, .Close_Bracket, 0); - case Ident: - push_ident_token(p, v.name, 1); - case Deref_Expr: - visit_expr(p, v.expr); - push_generic_token(p, v.op.kind, 0); - case Type_Cast: - push_generic_token(p, v.tok.kind, 1); - push_generic_token(p, .Open_Paren, 0); - visit_expr(p, v.type); - push_generic_token(p, .Close_Paren, 0); - merge_next_token(p); - visit_expr(p, v.expr); - case Basic_Directive: - push_generic_token(p, v.tok.kind, 1); - push_ident_token(p, v.name, 0); - case Distinct_Type: - push_generic_token(p, .Distinct, 1); - visit_expr(p, v.type); - case Dynamic_Array_Type: - visit_expr(p, v.tag); - push_generic_token(p, .Open_Bracket, 1); - push_generic_token(p, .Dynamic, 0); - push_generic_token(p, .Close_Bracket, 0); - visit_expr(p, v.elem); - case Bit_Set_Type: - push_generic_token(p, .Bit_Set, 1); - push_generic_token(p, .Open_Bracket, 0); + push_generic_token(p, .Open_Brace, 1); + visit_expr(p, v.asm_string); + push_generic_token(p, .Comma, 0); + visit_expr(p, v.constraints_string); + push_generic_token(p, .Close_Brace, 0); + case Undef: + push_generic_token(p, .Undef, 1); + case Auto_Cast: + push_generic_token(p, v.op.kind, 1); + visit_expr(p, v.expr); + case Ternary_Expr: + visit_expr(p, v.cond); + push_generic_token(p, v.op1.kind, 1); + visit_expr(p, v.x); + push_generic_token(p, v.op2.kind, 1); + visit_expr(p, v.y); + case Ternary_If_Expr: + visit_expr(p, v.x); + push_generic_token(p, v.op1.kind, 1); + visit_expr(p, v.cond); + push_generic_token(p, v.op2.kind, 1); + visit_expr(p, v.y); + case Ternary_When_Expr: + visit_expr(p, v.x); + push_generic_token(p, v.op1.kind, 1); + visit_expr(p, v.cond); + push_generic_token(p, v.op2.kind, 1); + visit_expr(p, v.y); + case Selector_Call_Expr: + visit_expr(p, v.call.expr); + push_generic_token(p, .Open_Paren, 1); + visit_exprs(p, v.call.args, true); + push_generic_token(p, .Close_Paren, 0); + case Ellipsis: + push_generic_token(p, .Ellipsis, 1); + visit_expr(p, v.expr); + case Relative_Type: + visit_expr(p, v.tag); + visit_expr(p, v.type); + case Slice_Expr: + visit_expr(p, v.expr); + push_generic_token(p, .Open_Bracket, 0); + visit_expr(p, v.low); + push_generic_token(p, v.interval.kind, 0); + if v.high != nil { + merge_next_token(p); + visit_expr(p, v.high); + } + push_generic_token(p, .Close_Bracket, 0); + case Ident: + push_ident_token(p, v.name, 1); + case Deref_Expr: + visit_expr(p, v.expr); + push_generic_token(p, v.op.kind, 0); + case Type_Cast: + push_generic_token(p, v.tok.kind, 1); + push_generic_token(p, .Open_Paren, 0); + visit_expr(p, v.type); + push_generic_token(p, .Close_Paren, 0); + merge_next_token(p); + visit_expr(p, v.expr); + case Basic_Directive: + push_generic_token(p, v.tok.kind, 1); + push_ident_token(p, v.name, 0); + case Distinct_Type: + push_generic_token(p, .Distinct, 1); + visit_expr(p, v.type); + case Dynamic_Array_Type: + visit_expr(p, v.tag); + push_generic_token(p, .Open_Bracket, 1); + push_generic_token(p, .Dynamic, 0); + push_generic_token(p, .Close_Bracket, 0); + visit_expr(p, v.elem); + case Bit_Set_Type: + push_generic_token(p, .Bit_Set, 1); + push_generic_token(p, .Open_Bracket, 0); - visit_expr(p, v.elem); + visit_expr(p, v.elem); - if v.underlying != nil { - push_generic_token(p, .Semicolon, 0); - visit_expr(p, v.underlying); - } + if v.underlying != nil { + push_generic_token(p, .Semicolon, 0); + visit_expr(p, v.underlying); + } - push_generic_token(p, .Close_Bracket, 0); - case Union_Type: - push_generic_token(p, .Union, 1); + push_generic_token(p, .Close_Bracket, 0); + case Union_Type: + push_generic_token(p, .Union, 1); - if v.poly_params != nil { - push_generic_token(p, .Open_Paren, 0); - visit_field_list(p, v.poly_params, true, false); - push_generic_token(p, .Close_Paren, 0); - } - - if v.is_maybe { - push_ident_token(p, "#maybe", 1); - } + if v.poly_params != nil { + push_generic_token(p, .Open_Paren, 0); + visit_field_list(p, v.poly_params, true, false); + push_generic_token(p, .Close_Paren, 0); + } - if v.where_clauses != nil { - move_line(p, v.where_clauses[0].pos); - push_generic_token(p, .Where, 1); - visit_exprs(p, v.where_clauses, true); - } + if v.is_maybe { + push_ident_token(p, "#maybe", 1); + } - if v.variants != nil && (len(v.variants) == 0 || v.pos.line == v.end.line) { - push_generic_token(p, .Open_Brace, 1); - visit_exprs(p, v.variants, true); - push_generic_token(p, .Close_Brace, 0); - } else { - visit_begin_brace(p, v.pos, .Generic); - newline_position(p, 1); - set_source_position(p, v.variants[0].pos); - visit_exprs(p, v.variants, true, true); - visit_end_brace(p, v.end); - } - case Enum_Type: - push_generic_token(p, .Enum, 1); + if v.where_clauses != nil { + move_line(p, v.where_clauses[0].pos); + push_generic_token(p, .Where, 1); + visit_exprs(p, v.where_clauses, true); + } - if v.base_type != nil { - visit_expr(p, v.base_type); - } + if v.variants != nil && (len(v.variants) == 0 || v.pos.line == v.end.line) { + push_generic_token(p, .Open_Brace, 1); + visit_exprs(p, v.variants, true); + push_generic_token(p, .Close_Brace, 0); + } else { + visit_begin_brace(p, v.pos, .Generic); + newline_position(p, 1); + set_source_position(p, v.variants[0].pos); + visit_exprs(p, v.variants, true, true); + visit_end_brace(p, v.end); + } + case Enum_Type: + push_generic_token(p, .Enum, 1); - if v.fields != nil && (len(v.fields) == 0 || v.pos.line == v.end.line) { - push_generic_token(p, .Open_Brace, 1); - visit_exprs(p, v.fields, true); - push_generic_token(p, .Close_Brace, 0); - } else { - visit_begin_brace(p, v.pos, .Generic); - newline_position(p, 1); - set_source_position(p, v.fields[0].pos); - visit_exprs(p, v.fields, true, true); - visit_end_brace(p, v.end); - } + if v.base_type != nil { + visit_expr(p, v.base_type); + } - set_source_position(p, v.end); - case Struct_Type: - push_generic_token(p, .Struct, 1); + if v.fields != nil && (len(v.fields) == 0 || v.pos.line == v.end.line) { + push_generic_token(p, .Open_Brace, 1); + visit_exprs(p, v.fields, true); + push_generic_token(p, .Close_Brace, 0); + } else { + visit_begin_brace(p, v.pos, .Generic); + newline_position(p, 1); + set_source_position(p, v.fields[0].pos); + visit_exprs(p, v.fields, true, true); + visit_end_brace(p, v.end); + } - hint_current_line(p, {.Struct}); + set_source_position(p, v.end); + case Struct_Type: + push_generic_token(p, .Struct, 1); - if v.is_packed { - push_ident_token(p, "#packed", 1); - } + hint_current_line(p,{.Struct}); - if v.is_raw_union { - push_ident_token(p, "#raw_union", 1); - } + if v.is_packed { + push_ident_token(p, "#packed", 1); + } - if v.align != nil { - push_ident_token(p, "#align", 1); - visit_expr(p, v.align); - } + if v.is_raw_union { + push_ident_token(p, "#raw_union", 1); + } - if v.poly_params != nil { - push_generic_token(p, .Open_Paren, 0); - visit_field_list(p, v.poly_params, true, false); - push_generic_token(p, .Close_Paren, 0); - } + if v.align != nil { + push_ident_token(p, "#align", 1); + visit_expr(p, v.align); + } - if v.where_clauses != nil { - move_line(p, v.where_clauses[0].pos); - push_generic_token(p, .Where, 1); - visit_exprs(p, v.where_clauses, true); - } + if v.poly_params != nil { + push_generic_token(p, .Open_Paren, 0); + visit_field_list(p, v.poly_params, true, false); + push_generic_token(p, .Close_Paren, 0); + } - if v.fields != nil && (len(v.fields.list) == 0 || v.pos.line == v.end.line) { - push_generic_token(p, .Open_Brace, 1); - set_source_position(p, v.fields.pos); - visit_field_list(p, v.fields, true); - push_generic_token(p, .Close_Brace, 0); - } else if v.fields != nil { - visit_begin_brace(p, v.pos, .Generic, len(v.fields.list)); - set_source_position(p, v.fields.pos); - visit_field_list(p, v.fields, true, true, true); - visit_end_brace(p, v.end); - } + if v.where_clauses != nil { + move_line(p, v.where_clauses[0].pos); + push_generic_token(p, .Where, 1); + visit_exprs(p, v.where_clauses, true); + } - set_source_position(p, v.end); - case Proc_Lit: + if v.fields != nil && (len(v.fields.list) == 0 || v.pos.line == v.end.line) { + push_generic_token(p, .Open_Brace, 1); + set_source_position(p, v.fields.pos); + visit_field_list(p, v.fields, true); + push_generic_token(p, .Close_Brace, 0); + } else if v.fields != nil { + visit_begin_brace(p, v.pos, .Generic, len(v.fields.list)); + set_source_position(p, v.fields.pos); + visit_field_list(p, v.fields, true, true, true); + visit_end_brace(p, v.end); + } - if v.inlining == .Inline { - push_ident_token(p, "#force_inline", 0); - } + set_source_position(p, v.end); + case Proc_Lit: - visit_proc_type(p, v.type^); + if v.inlining == .Inline { + push_ident_token(p, "#force_inline", 0); + } - if v.where_clauses != nil { - move_line(p, v.where_clauses[0].pos); - push_generic_token(p, .Where, 1); - visit_exprs(p, v.where_clauses, true); - } + visit_proc_type(p, v.type^); - if v.body != nil { - set_source_position(p, v.body.pos); - visit_stmt(p, v.body, .Proc); - } else { - push_generic_token(p, .Undef, 1); - } - case Proc_Type: - visit_proc_type(p, v); - case Basic_Lit: - push_generic_token(p, v.tok.kind, 1, v.tok.text); - case Binary_Expr: - visit_binary_expr(p, v); - case Implicit_Selector_Expr: - push_generic_token(p, .Period, 1); - push_ident_token(p, v.field.name, 0); - case Call_Expr: - visit_expr(p, v.expr); - push_generic_token(p, .Open_Paren, 0); - visit_call_exprs(p, v.args, v.ellipsis.kind == .Ellipsis); - push_generic_token(p, .Close_Paren, 0); - case Typeid_Type: - push_generic_token(p, .Typeid, 1); + if v.where_clauses != nil { + move_line(p, v.where_clauses[0].pos); + push_generic_token(p, .Where, 1); + visit_exprs(p, v.where_clauses, true); + } - if v.specialization != nil { - push_generic_token(p, .Quo, 0); - visit_expr(p, v.specialization); - } - case Selector_Expr: - visit_expr(p, v.expr); - push_generic_token(p, v.op.kind, 0); - visit_expr(p, v.field); - case Paren_Expr: - push_generic_token(p, .Open_Paren, 1); - visit_expr(p, v.expr); - push_generic_token(p, .Close_Paren, 0); - case Index_Expr: - visit_expr(p, v.expr); - push_generic_token(p, .Open_Bracket, 0); - visit_expr(p, v.index); - push_generic_token(p, .Close_Bracket, 0); - case Proc_Group: - - push_generic_token(p, v.tok.kind, 0); + if v.body != nil { + set_source_position(p, v.body.pos); + visit_stmt(p, v.body, .Proc); + } else { + push_generic_token(p, .Undef, 1); + } + case Proc_Type: + visit_proc_type(p, v); + case Basic_Lit: + push_generic_token(p, v.tok.kind, 1, v.tok.text); + case Binary_Expr: + visit_binary_expr(p, v); + case Implicit_Selector_Expr: + push_generic_token(p, .Period, 1); + push_ident_token(p, v.field.name, 0); + case Call_Expr: + visit_expr(p, v.expr); + push_generic_token(p, .Open_Paren, 0); + visit_call_exprs(p, v.args, v.ellipsis.kind == .Ellipsis); + push_generic_token(p, .Close_Paren, 0); + case Typeid_Type: + push_generic_token(p, .Typeid, 1); - if len(v.args) != 0 && v.pos.line != v.args[len(v.args) - 1].pos.line { - visit_begin_brace(p, v.pos, .Generic); - newline_position(p, 1); - set_source_position(p, v.args[0].pos); - visit_exprs(p, v.args, true, true); - visit_end_brace(p, v.end); - } else { - push_generic_token(p, .Open_Brace, 0); - visit_exprs(p, v.args, true); - push_generic_token(p, .Close_Brace, 0); - } - - case Comp_Lit: - - if v.type != nil { - visit_expr(p, v.type); - } + if v.specialization != nil { + push_generic_token(p, .Quo, 0); + visit_expr(p, v.specialization); + } + case Selector_Expr: + visit_expr(p, v.expr); + push_generic_token(p, v.op.kind, 0); + visit_expr(p, v.field); + case Paren_Expr: + push_generic_token(p, .Open_Paren, 1); + visit_expr(p, v.expr); + push_generic_token(p, .Close_Paren, 0); + case Index_Expr: + visit_expr(p, v.expr); + push_generic_token(p, .Open_Bracket, 0); + visit_expr(p, v.index); + push_generic_token(p, .Close_Bracket, 0); + case Proc_Group: - if len(v.elems) != 0 && v.pos.line != v.elems[len(v.elems) - 1].pos.line { - visit_begin_brace(p, v.pos, .Comp_Lit); - newline_position(p, 1); - set_source_position(p, v.elems[0].pos); - visit_exprs(p, v.elems, true, true); - visit_end_brace(p, v.end); - } else { - push_generic_token(p, .Open_Brace, 0); - visit_exprs(p, v.elems, true); - push_generic_token(p, .Close_Brace, 0); - } - - case Unary_Expr: - push_generic_token(p, v.op.kind, 1); - merge_next_token(p); - visit_expr(p, v.expr); - case Field_Value: - visit_expr(p, v.field); - push_generic_token(p, .Eq, 1); - visit_expr(p, v.value); - case Type_Assertion: - visit_expr(p, v.expr); + push_generic_token(p, v.tok.kind, 0); - if unary, ok := v.type.derived.(Unary_Expr); ok && unary.op.text == "?" { - push_generic_token(p, .Period, 0); - visit_expr(p, v.type); - } else { - push_generic_token(p, .Period, 0); - push_generic_token(p, .Open_Paren, 0); - visit_expr(p, v.type); - push_generic_token(p, .Close_Paren, 0); - } + if len(v.args) != 0 && v.pos.line != v.args[len(v.args) - 1].pos.line { + visit_begin_brace(p, v.pos, .Generic); + newline_position(p, 1); + set_source_position(p, v.args[0].pos); + visit_exprs(p, v.args, true, true); + visit_end_brace(p, v.end); + } else { + push_generic_token(p, .Open_Brace, 0); + visit_exprs(p, v.args, true); + push_generic_token(p, .Close_Brace, 0); + } - case Pointer_Type: - push_generic_token(p, .Pointer, 1); - merge_next_token(p); - visit_expr(p, v.elem); - case Implicit: - push_generic_token(p, v.tok.kind, 1); - case Poly_Type: - push_generic_token(p, .Dollar, 1); - merge_next_token(p); - visit_expr(p, v.type); + case Comp_Lit: - if v.specialization != nil { - push_generic_token(p, .Quo, 0); - merge_next_token(p); - visit_expr(p, v.specialization); - } - case Array_Type: - visit_expr(p, v.tag); - push_generic_token(p, .Open_Bracket, 1); - visit_expr(p, v.len); - push_generic_token(p, .Close_Bracket, 0); - visit_expr(p, v.elem); - case Map_Type: - push_generic_token(p, .Map, 1); - push_generic_token(p, .Open_Bracket, 0); - visit_expr(p, v.key); - push_generic_token(p, .Close_Bracket, 0); - visit_expr(p, v.value); - case Helper_Type: - visit_expr(p, v.type); - case: - panic(fmt.aprint(expr.derived)); - } + if v.type != nil { + visit_expr(p, v.type); + } + + if len(v.elems) != 0 && v.pos.line != v.elems[len(v.elems) - 1].pos.line { + visit_begin_brace(p, v.pos, .Comp_Lit); + newline_position(p, 1); + set_source_position(p, v.elems[0].pos); + visit_exprs(p, v.elems, true, true); + visit_end_brace(p, v.end); + } else { + push_generic_token(p, .Open_Brace, 0); + visit_exprs(p, v.elems, true); + push_generic_token(p, .Close_Brace, 0); + } + + case Unary_Expr: + push_generic_token(p, v.op.kind, 1); + merge_next_token(p); + visit_expr(p, v.expr); + case Field_Value: + visit_expr(p, v.field); + push_generic_token(p, .Eq, 1); + visit_expr(p, v.value); + case Type_Assertion: + visit_expr(p, v.expr); + + if unary, ok := v.type.derived.(Unary_Expr); ok && unary.op.text == "?" { + push_generic_token(p, .Period, 0); + visit_expr(p, v.type); + } else { + push_generic_token(p, .Period, 0); + push_generic_token(p, .Open_Paren, 0); + visit_expr(p, v.type); + push_generic_token(p, .Close_Paren, 0); + } + + case Pointer_Type: + push_generic_token(p, .Pointer, 1); + merge_next_token(p); + visit_expr(p, v.elem); + case Implicit: + push_generic_token(p, v.tok.kind, 1); + case Poly_Type: + push_generic_token(p, .Dollar, 1); + merge_next_token(p); + visit_expr(p, v.type); + + if v.specialization != nil { + push_generic_token(p, .Quo, 0); + merge_next_token(p); + visit_expr(p, v.specialization); + } + case Array_Type: + visit_expr(p, v.tag); + push_generic_token(p, .Open_Bracket, 1); + visit_expr(p, v.len); + push_generic_token(p, .Close_Bracket, 0); + visit_expr(p, v.elem); + case Map_Type: + push_generic_token(p, .Map, 1); + push_generic_token(p, .Open_Bracket, 0); + visit_expr(p, v.key); + push_generic_token(p, .Close_Bracket, 0); + visit_expr(p, v.value); + case Helper_Type: + visit_expr(p, v.type); + case: + panic(fmt.aprint(expr.derived)); + } } - visit_begin_brace :: proc(p: ^Printer, begin: tokenizer.Pos, type: Block_Type, count := 0) { - set_source_position(p, begin); + set_source_position(p, begin); - newline_braced := p.config.brace_style == .Allman; - newline_braced |= p.config.brace_style == .K_And_R && type == .Proc; - newline_braced &= p.config.brace_style != ._1TBS; + newline_braced := p.config.brace_style == .Allman; + 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 = "{", - }; + format_token := Format_Token { + kind = .Open_Brace, + parameter_count = count, + text = "{", + }; - if newline_braced { - newline_position(p, 1); - push_format_token(p, format_token); - indent(p); - } else { - format_token.spaces_before = 1; - push_format_token(p, format_token); - indent(p); - } + if newline_braced { + newline_position(p, 1); + push_format_token(p, format_token); + indent(p); + } else { + format_token.spaces_before = 1; + push_format_token(p, format_token); + indent(p); + } } visit_end_brace :: proc(p: ^Printer, end: tokenizer.Pos) { - set_source_position(p, end); - newline_position(p, 1); - push_generic_token(p, .Close_Brace, 0); - unindent(p); - p.current_line.depth = p.depth; + set_source_position(p, end); + newline_position(p, 1); + push_generic_token(p, .Close_Brace, 0); + unindent(p); + p.current_line.depth = p.depth; } -visit_block_stmts :: proc(p: ^Printer, stmts: []^ast.Stmt, split := false) { - for stmt, i in stmts { - visit_stmt(p, stmt, .Generic, false, true); +visit_block_stmts :: proc(p: ^Printer, stmts: [] ^ast.Stmt, split := false) { + for stmt, i in stmts { + visit_stmt(p, stmt, .Generic, false, true); - if split && i != len(stmts)-1 && stmt.pos.line == stmts[i+1].pos.line { - newline_position(p, 1); - } - } + if split && i != len(stmts) - 1 && stmt.pos.line == stmts[i + 1].pos.line { + newline_position(p, 1); + } + } } visit_field_list :: proc(p: ^Printer, list: ^ast.Field_List, add_comma := false, trailing := false, enforce_newline := false) { - if list.list == nil { - return; - } + if list.list == nil { + return; + } - for field, i in list.list { + for field, i in list.list { - if !move_line_limit(p, field.pos, 1) && enforce_newline { - newline_position(p, 1); - } + if !move_line_limit(p, field.pos, 1) && enforce_newline { + newline_position(p, 1); + } - if .Using in field.flags { - push_generic_token(p, .Using, 0); - } + if .Using in field.flags { + push_generic_token(p, .Using, 0); + } - visit_exprs(p, field.names, true); + visit_exprs(p, field.names, true); - if field.type != nil { - if len(field.names) != 0 { - push_generic_token(p, .Colon, 0); - } - visit_expr(p, field.type); - } else { - push_generic_token(p, .Colon, 1); - push_generic_token(p, .Eq, 0); - visit_expr(p, field.default_value); - } + if field.type != nil { + if len(field.names) != 0 { + push_generic_token(p, .Colon, 0); + } + visit_expr(p, field.type); + } else { + push_generic_token(p, .Colon, 1); + push_generic_token(p, .Eq, 0); + visit_expr(p, field.default_value); + } - if field.tag.text != "" { - push_generic_token(p, field.tag.kind, 1, field.tag.text); - } + if field.tag.text != "" { + push_generic_token(p, field.tag.kind, 1, field.tag.text); + } - if (i != len(list.list) - 1 || trailing) && add_comma { - push_generic_token(p, .Comma, 0); - } - } + if (i != len(list.list) - 1 || trailing) && add_comma { + push_generic_token(p, .Comma, 0); + } + } } visit_proc_type :: proc(p: ^Printer, proc_type: ast.Proc_Type) { - push_generic_token(p, .Proc, 1); + push_generic_token(p, .Proc, 1); - explicit_calling := false; + explicit_calling := false; - switch proc_type.calling_convention { - case .Odin: - case .Contextless: - push_string_token(p, "\"contextless\"", 1); - explicit_calling = true; - case .C_Decl: - push_string_token(p, "\"c\"", 1); - explicit_calling = true; - case .Std_Call: - push_string_token(p, "\"std\"", 1); - explicit_calling = true; - case .Fast_Call: - push_string_token(p, "\"fast\"", 1); - explicit_calling = true; - case .None: - //nothing i guess - case .Invalid: - //nothing i guess - case .Foreign_Block_Default: - } + switch proc_type.calling_convention { + case .Odin: + case .Contextless: + push_string_token(p, "\"contextless\"", 1); + explicit_calling = true; + case .C_Decl: + push_string_token(p, "\"c\"", 1); + explicit_calling = true; + case .Std_Call: + push_string_token(p, "\"std\"", 1); + explicit_calling = true; + case .Fast_Call: + push_string_token(p, "\"fast\"", 1); + explicit_calling = true; + case .None: + //nothing i guess + case .Invalid: + //nothing i guess + case .Foreign_Block_Default: + } - if explicit_calling { - push_generic_token(p, .Open_Paren, 1); - } else { - push_generic_token(p, .Open_Paren, 0); - } + if explicit_calling { + push_generic_token(p, .Open_Paren, 1); + } else { + push_generic_token(p, .Open_Paren, 0); + } - visit_signature_list(p, proc_type.params, false); + visit_signature_list(p, proc_type.params, false); - push_generic_token(p, .Close_Paren, 0); + push_generic_token(p, .Close_Paren, 0); - if proc_type.results != nil { - push_generic_token(p, .Sub, 1); - push_generic_token(p, .Gt, 0); + if proc_type.results != nil { + push_generic_token(p, .Sub, 1); + push_generic_token(p, .Gt, 0); - use_parens := false; - use_named := false; + use_parens := false; + use_named := false; - if len(proc_type.results.list) > 1 { - use_parens = true; - } else if len(proc_type.results.list) == 1 { + if len(proc_type.results.list) > 1 { + use_parens = true; + } else if len(proc_type.results.list) == 1 { - for name in proc_type.results.list[0].names { - if ident, ok := name.derived.(ast.Ident); ok { - if ident.name != "_" { - use_parens = true; - } - } - } - } + for name in proc_type.results.list[0].names { + if ident, ok := name.derived.(ast.Ident); ok { + if ident.name != "_" { + use_parens = true; + } + } + } + } - if use_parens { - push_generic_token(p, .Open_Paren, 1); - visit_signature_list(p, proc_type.results); - push_generic_token(p, .Close_Paren, 0); - } else { - visit_signature_list(p, proc_type.results); - } - } - + if use_parens { + push_generic_token(p, .Open_Paren, 1); + visit_signature_list(p, proc_type.results); + push_generic_token(p, .Close_Paren, 0); + } else { + visit_signature_list(p, proc_type.results); + } + } } visit_binary_expr :: proc(p: ^Printer, binary: ast.Binary_Expr) { - move_line(p, binary.left.pos); + move_line(p, binary.left.pos); - if v, ok := binary.left.derived.(ast.Binary_Expr); ok { - visit_binary_expr(p, v); - } else { - visit_expr(p, binary.left); - } + if v, ok := binary.left.derived.(ast.Binary_Expr); ok { + visit_binary_expr(p, v); + } else { + visit_expr(p, binary.left); + } - if binary.op.kind == .Ellipsis || binary.op.kind == .Range_Half { - push_generic_token(p, binary.op.kind, 0); - } else { - push_generic_token(p, binary.op.kind, 1); - } + if binary.op.kind == .Ellipsis || binary.op.kind == .Range_Half { + push_generic_token(p, binary.op.kind, 0); + } else { + push_generic_token(p, binary.op.kind, 1); + } - move_line(p, binary.right.pos); - - if v, ok := binary.right.derived.(ast.Binary_Expr); ok { - visit_binary_expr(p, v); - } else { - visit_expr(p, binary.right); - } + move_line(p, binary.right.pos); + if v, ok := binary.right.derived.(ast.Binary_Expr); ok { + visit_binary_expr(p, v); + } else { + visit_expr(p, binary.right); + } } -visit_call_exprs :: proc(p: ^Printer, list: []^ast.Expr, ellipsis := false) { +visit_call_exprs :: proc(p: ^Printer, list: [] ^ast.Expr, ellipsis := false) { - if len(list) == 0 { - return; - } + if len(list) == 0 { + return; + } - //all the expression are on the line - if list[0].pos.line == list[len(list) - 1].pos.line { - for expr, i in list { + //all the expression are on the line + if list[0].pos.line == list[len(list) - 1].pos.line { + for expr, i in list { - if i == len(list) - 1 && ellipsis { - push_generic_token(p, .Ellipsis, 0); - } + if i == len(list) - 1 && ellipsis { + push_generic_token(p, .Ellipsis, 0); + } - visit_expr(p, expr); + visit_expr(p, expr); - if i != len(list) - 1 { - push_generic_token(p, .Comma, 0); - } - } - } else { - for expr, i in list { + if i != len(list) - 1 { + push_generic_token(p, .Comma, 0); + } + } + } else { + for expr, i in list { - //we have to newline the expressions to respect the source - move_line_limit(p, expr.pos, 1); - + //we have to newline the expressions to respect the source + move_line_limit(p, expr.pos, 1); - if i == len(list) - 1 && ellipsis { - push_generic_token(p, .Ellipsis, 0); - } + if i == len(list) - 1 && ellipsis { + push_generic_token(p, .Ellipsis, 0); + } - visit_expr(p, expr); + visit_expr(p, expr); - if i != len(list) - 1 { - push_generic_token(p, .Comma, 0); - } - } - } + if i != len(list) - 1 { + push_generic_token(p, .Comma, 0); + } + } + } } - visit_signature_list :: proc(p: ^Printer, list: ^ast.Field_List, remove_blank := true) { - if list.list == nil { - return; - } + if list.list == nil { + return; + } - for field, i in list.list { + for field, i in list.list { - move_line_limit(p, field.pos, 1); + move_line_limit(p, field.pos, 1); - if .Using in field.flags { - push_generic_token(p, .Using, 0); - } + if .Using in field.flags { + push_generic_token(p, .Using, 0); + } - named := false; + named := false; - for name in field.names { - if ident, ok := name.derived.(ast.Ident); ok { - //for some reason the parser uses _ to mean empty - if ident.name != "_" || !remove_blank { - named = true; - } - } else { - //alternative is poly names - named = true; - } - } + for name in field.names { + if ident, ok := name.derived.(ast.Ident); ok { + //for some reason the parser uses _ to mean empty + if ident.name != "_" || !remove_blank { + named = true; + } + } else { + //alternative is poly names + named = true; + } + } - if named { - visit_exprs(p, field.names, true); + if named { + visit_exprs(p, field.names, true); - if len(field.names) != 0 && field.type != nil { - push_generic_token(p, .Colon, 0); - } - } + if len(field.names) != 0 && field.type != nil { + push_generic_token(p, .Colon, 0); + } + } - if field.type != nil && field.default_value != nil { - visit_expr(p, field.type); - push_generic_token(p, .Eq, 0); - visit_expr(p, field.default_value); - } else if field.type != nil { - visit_expr(p, field.type); - } else { - push_generic_token(p, .Colon, 1); - push_generic_token(p, .Eq, 0); - visit_expr(p, field.default_value); - } - - if i != len(list.list) - 1 { - push_generic_token(p, .Comma, 0); - } - } -} + if field.type != nil && field.default_value != nil { + visit_expr(p, field.type); + push_generic_token(p, .Eq, 1); + visit_expr(p, field.default_value); + } else if field.type != nil { + visit_expr(p, field.type); + } else { + push_generic_token(p, .Colon, 1); + push_generic_token(p, .Eq, 0); + visit_expr(p, field.default_value); + } + if i != len(list.list) - 1 { + push_generic_token(p, .Comma, 0); + } + } +} \ No newline at end of file From a12db382e05cbd3ea05df05c06f8dd15de8b8b65 Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Thu, 15 Apr 2021 00:24:00 +0200 Subject: [PATCH 22/49] damn, ran the odinfmt with spaces instead of tabs... --- core/odin/printer/printer.odin | 640 +++++----- core/odin/printer/visit.odin | 2120 ++++++++++++++++---------------- 2 files changed, 1380 insertions(+), 1380 deletions(-) diff --git a/core/odin/printer/printer.odin b/core/odin/printer/printer.odin index 4d8539dfa..3db48662c 100644 --- a/core/odin/printer/printer.odin +++ b/core/odin/printer/printer.odin @@ -13,184 +13,184 @@ Line_Type_Enum :: enum {Line_Comment, Value_Decl, Switch_Stmt, Struct} Line_Type :: bit_set[Line_Type_Enum]; Line :: struct { - format_tokens: [dynamic] Format_Token, - finalized: bool, - used: bool, - depth: int, - types: Line_Type, //for performance, so you don't have to verify what types are in it by going through the tokens - might give problems when adding linebreaking + format_tokens: [dynamic] Format_Token, + finalized: bool, + used: bool, + depth: int, + types: Line_Type, //for performance, so you don't have to verify what types are in it by going through the tokens - might give problems when adding linebreaking } Format_Token :: struct { - kind: tokenizer.Token_Kind, - text: string, - spaces_before: int, - parameter_count: int, + kind: tokenizer.Token_Kind, + text: string, + spaces_before: int, + parameter_count: int, } Printer :: struct { - string_builder: strings.Builder, - config: Config, - depth: int, //the identation depth - comments: [dynamic] ^ast.Comment_Group, - latest_comment_index: int, - allocator: mem.Allocator, - file: ^ast.File, - source_position: tokenizer.Pos, - last_source_position: tokenizer.Pos, - 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, - last_line_index: int, - last_token: ^Format_Token, - merge_next_token: bool, - space_next_token: bool, - debug: bool, + string_builder: strings.Builder, + config: Config, + depth: int, //the identation depth + comments: [dynamic] ^ast.Comment_Group, + latest_comment_index: int, + allocator: mem.Allocator, + file: ^ast.File, + source_position: tokenizer.Pos, + last_source_position: tokenizer.Pos, + 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, + last_line_index: int, + last_token: ^Format_Token, + merge_next_token: bool, + space_next_token: bool, + debug: bool, } Config :: struct { - spaces: int, //Spaces per indentation - newline_limit: int, //The limit of newlines between statements and declarations. - tabs: bool, //Enable or disable tabs - convert_do: bool, //Convert all do statements to brace blocks - semicolons: bool, //Enable semicolons - split_multiple_stmts: bool, - align_switch: bool, - brace_style: Brace_Style, - align_assignments: bool, - align_structs: bool, - align_style: Alignment_Style, - indent_cases: bool, - newline_style: Newline_Style, + spaces: int, //Spaces per indentation + newline_limit: int, //The limit of newlines between statements and declarations. + tabs: bool, //Enable or disable tabs + convert_do: bool, //Convert all do statements to brace blocks + semicolons: bool, //Enable semicolons + split_multiple_stmts: bool, + align_switch: bool, + brace_style: Brace_Style, + align_assignments: bool, + align_structs: bool, + align_style: Alignment_Style, + indent_cases: bool, + newline_style: Newline_Style, } Brace_Style :: enum { - _1TBS, - Allman, - Stroustrup, - K_And_R, + _1TBS, + Allman, + Stroustrup, + K_And_R, } Block_Type :: enum { - None, - If_Stmt, - Proc, - Generic, - Comp_Lit, - Switch_Stmt, + None, + If_Stmt, + Proc, + Generic, + Comp_Lit, + Switch_Stmt, } Alignment_Style :: enum { - Align_On_Colon_And_Equals, - Align_On_Type_And_Equals, + Align_On_Colon_And_Equals, + Align_On_Type_And_Equals, } Newline_Style :: enum { - CRLF, - LF, + CRLF, + LF, } default_style := Config { - spaces = 4, - newline_limit = 2, - convert_do = false, - semicolons = true, - tabs = false, - brace_style = ._1TBS, - split_multiple_stmts = true, - align_assignments = true, - align_style = .Align_On_Type_And_Equals, - indent_cases = false, - align_switch = true, - align_structs = true, - newline_style = .CRLF, + spaces = 4, + newline_limit = 2, + convert_do = false, + semicolons = true, + tabs = true, + brace_style = ._1TBS, + split_multiple_stmts = true, + align_assignments = true, + align_style = .Align_On_Type_And_Equals, + indent_cases = false, + align_switch = true, + align_structs = true, + newline_style = .CRLF, }; make_printer :: proc(config: Config, allocator := context.allocator) -> Printer { - return { - config = config, - allocator = allocator, - debug = false, - }; + return { + config = config, + allocator = allocator, + debug = false, + }; } print :: proc(p: ^Printer, file: ^ast.File) -> string { - p.comments = file.comments; + 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); - } + 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); + set_line(p, 0); - push_generic_token(p, .Package, 0); - push_ident_token(p, file.pkg_name, 1); + 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); - } + for decl in file.decls { + visit_decl(p, cast(^ast.Decl)decl); + } - if len(p.comments) > 0 { - infinite := p.comments[len(p.comments) - 1].end; - infinite.offset = 9999999; - push_comments(p, infinite); - } + if len(p.comments) > 0 { + infinite := p.comments[len(p.comments) - 1].end; + infinite.offset = 9999999; + push_comments(p, infinite); + } - fix_lines(p); + fix_lines(p); - builder := strings.make_builder(0, mem.megabytes(5), p.allocator); + builder := strings.make_builder(0, mem.megabytes(5), p.allocator); - last_line := 0; + last_line := 0; - newline: string; + newline: string; - if p.config.newline_style == .LF { - newline = "\n"; - } else { - newline = "\r\n"; - } + 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 line, line_index in p.lines { + diff_line := line_index - last_line; - for i := 0; i < diff_line; i += 1 { - strings.write_string(&builder, newline); - } + 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'); - } - } else { - for i := 0; i < line.depth * p.config.spaces; 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: ", line_index)); - } + if p.debug { + strings.write_string(&builder, fmt.tprintf("line %v: ", line_index)); + } - for format_token in line.format_tokens { + for format_token in line.format_tokens { - for i := 0; i < format_token.spaces_before; i += 1 { - strings.write_byte(&builder, ' '); - } + for i := 0; i < format_token.spaces_before; i += 1 { + strings.write_byte(&builder, ' '); + } - strings.write_string(&builder, format_token.text); - } + strings.write_string(&builder, format_token.text); + } - last_line = line_index; - } + last_line = line_index; + } - return strings.to_string(builder); + return strings.to_string(builder); } fix_lines :: proc(p: ^Printer) { - align_var_decls(p); - align_blocks(p); - align_comments(p); //align them last since they rely on the other alignments + 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) { @@ -198,277 +198,277 @@ align_var_decls :: proc(p: ^Printer) { align_switch_smt :: proc(p: ^Printer, index: int) { - switch_found := false; - brace_token: Format_Token; - brace_line: int; + switch_found := false; + brace_token: Format_Token; + brace_line: int; - found_switch_brace: for line, line_index in p.lines[index:] { + found_switch_brace: for line, line_index in p.lines[index:] { - for format_token in line.format_tokens { + for format_token in line.format_tokens { - if format_token.kind == .Open_Brace && switch_found { - brace_token = format_token; - brace_line = line_index + index; - break found_switch_brace; - } else if format_token.kind == .Open_Brace { - break; - } else if format_token.kind == .Switch { - switch_found = true; - } - } - } + if format_token.kind == .Open_Brace && switch_found { + brace_token = format_token; + brace_line = line_index + 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; - } + if !switch_found { + return; + } - largest := 0; - case_count := 0; + largest := 0; + case_count := 0; - //find all the switch cases that are one lined - for line, line_index in p.lines[brace_line + 1:] { + //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; + case_found := false; + colon_found := false; + length := 0; - for format_token in line.format_tokens { + for format_token in line.format_tokens { - if format_token.kind == .Comment { - continue; - } + 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; - } + //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; - case_count += 1; - } else if format_token.kind == .Colon { - colon_found = true; - } + if format_token.kind == .Case { + case_found = true; + case_count += 1; + } else if format_token.kind == .Colon { + colon_found = true; + } - length += len(format_token.text) + format_token.spaces_before; - } + length += len(format_token.text) + format_token.spaces_before; + } - if case_count >= brace_token.parameter_count { - break; - } - } + if case_count >= brace_token.parameter_count { + break; + } + } - case_count = 0; + case_count = 0; - for line, line_index in p.lines[brace_line + 1:] { + for line, line_index in p.lines[brace_line + 1:] { - case_found := false; - colon_found := false; - length := 0; + case_found := false; + colon_found := false; + length := 0; - for format_token, i in line.format_tokens { + for format_token, i in line.format_tokens { - if format_token.kind == .Comment { - continue; - } + 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; - } + //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; - case_count += 1; - } else if format_token.kind == .Colon { - colon_found = true; - } + if format_token.kind == .Case { + case_found = true; + case_count += 1; + } else if format_token.kind == .Colon { + colon_found = true; + } - length += len(format_token.text) + format_token.spaces_before; - } + length += len(format_token.text) + format_token.spaces_before; + } - if case_count >= brace_token.parameter_count { - break; - } - } + if case_count >= brace_token.parameter_count { + break; + } + } } align_struct :: proc(p: ^Printer, index: int) { - struct_found := false; - brace_token: Format_Token; - brace_line: int; + struct_found := false; + brace_token: Format_Token; + brace_line: int; - found_struct_brace: for line, line_index in p.lines[index:] { + found_struct_brace: for line, line_index in p.lines[index:] { - for format_token in line.format_tokens { + for format_token in line.format_tokens { - if format_token.kind == .Open_Brace && struct_found { - brace_token = format_token; - brace_line = line_index + index; - break found_struct_brace; - } else if format_token.kind == .Open_Brace { - break; - } else if format_token.kind == .Struct { - struct_found = true; - } - } - } + if format_token.kind == .Open_Brace && struct_found { + brace_token = format_token; + brace_line = line_index + index; + break found_struct_brace; + } else if format_token.kind == .Open_Brace { + break; + } else if format_token.kind == .Struct { + struct_found = true; + } + } + } - if !struct_found { - return; - } + if !struct_found { + return; + } - largest := 0; - colon_count := 0; + largest := 0; + colon_count := 0; - for line, line_index in p.lines[brace_line + 1:] { + for line, line_index in p.lines[brace_line + 1:] { - length := 0; + length := 0; - for format_token in line.format_tokens { + for format_token in line.format_tokens { - if format_token.kind == .Comment { - continue; - } + if format_token.kind == .Comment { + continue; + } - if format_token.kind == .Colon { - colon_count += 1; - largest = max(length, largest); - break; - } + if format_token.kind == .Colon { + colon_count += 1; + largest = max(length, largest); + break; + } - length += len(format_token.text) + format_token.spaces_before; - } + length += len(format_token.text) + format_token.spaces_before; + } - if colon_count >= brace_token.parameter_count { - break; - } - } + if colon_count >= brace_token.parameter_count { + break; + } + } - colon_count = 0; + colon_count = 0; - for line, line_index in p.lines[brace_line + 1:] { + for line, line_index in p.lines[brace_line + 1:] { - length := 0; + length := 0; - for format_token, i in line.format_tokens { + for format_token, i in line.format_tokens { - if format_token.kind == .Comment { - continue; - } + if format_token.kind == .Comment { + continue; + } - if format_token.kind == .Colon { - colon_count += 1; - line.format_tokens[i + 1].spaces_before = largest - length + 1; - break; - } + if format_token.kind == .Colon { + colon_count += 1; + line.format_tokens[i + 1].spaces_before = largest - length + 1; + break; + } - length += len(format_token.text) + format_token.spaces_before; - } + length += len(format_token.text) + format_token.spaces_before; + } - if colon_count >= brace_token.parameter_count { - break; - } - } + if colon_count >= brace_token.parameter_count { + break; + } + } } align_blocks :: proc(p: ^Printer) { - for line, line_index in p.lines { + for line, line_index in p.lines { - if len(line.format_tokens) <= 0 { - continue; - } + if len(line.format_tokens) <= 0 { + continue; + } - if .Switch_Stmt in line.types && p.config.align_switch { - align_switch_smt(p, line_index); - } + if .Switch_Stmt in line.types && p.config.align_switch { + align_switch_smt(p, line_index); + } - if .Struct in line.types && p.config.align_structs { - align_struct(p, line_index); - } - } + if .Struct in line.types && p.config.align_structs { + align_struct(p, line_index); + } + } } align_comments :: proc(p: ^Printer) { - Comment_Align_Info :: struct { - length: int, - begin: int, - end: int, - depth: int, - }; + Comment_Align_Info :: struct { + length: int, + begin: int, + end: int, + depth: int, + }; - comment_infos := make([dynamic] Comment_Align_Info, 0, context.temp_allocator); + comment_infos := make([dynamic] Comment_Align_Info, 0, context.temp_allocator); - current_info: Comment_Align_Info; + current_info: Comment_Align_Info; - for line, line_index in p.lines { + for line, line_index in p.lines { - if len(line.format_tokens) <= 0 { - continue; - } + if len(line.format_tokens) <= 0 { + continue; + } - if .Line_Comment in line.types { + if .Line_Comment in line.types { - if current_info.end + 1 != line_index || current_info.depth != line.depth || - (current_info.begin == current_info.end && current_info.length == 0) { + if current_info.end + 1 != line_index || current_info.depth != line.depth || + (current_info.begin == current_info.end && current_info.length == 0) { - if (current_info.begin != 0 && current_info.end != 0) || current_info.length > 0 { - append(&comment_infos, current_info); - } + 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.depth = line.depth; - current_info.length = 0; - } + current_info.begin = line_index; + current_info.end = line_index; + current_info.depth = line.depth; + current_info.length = 0; + } - length := 0; + length := 0; - for format_token, i in line.format_tokens { + 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; - } + 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); - } - } - } + 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); - } + if (current_info.begin != 0 && current_info.end != 0) || current_info.length > 0 { + append(&comment_infos, current_info); + } - for info in comment_infos { + for info in comment_infos { - if info.begin == info.end || info.length == 0 { - continue; - } + if info.begin == info.end || info.length == 0 { + continue; + } - for i := info.begin; i <= info.end; i += 1 { + for i := info.begin; i <= info.end; i += 1 { - l := p.lines[i]; + l := p.lines[i]; - length := 0; + length := 0; - for format_token, i in l.format_tokens { + 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; - } - } + 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); - } - } - } + 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 7cc856e3b..ae3097f03 100644 --- a/core/odin/printer/visit.odin +++ b/core/odin/printer/visit.odin @@ -12,1453 +12,1453 @@ 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 { - 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) comment_before_position :: proc(p: ^Printer, pos: tokenizer.Pos) -> bool { - if len(p.comments) <= p.latest_comment_index { - return false; - } + if len(p.comments) <= p.latest_comment_index { + return false; + } - comment := p.comments[p.latest_comment_index]; + comment := p.comments[p.latest_comment_index]; - return comment.pos.offset < pos.offset; + return comment.pos.offset < pos.offset; } @(private) next_comment_group :: proc(p: ^Printer) { - p.latest_comment_index += 1; + p.latest_comment_index += 1; } @(private) push_comment :: proc(p: ^Printer, comment: tokenizer.Token) -> int { - if len(comment.text) == 0 { - return 0; - } + if len(comment.text) == 0 { + return 0; + } - if comment.text[0] == '/' && comment.text[1] == '/' { - format_token := Format_Token { - spaces_before = 1, - kind = .Comment, - text = comment.text, - }; + if comment.text[0] == '/' && comment.text[1] == '/' { + format_token := Format_Token { + spaces_before = 1, + kind = .Comment, + text = comment.text, + }; - if len(p.current_line.format_tokens) == 0 { - format_token.spaces_before = 0; - } + if len(p.current_line.format_tokens) == 0 { + format_token.spaces_before = 0; + } - if !p.current_line.used { - p.current_line.used = true; - p.current_line.depth = p.depth; - } + if !p.current_line.used { + p.current_line.used = true; + p.current_line.depth = p.depth; + } - append(&p.current_line.format_tokens, format_token); - p.last_token = &p.current_line.format_tokens[len(p.current_line.format_tokens) - 1]; + 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}); + hint_current_line(p,{.Line_Comment}); - return 0; - } else { + return 0; + } else { - builder := strings.make_builder(context.temp_allocator); + builder := strings.make_builder(context.temp_allocator); - c_len := len(comment.text); - trim_space := true; + c_len := len(comment.text); + trim_space := true; - multilines: [dynamic] string; + multilines: [dynamic] string; - for i := 0; i < len(comment.text); i += 1 { + for i := 0; i < len(comment.text); i += 1 { - c := comment.text[i]; + c := comment.text[i]; - if c != ' ' && c != '\t' { - trim_space = false; - } + if c != ' ' && c != '\t' { + trim_space = false; + } - if (c == ' ' || c == '\t' || c == '\n') && trim_space { - continue; - } else if c == 13 && comment.text[min(c_len - 1, i + 1)] == 10 { - append(&multilines, strings.to_string(builder)); - builder = strings.make_builder(context.temp_allocator); - trim_space = true; - i += 1; - } else if c == 10 { - append(&multilines, strings.to_string(builder)); - builder = strings.make_builder(context.temp_allocator); - trim_space = true; - } else if c == '/' && comment.text[min(c_len - 1, i + 1)] == '*' { - strings.write_string(&builder, "/*"); - trim_space = true; - p.depth += 1; - i += 1; - } else if c == '*' && comment.text[min(c_len - 1, i + 1)] == '/' { - p.depth -= 1; - trim_space = true; - strings.write_string(&builder, "*/"); - i += 1; - } else { - strings.write_byte(&builder, c); - } - } + if (c == ' ' || c == '\t' || c == '\n') && trim_space { + continue; + } else if c == 13 && comment.text[min(c_len - 1, i + 1)] == 10 { + append(&multilines, strings.to_string(builder)); + builder = strings.make_builder(context.temp_allocator); + trim_space = true; + i += 1; + } else if c == 10 { + append(&multilines, strings.to_string(builder)); + builder = strings.make_builder(context.temp_allocator); + trim_space = true; + } else if c == '/' && comment.text[min(c_len - 1, i + 1)] == '*' { + strings.write_string(&builder, "/*"); + trim_space = true; + p.depth += 1; + i += 1; + } else if c == '*' && comment.text[min(c_len - 1, i + 1)] == '/' { + p.depth -= 1; + trim_space = true; + strings.write_string(&builder, "*/"); + i += 1; + } else { + strings.write_byte(&builder, c); + } + } - if strings.builder_len(builder) > 0 { - append(&multilines, strings.to_string(builder)); - } + if strings.builder_len(builder) > 0 { + append(&multilines, strings.to_string(builder)); + } - for line in multilines { - format_token := Format_Token { - spaces_before = 1, - kind = .Comment, - text = line, - }; + for line in multilines { + format_token := Format_Token { + spaces_before = 1, + kind = .Comment, + text = line, + }; - if len(p.current_line.format_tokens) == 0 { - format_token.spaces_before = 0; - } + if len(p.current_line.format_tokens) == 0 { + format_token.spaces_before = 0; + } - if strings.contains(line, "*/") { - unindent(p); - } + if strings.contains(line, "*/") { + unindent(p); + } - if !p.current_line.used { - p.current_line.used = true; - p.current_line.depth = p.depth; - } + if !p.current_line.used { + p.current_line.used = true; + p.current_line.depth = p.depth; + } - append(&p.current_line.format_tokens, format_token); - p.last_token = &p.current_line.format_tokens[len(p.current_line.format_tokens) - 1]; + append(&p.current_line.format_tokens, format_token); + p.last_token = &p.current_line.format_tokens[len(p.current_line.format_tokens) - 1]; - if strings.contains(line, "/*") { - indent(p); - } + if strings.contains(line, "/*") { + indent(p); + } - newline_position(p, 1); - } + newline_position(p, 1); + } - return len(multilines); - } + return len(multilines); + } } @(private) push_comments :: proc(p: ^Printer, pos: tokenizer.Pos) { - prev_comment: ^tokenizer.Token; - prev_comment_lines: int; + prev_comment: ^tokenizer.Token; + prev_comment_lines: int; - for comment_before_position(p, pos) { + for comment_before_position(p, pos) { - comment_group := p.comments[p.latest_comment_index]; + comment_group := p.comments[p.latest_comment_index]; - if prev_comment == nil { - lines := comment_group.pos.line - p.last_source_position.line; - set_line(p, p.last_line_index + min(p.config.newline_limit, lines)); - } + if prev_comment == nil { + lines := comment_group.pos.line - p.last_source_position.line; + set_line(p, p.last_line_index + min(p.config.newline_limit, lines)); + } - for comment, i in comment_group.list { + for comment, i in comment_group.list { - if prev_comment != nil && p.last_source_position.line != comment.pos.line { - newline_position(p, min(p.config.newline_limit, comment.pos.line - prev_comment.pos.line - prev_comment_lines)); - } + if prev_comment != nil && p.last_source_position.line != comment.pos.line { + newline_position(p, min(p.config.newline_limit, comment.pos.line - prev_comment.pos.line - prev_comment_lines)); + } - prev_comment_lines = push_comment(p, comment); - prev_comment = &comment_group.list[i]; - } + prev_comment_lines = push_comment(p, comment); + prev_comment = &comment_group.list[i]; + } - next_comment_group(p); - } + next_comment_group(p); + } - if prev_comment != nil { - newline_position(p, min(p.config.newline_limit, p.source_position.line - prev_comment.pos.line)); - } + if prev_comment != nil { + newline_position(p, min(p.config.newline_limit, p.source_position.line - prev_comment.pos.line)); + } } @(private) append_format_token :: proc(p: ^Printer, format_token: Format_Token) -> ^Format_Token { - format_token := format_token; + format_token := format_token; - if p.last_token != nil && (p.last_token.kind == .Ellipsis || p.last_token.kind == .Range_Half || - p.last_token.kind == .Open_Paren || p.last_token.kind == .Period || - p.last_token.kind == .Open_Brace || p.last_token.kind == .Open_Bracket) { - format_token.spaces_before = 0; - } else if p.merge_next_token { - format_token.spaces_before = 0; - p.merge_next_token = false; - } else if p.space_next_token { - format_token.spaces_before = 1; - p.space_next_token = false; - } + if p.last_token != nil && (p.last_token.kind == .Ellipsis || p.last_token.kind == .Range_Half || + p.last_token.kind == .Open_Paren || p.last_token.kind == .Period || + p.last_token.kind == .Open_Brace || p.last_token.kind == .Open_Bracket) { + format_token.spaces_before = 0; + } else if p.merge_next_token { + format_token.spaces_before = 0; + p.merge_next_token = false; + } else if p.space_next_token { + format_token.spaces_before = 1; + p.space_next_token = false; + } - push_comments(p, p.source_position); + push_comments(p, p.source_position); - unwrapped_line := p.current_line; + unwrapped_line := p.current_line; - if !unwrapped_line.used { - 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; - } + if len(unwrapped_line.format_tokens) == 0 && format_token.spaces_before == 1 { + format_token.spaces_before = 0; + } - p.last_source_position = p.source_position; - p.last_line_index = p.current_line_index; + p.last_source_position = p.source_position; + p.last_line_index = p.current_line_index; - append(&unwrapped_line.format_tokens, format_token); - return &unwrapped_line.format_tokens[len(unwrapped_line.format_tokens) - 1]; + append(&unwrapped_line.format_tokens, format_token); + 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); + p.last_token = append_format_token(p, format_token); } @(private) push_generic_token :: proc(p: ^Printer, kind: tokenizer.Token_Kind, spaces_before: int, value := "") { - format_token := Format_Token { - spaces_before = spaces_before, - kind = kind, - text = tokenizer.tokens[kind], - }; + format_token := Format_Token { + spaces_before = spaces_before, + kind = kind, + text = tokenizer.tokens[kind], + }; - if value != "" { - format_token.text = value; - } + if value != "" { + format_token.text = value; + } - p.last_token = append_format_token(p, format_token); + p.last_token = append_format_token(p, format_token); } @(private) push_string_token :: proc(p: ^Printer, text: string, spaces_before: int) { - format_token := Format_Token { - spaces_before = spaces_before, - kind = .String, - text = text, - }; + format_token := Format_Token { + spaces_before = spaces_before, + kind = .String, + text = text, + }; - p.last_token = append_format_token(p, format_token); + p.last_token = append_format_token(p, format_token); } @(private) push_ident_token :: proc(p: ^Printer, text: string, spaces_before: int) { - format_token := Format_Token { - spaces_before = spaces_before, - kind = .Ident, - text = text, - }; + format_token := Format_Token { + spaces_before = spaces_before, + kind = .Ident, + text = text, + }; - p.last_token = append_format_token(p, format_token); + p.last_token = append_format_token(p, format_token); } @(private) set_source_position :: proc(p: ^Printer, pos: tokenizer.Pos) { - p.source_position = pos; + p.source_position = pos; } @(private) move_line :: proc(p: ^Printer, pos: tokenizer.Pos) { - move_line_limit(p, pos, p.config.newline_limit); + move_line_limit(p, pos, p.config.newline_limit); } @(private) move_line_limit :: proc(p: ^Printer, pos: tokenizer.Pos, limit: int) -> bool { - lines := min(pos.line - p.source_position.line, limit); + lines := min(pos.line - p.source_position.line, limit); - if lines < 0 { - return false; - } + if lines < 0 { + return false; + } - p.source_position = pos; - p.current_line_index += lines; - set_line(p, p.current_line_index); - return lines > 0; + p.source_position = pos; + p.current_line_index += lines; + set_line(p, p.current_line_index); + return lines > 0; } @(private) set_line :: proc(p: ^Printer, line: int) -> ^Line { - unwrapped_line: ^Line; + unwrapped_line: ^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]; - } + 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]; + } - p.current_line = unwrapped_line; - p.current_line_index = line; + p.current_line = unwrapped_line; + p.current_line_index = line; - return unwrapped_line; + return unwrapped_line; } @(private) newline_position :: proc(p: ^Printer, count: int) { - p.current_line_index += count; - set_line(p, p.current_line_index); + p.current_line_index += count; + set_line(p, p.current_line_index); } @(private) indent :: proc(p: ^Printer) { - p.depth += 1; + p.depth += 1; } @(private) unindent :: proc(p: ^Printer) { - p.depth -= 1; + p.depth -= 1; } @(private) merge_next_token :: proc(p: ^Printer) { - p.merge_next_token = true; + p.merge_next_token = true; } @(private) space_next_token :: proc(p: ^Printer) { - p.space_next_token = true; + p.space_next_token = true; } @(private) hint_current_line :: proc(p: ^Printer, hint: Line_Type) { - p.current_line.types |= hint; + p.current_line.types |= hint; } @(private) visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) { - using ast; + using ast; - if decl == nil { - return; - } + if decl == nil { + return; + } - switch v in &decl.derived { - case Expr_Stmt: - move_line(p, decl.pos); - visit_expr(p, v.expr); - if p.config.semicolons { - push_generic_token(p, .Semicolon, 0); - } - case When_Stmt: - visit_stmt(p, cast(^Stmt)decl); - case Foreign_Import_Decl: - if len(v.attributes) > 0 { - sort.sort(sort_attribute(&v.attributes)); - move_line(p, v.attributes[0].pos); - visit_attributes(p, v.attributes); - } + switch v in &decl.derived { + case Expr_Stmt: + move_line(p, decl.pos); + visit_expr(p, v.expr); + if p.config.semicolons { + push_generic_token(p, .Semicolon, 0); + } + case When_Stmt: + visit_stmt(p, cast(^Stmt)decl); + case Foreign_Import_Decl: + if len(v.attributes) > 0 { + sort.sort(sort_attribute(&v.attributes)); + move_line(p, v.attributes[0].pos); + visit_attributes(p, v.attributes); + } - move_line(p, decl.pos); + move_line(p, decl.pos); - push_generic_token(p, v.foreign_tok.kind, 0); - push_generic_token(p, v.import_tok.kind, 1); + push_generic_token(p, v.foreign_tok.kind, 0); + push_generic_token(p, v.import_tok.kind, 1); - if v.name != nil { - push_ident_token(p, v.name.name, 1); - } + if v.name != nil { + push_ident_token(p, v.name.name, 1); + } - for path in v.fullpaths { - push_ident_token(p, path, 0); - } - case Foreign_Block_Decl: + for path in v.fullpaths { + push_ident_token(p, path, 0); + } + case Foreign_Block_Decl: - if len(v.attributes) > 0 { - sort.sort(sort_attribute(&v.attributes)); - move_line(p, v.attributes[0].pos); - visit_attributes(p, v.attributes); - } + if len(v.attributes) > 0 { + sort.sort(sort_attribute(&v.attributes)); + move_line(p, v.attributes[0].pos); + visit_attributes(p, v.attributes); + } - move_line(p, decl.pos); + move_line(p, decl.pos); - push_generic_token(p, .Foreign, 0); + push_generic_token(p, .Foreign, 0); - visit_expr(p, v.foreign_library); - visit_stmt(p, v.body); - case Import_Decl: - move_line(p, decl.pos); + visit_expr(p, v.foreign_library); + visit_stmt(p, v.body); + case Import_Decl: + move_line(p, decl.pos); - if v.name.text != "" { - push_generic_token(p, v.import_tok.kind, 1); - push_generic_token(p, v.name.kind, 1, v.name.text); - push_ident_token(p, v.fullpath, 1); - } else { - push_generic_token(p, v.import_tok.kind, 1); - push_ident_token(p, v.fullpath, 1); - } + if v.name.text != "" { + push_generic_token(p, v.import_tok.kind, 1); + push_generic_token(p, v.name.kind, 1, v.name.text); + push_ident_token(p, v.fullpath, 1); + } else { + push_generic_token(p, v.import_tok.kind, 1); + push_ident_token(p, v.fullpath, 1); + } - case Value_Decl: - if len(v.attributes) > 0 { - sort.sort(sort_attribute(&v.attributes)); - move_line(p, v.attributes[0].pos); - visit_attributes(p, v.attributes); - } + case Value_Decl: + if len(v.attributes) > 0 { + sort.sort(sort_attribute(&v.attributes)); + move_line(p, v.attributes[0].pos); + visit_attributes(p, v.attributes); + } - move_line(p, decl.pos); + move_line(p, decl.pos); - if v.is_using { - push_generic_token(p, .Using, 0); - } + if v.is_using { + push_generic_token(p, .Using, 0); + } - visit_exprs(p, v.names, true); + visit_exprs(p, v.names, true); - if v.type != nil { - if !v.is_mutable && v.type != nil { - push_generic_token(p, .Colon, 0); - } else { - push_generic_token(p, .Colon, 0); - } + if v.type != nil { + if !v.is_mutable && v.type != nil { + push_generic_token(p, .Colon, 0); + } else { + push_generic_token(p, .Colon, 0); + } - visit_expr(p, v.type); - } else { - if !v.is_mutable && v.type == nil { - push_generic_token(p, .Colon, 1); - push_generic_token(p, .Colon, 0); - } else { - push_generic_token(p, .Colon, 1); - } - } + visit_expr(p, v.type); + } else { + if !v.is_mutable && v.type == nil { + push_generic_token(p, .Colon, 1); + push_generic_token(p, .Colon, 0); + } else { + push_generic_token(p, .Colon, 1); + } + } - if v.is_mutable && v.type != nil && len(v.values) != 0 { - push_generic_token(p, .Eq, 1); - } else if v.is_mutable && v.type == nil && len(v.values) != 0 { - push_generic_token(p, .Eq, 0); - } else if !v.is_mutable && v.type != nil { - push_generic_token(p, .Colon, 0); - } + if v.is_mutable && v.type != nil && len(v.values) != 0 { + push_generic_token(p, .Eq, 1); + } else if v.is_mutable && v.type == nil && len(v.values) != 0 { + push_generic_token(p, .Eq, 0); + } else if !v.is_mutable && v.type != nil { + push_generic_token(p, .Colon, 0); + } - visit_exprs(p, v.values, true); + visit_exprs(p, v.values, true); - add_semicolon := true; + add_semicolon := true; - for value in v.values { - switch a in value.derived { - case Proc_Lit, Union_Type, Enum_Type, Struct_Type: - add_semicolon = false || called_in_stmt; - } - } + for value in v.values { + switch a in value.derived { + case Proc_Lit, Union_Type, Enum_Type, Struct_Type: + add_semicolon = false || called_in_stmt; + } + } - if add_semicolon && p.config.semicolons && !p.skip_semicolon { - push_generic_token(p, .Semicolon, 0); - } + if add_semicolon && p.config.semicolons && !p.skip_semicolon { + push_generic_token(p, .Semicolon, 0); + } - case: - panic(fmt.aprint(decl.derived)); - } + case: + panic(fmt.aprint(decl.derived)); + } } @(private) visit_exprs :: proc(p: ^Printer, list: [] ^ast.Expr, add_comma := false, trailing := false) { - if len(list) == 0 { - return; - } + if len(list) == 0 { + return; + } - //we have to newline the expressions to respect the source - for expr, i in list { + //we have to newline the expressions to respect the source + for expr, i in list { - move_line_limit(p, expr.pos, 1); + move_line_limit(p, expr.pos, 1); - visit_expr(p, expr); + visit_expr(p, expr); - if (i != len(list) - 1 || trailing) && add_comma { - push_generic_token(p, .Comma, 0); - } - } + if (i != len(list) - 1 || trailing) && add_comma { + push_generic_token(p, .Comma, 0); + } + } } @(private) visit_attributes :: proc(p: ^Printer, attributes: [dynamic] ^ast.Attribute) { - if len(attributes) == 0 { - return; - } + if len(attributes) == 0 { + return; + } - for attribute, i in attributes { + for attribute, i in attributes { - move_line_limit(p, attribute.pos, 1); + move_line_limit(p, attribute.pos, 1); - push_generic_token(p, .At, 0); - push_generic_token(p, .Open_Paren, 0); + push_generic_token(p, .At, 0); + push_generic_token(p, .Open_Paren, 0); - visit_exprs(p, attribute.elems, true); + visit_exprs(p, attribute.elems, true); - push_generic_token(p, .Close_Paren, 0); - } + push_generic_token(p, .Close_Paren, 0); + } } @(private) visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Generic, empty_block := false, block_stmt := false) { - using ast; + using ast; - if stmt == nil { - return; - } + if stmt == nil { + return; + } - switch v in stmt.derived { - case Value_Decl: - visit_decl(p, cast(^Decl)stmt, true); - return; - case Foreign_Import_Decl: - visit_decl(p, cast(^Decl)stmt, true); - return; - case Foreign_Block_Decl: - visit_decl(p, cast(^Decl)stmt, true); - return; - } + switch v in stmt.derived { + case Value_Decl: + visit_decl(p, cast(^Decl)stmt, true); + return; + case Foreign_Import_Decl: + visit_decl(p, cast(^Decl)stmt, true); + return; + case Foreign_Block_Decl: + visit_decl(p, cast(^Decl)stmt, true); + return; + } - switch v in stmt.derived { - case Using_Stmt: - move_line(p, v.pos); + switch v in stmt.derived { + case Using_Stmt: + move_line(p, v.pos); - push_generic_token(p, .Using, 1); + push_generic_token(p, .Using, 1); - visit_exprs(p, v.list, true); + visit_exprs(p, v.list, true); - if p.config.semicolons { - push_generic_token(p, .Semicolon, 0); - } - case Block_Stmt: - move_line(p, v.pos); + if p.config.semicolons { + push_generic_token(p, .Semicolon, 0); + } + case Block_Stmt: + move_line(p, v.pos); - if v.pos.line == v.end.line { - if !empty_block { - push_generic_token(p, .Open_Brace, 0); - } + if v.pos.line == v.end.line { + if !empty_block { + push_generic_token(p, .Open_Brace, 0); + } - set_source_position(p, v.pos); + set_source_position(p, v.pos); - visit_block_stmts(p, v.stmts, len(v.stmts) > 1 && p.config.split_multiple_stmts); + visit_block_stmts(p, v.stmts, len(v.stmts) > 1 && p.config.split_multiple_stmts); - set_source_position(p, v.end); + set_source_position(p, v.end); - if !empty_block { - push_generic_token(p, .Close_Brace, 0); - } - } else { - if !empty_block { - visit_begin_brace(p, v.pos, block_type, len(v.stmts)); - } + if !empty_block { + push_generic_token(p, .Close_Brace, 0); + } + } else { + if !empty_block { + visit_begin_brace(p, v.pos, block_type, len(v.stmts)); + } - set_source_position(p, v.pos); + set_source_position(p, v.pos); - visit_block_stmts(p, v.stmts, len(v.stmts) > 1 && p.config.split_multiple_stmts); + visit_block_stmts(p, v.stmts, len(v.stmts) > 1 && p.config.split_multiple_stmts); - set_source_position(p, v.end); + set_source_position(p, v.end); - if !empty_block { - visit_end_brace(p, v.end); - } - } - case If_Stmt: - move_line(p, v.pos); + if !empty_block { + visit_end_brace(p, v.end); + } + } + case If_Stmt: + move_line(p, v.pos); - if v.label != nil { - visit_expr(p, v.label); - push_generic_token(p, .Colon, 0); - } + if v.label != nil { + visit_expr(p, v.label); + push_generic_token(p, .Colon, 0); + } - push_generic_token(p, .If, 1); + push_generic_token(p, .If, 1); - if v.init != nil { - p.skip_semicolon = true; - visit_stmt(p, v.init); - p.skip_semicolon = false; - push_generic_token(p, .Semicolon, 0); - } + if v.init != nil { + p.skip_semicolon = true; + visit_stmt(p, v.init); + p.skip_semicolon = false; + push_generic_token(p, .Semicolon, 0); + } - visit_expr(p, v.cond); + visit_expr(p, v.cond); - uses_do := false; + uses_do := false; - if check_stmt, ok := v.body.derived.(Block_Stmt); ok && check_stmt.uses_do { - uses_do = true; - } + if check_stmt, ok := v.body.derived.(Block_Stmt); ok && check_stmt.uses_do { + uses_do = true; + } - if uses_do && !p.config.convert_do { - push_generic_token(p, .Do, 1); - visit_stmt(p, v.body, .If_Stmt, true); - } else { - if uses_do { - newline_position(p, 1); - } + if uses_do && !p.config.convert_do { + push_generic_token(p, .Do, 1); + visit_stmt(p, v.body, .If_Stmt, true); + } else { + if uses_do { + newline_position(p, 1); + } - visit_stmt(p, v.body, .If_Stmt); - } + visit_stmt(p, v.body, .If_Stmt); + } - if v.else_stmt != nil { + if v.else_stmt != nil { - if p.config.brace_style == .Allman || p.config.brace_style == .Stroustrup { - newline_position(p, 1); - } + if p.config.brace_style == .Allman || p.config.brace_style == .Stroustrup { + newline_position(p, 1); + } - push_generic_token(p, .Else, 1); + push_generic_token(p, .Else, 1); - set_source_position(p, v.else_stmt.pos); + set_source_position(p, v.else_stmt.pos); - visit_stmt(p, v.else_stmt); - } - case Switch_Stmt: - move_line(p, v.pos); + visit_stmt(p, v.else_stmt); + } + case Switch_Stmt: + move_line(p, v.pos); - if v.label != nil { - visit_expr(p, v.label); - push_generic_token(p, .Colon, 0); - } + if v.label != nil { + visit_expr(p, v.label); + push_generic_token(p, .Colon, 0); + } - if v.partial { - push_ident_token(p, "#partial", 1); - } + if v.partial { + push_ident_token(p, "#partial", 1); + } - push_generic_token(p, .Switch, 1); + push_generic_token(p, .Switch, 1); - hint_current_line(p,{.Switch_Stmt}); + hint_current_line(p,{.Switch_Stmt}); - if v.init != nil { - p.skip_semicolon = true; - visit_stmt(p, v.init); - p.skip_semicolon = false; - } + if v.init != nil { + p.skip_semicolon = true; + visit_stmt(p, v.init); + p.skip_semicolon = false; + } - if v.init != nil && v.cond != nil { - push_generic_token(p, .Semicolon, 0); - } + if v.init != nil && v.cond != nil { + push_generic_token(p, .Semicolon, 0); + } - visit_expr(p, v.cond); - visit_stmt(p, v.body); - case Case_Clause: - move_line(p, v.pos); + visit_expr(p, v.cond); + visit_stmt(p, v.body); + case Case_Clause: + move_line(p, v.pos); - if !p.config.indent_cases { - unindent(p); - } + if !p.config.indent_cases { + unindent(p); + } - push_generic_token(p, .Case, 0); + push_generic_token(p, .Case, 0); - if v.list != nil { - visit_exprs(p, v.list, true); - } + if v.list != nil { + visit_exprs(p, v.list, true); + } - push_generic_token(p, v.terminator.kind, 0); + push_generic_token(p, v.terminator.kind, 0); - indent(p); + indent(p); - visit_block_stmts(p, v.body); + visit_block_stmts(p, v.body); - unindent(p); + unindent(p); - if !p.config.indent_cases { - indent(p); - } - case Type_Switch_Stmt: - move_line(p, v.pos); + if !p.config.indent_cases { + indent(p); + } + case Type_Switch_Stmt: + move_line(p, v.pos); - if v.label != nil { - visit_expr(p, v.label); - push_generic_token(p, .Colon, 0); - } + if v.label != nil { + visit_expr(p, v.label); + push_generic_token(p, .Colon, 0); + } - if v.partial { - push_ident_token(p, "#partial", 1); - } + if v.partial { + push_ident_token(p, "#partial", 1); + } - push_generic_token(p, .Switch, 1); + push_generic_token(p, .Switch, 1); - visit_stmt(p, v.tag); - visit_stmt(p, v.body); - case Assign_Stmt: - move_line(p, v.pos); + visit_stmt(p, v.tag); + visit_stmt(p, v.body); + case Assign_Stmt: + move_line(p, v.pos); - visit_exprs(p, v.lhs, true); + visit_exprs(p, v.lhs, true); - push_generic_token(p, v.op.kind, 1); + push_generic_token(p, v.op.kind, 1); - visit_exprs(p, v.rhs, true); + visit_exprs(p, v.rhs, true); - if block_stmt && p.config.semicolons { - push_generic_token(p, .Semicolon, 0); - } - case Expr_Stmt: - move_line(p, v.pos); - visit_expr(p, v.expr); - if block_stmt && p.config.semicolons { - push_generic_token(p, .Semicolon, 0); - } - case For_Stmt: - //this should be simplified - move_line(p, v.pos); + if block_stmt && p.config.semicolons { + push_generic_token(p, .Semicolon, 0); + } + case Expr_Stmt: + move_line(p, v.pos); + visit_expr(p, v.expr); + if block_stmt && p.config.semicolons { + push_generic_token(p, .Semicolon, 0); + } + case For_Stmt: + //this should be simplified + move_line(p, v.pos); - if v.label != nil { - visit_expr(p, v.label); - push_generic_token(p, .Colon, 0); - } + if v.label != nil { + visit_expr(p, v.label); + push_generic_token(p, .Colon, 0); + } - push_generic_token(p, .For, 1); + push_generic_token(p, .For, 1); - if v.init != nil { - p.skip_semicolon = true; - visit_stmt(p, v.init); - p.skip_semicolon = false; - push_generic_token(p, .Semicolon, 0); - } else if v.post != nil { - push_generic_token(p, .Semicolon, 0); - } + if v.init != nil { + p.skip_semicolon = true; + visit_stmt(p, v.init); + p.skip_semicolon = false; + push_generic_token(p, .Semicolon, 0); + } else if v.post != nil { + push_generic_token(p, .Semicolon, 0); + } - if v.cond != nil { - visit_expr(p, v.cond); - } + if v.cond != nil { + visit_expr(p, v.cond); + } - if v.post != nil { - push_generic_token(p, .Semicolon, 0); - visit_stmt(p, v.post); - } else if v.post == nil && v.cond != nil && v.init != nil { - push_generic_token(p, .Semicolon, 0); - } + if v.post != nil { + push_generic_token(p, .Semicolon, 0); + visit_stmt(p, v.post); + } else if v.post == nil && v.cond != nil && v.init != nil { + push_generic_token(p, .Semicolon, 0); + } - visit_stmt(p, v.body); - case Inline_Range_Stmt: + visit_stmt(p, v.body); + case Inline_Range_Stmt: - move_line(p, v.pos); + move_line(p, v.pos); - if v.label != nil { - visit_expr(p, v.label); - push_generic_token(p, .Colon, 0); - } + if v.label != nil { + visit_expr(p, v.label); + push_generic_token(p, .Colon, 0); + } - push_ident_token(p, "#unroll", 0); + push_ident_token(p, "#unroll", 0); - push_generic_token(p, .For, 1); - visit_expr(p, v.val0); + push_generic_token(p, .For, 1); + visit_expr(p, v.val0); - if v.val1 != nil { - push_generic_token(p, .Comma, 0); - visit_expr(p, v.val1); - } + if v.val1 != nil { + push_generic_token(p, .Comma, 0); + visit_expr(p, v.val1); + } - push_generic_token(p, .In, 1); + push_generic_token(p, .In, 1); - visit_expr(p, v.expr); - visit_stmt(p, v.body); - case Range_Stmt: + visit_expr(p, v.expr); + visit_stmt(p, v.body); + case Range_Stmt: - move_line(p, v.pos); + move_line(p, v.pos); - if v.label != nil { - visit_expr(p, v.label); - push_generic_token(p, .Colon, 0); - } + if v.label != nil { + visit_expr(p, v.label); + push_generic_token(p, .Colon, 0); + } - push_generic_token(p, .For, 1); + push_generic_token(p, .For, 1); - if len(v.vals) >= 1 { - visit_expr(p, v.vals[0]); - } + if len(v.vals) >= 1 { + visit_expr(p, v.vals[0]); + } - if len(v.vals) >= 2 { - push_generic_token(p, .Comma, 0); - visit_expr(p, v.vals[1]); - } + if len(v.vals) >= 2 { + push_generic_token(p, .Comma, 0); + visit_expr(p, v.vals[1]); + } - push_generic_token(p, .In, 1); + push_generic_token(p, .In, 1); - visit_expr(p, v.expr); + visit_expr(p, v.expr); - visit_stmt(p, v.body); - case Return_Stmt: - move_line(p, v.pos); + visit_stmt(p, v.body); + case Return_Stmt: + move_line(p, v.pos); - push_generic_token(p, .Return, 1); + push_generic_token(p, .Return, 1); - if v.results != nil { - visit_exprs(p, v.results, true); - } + if v.results != nil { + visit_exprs(p, v.results, true); + } - if block_stmt && p.config.semicolons { - push_generic_token(p, .Semicolon, 0); - } - case Defer_Stmt: - move_line(p, v.pos); - push_generic_token(p, .Defer, 0); + if block_stmt && p.config.semicolons { + push_generic_token(p, .Semicolon, 0); + } + case Defer_Stmt: + move_line(p, v.pos); + push_generic_token(p, .Defer, 0); - visit_stmt(p, v.stmt); + visit_stmt(p, v.stmt); - if p.config.semicolons { - push_generic_token(p, .Semicolon, 0); - } - case When_Stmt: - move_line(p, v.pos); - push_generic_token(p, .When, 1); - visit_expr(p, v.cond); + if p.config.semicolons { + push_generic_token(p, .Semicolon, 0); + } + case When_Stmt: + move_line(p, v.pos); + push_generic_token(p, .When, 1); + visit_expr(p, v.cond); - visit_stmt(p, v.body); + visit_stmt(p, v.body); - if v.else_stmt != nil { + if v.else_stmt != nil { - if p.config.brace_style == .Allman { - newline_position(p, 1); - } + if p.config.brace_style == .Allman { + newline_position(p, 1); + } - push_generic_token(p, .Else, 1); + push_generic_token(p, .Else, 1); - set_source_position(p, v.else_stmt.pos); + set_source_position(p, v.else_stmt.pos); - visit_stmt(p, v.else_stmt); - } + visit_stmt(p, v.else_stmt); + } - case Branch_Stmt: + case Branch_Stmt: - move_line(p, v.pos); + move_line(p, v.pos); - push_generic_token(p, v.tok.kind, 0); + push_generic_token(p, v.tok.kind, 0); - if v.label != nil { - visit_expr(p, v.label); - } + if v.label != nil { + visit_expr(p, v.label); + } - if p.config.semicolons { - push_generic_token(p, .Semicolon, 0); - } - case: - panic(fmt.aprint(stmt.derived)); - } + if p.config.semicolons { + push_generic_token(p, .Semicolon, 0); + } + case: + panic(fmt.aprint(stmt.derived)); + } - set_source_position(p, stmt.end); + set_source_position(p, stmt.end); } @(private) visit_expr :: proc(p: ^Printer, expr: ^ast.Expr) { - using ast; + using ast; - if expr == nil { - return; - } + if expr == nil { + return; + } - set_source_position(p, expr.pos); + set_source_position(p, expr.pos); - switch v in expr.derived { - case Inline_Asm_Expr: - push_generic_token(p, v.tok.kind, 1, v.tok.text); + switch v in expr.derived { + case Inline_Asm_Expr: + push_generic_token(p, v.tok.kind, 1, v.tok.text); - push_generic_token(p, .Open_Paren, 1); - visit_exprs(p, v.param_types, true, false); - push_generic_token(p, .Close_Paren, 0); + push_generic_token(p, .Open_Paren, 1); + visit_exprs(p, v.param_types, true, false); + push_generic_token(p, .Close_Paren, 0); - push_generic_token(p, .Sub, 1); - push_generic_token(p, .Gt, 0); + push_generic_token(p, .Sub, 1); + push_generic_token(p, .Gt, 0); - visit_expr(p, v.return_type); + visit_expr(p, v.return_type); - push_generic_token(p, .Open_Brace, 1); - visit_expr(p, v.asm_string); - push_generic_token(p, .Comma, 0); - visit_expr(p, v.constraints_string); - push_generic_token(p, .Close_Brace, 0); - case Undef: - push_generic_token(p, .Undef, 1); - case Auto_Cast: - push_generic_token(p, v.op.kind, 1); - visit_expr(p, v.expr); - case Ternary_Expr: - visit_expr(p, v.cond); - push_generic_token(p, v.op1.kind, 1); - visit_expr(p, v.x); - push_generic_token(p, v.op2.kind, 1); - visit_expr(p, v.y); - case Ternary_If_Expr: - visit_expr(p, v.x); - push_generic_token(p, v.op1.kind, 1); - visit_expr(p, v.cond); - push_generic_token(p, v.op2.kind, 1); - visit_expr(p, v.y); - case Ternary_When_Expr: - visit_expr(p, v.x); - push_generic_token(p, v.op1.kind, 1); - visit_expr(p, v.cond); - push_generic_token(p, v.op2.kind, 1); - visit_expr(p, v.y); - case Selector_Call_Expr: - visit_expr(p, v.call.expr); - push_generic_token(p, .Open_Paren, 1); - visit_exprs(p, v.call.args, true); - push_generic_token(p, .Close_Paren, 0); - case Ellipsis: - push_generic_token(p, .Ellipsis, 1); - visit_expr(p, v.expr); - case Relative_Type: - visit_expr(p, v.tag); - visit_expr(p, v.type); - case Slice_Expr: - visit_expr(p, v.expr); - push_generic_token(p, .Open_Bracket, 0); - visit_expr(p, v.low); - push_generic_token(p, v.interval.kind, 0); - if v.high != nil { - merge_next_token(p); - visit_expr(p, v.high); - } - push_generic_token(p, .Close_Bracket, 0); - case Ident: - push_ident_token(p, v.name, 1); - case Deref_Expr: - visit_expr(p, v.expr); - push_generic_token(p, v.op.kind, 0); - case Type_Cast: - push_generic_token(p, v.tok.kind, 1); - push_generic_token(p, .Open_Paren, 0); - visit_expr(p, v.type); - push_generic_token(p, .Close_Paren, 0); - merge_next_token(p); - visit_expr(p, v.expr); - case Basic_Directive: - push_generic_token(p, v.tok.kind, 1); - push_ident_token(p, v.name, 0); - case Distinct_Type: - push_generic_token(p, .Distinct, 1); - visit_expr(p, v.type); - case Dynamic_Array_Type: - visit_expr(p, v.tag); - push_generic_token(p, .Open_Bracket, 1); - push_generic_token(p, .Dynamic, 0); - push_generic_token(p, .Close_Bracket, 0); - visit_expr(p, v.elem); - case Bit_Set_Type: - push_generic_token(p, .Bit_Set, 1); - push_generic_token(p, .Open_Bracket, 0); + push_generic_token(p, .Open_Brace, 1); + visit_expr(p, v.asm_string); + push_generic_token(p, .Comma, 0); + visit_expr(p, v.constraints_string); + push_generic_token(p, .Close_Brace, 0); + case Undef: + push_generic_token(p, .Undef, 1); + case Auto_Cast: + push_generic_token(p, v.op.kind, 1); + visit_expr(p, v.expr); + case Ternary_Expr: + visit_expr(p, v.cond); + push_generic_token(p, v.op1.kind, 1); + visit_expr(p, v.x); + push_generic_token(p, v.op2.kind, 1); + visit_expr(p, v.y); + case Ternary_If_Expr: + visit_expr(p, v.x); + push_generic_token(p, v.op1.kind, 1); + visit_expr(p, v.cond); + push_generic_token(p, v.op2.kind, 1); + visit_expr(p, v.y); + case Ternary_When_Expr: + visit_expr(p, v.x); + push_generic_token(p, v.op1.kind, 1); + visit_expr(p, v.cond); + push_generic_token(p, v.op2.kind, 1); + visit_expr(p, v.y); + case Selector_Call_Expr: + visit_expr(p, v.call.expr); + push_generic_token(p, .Open_Paren, 1); + visit_exprs(p, v.call.args, true); + push_generic_token(p, .Close_Paren, 0); + case Ellipsis: + push_generic_token(p, .Ellipsis, 1); + visit_expr(p, v.expr); + case Relative_Type: + visit_expr(p, v.tag); + visit_expr(p, v.type); + case Slice_Expr: + visit_expr(p, v.expr); + push_generic_token(p, .Open_Bracket, 0); + visit_expr(p, v.low); + push_generic_token(p, v.interval.kind, 0); + if v.high != nil { + merge_next_token(p); + visit_expr(p, v.high); + } + push_generic_token(p, .Close_Bracket, 0); + case Ident: + push_ident_token(p, v.name, 1); + case Deref_Expr: + visit_expr(p, v.expr); + push_generic_token(p, v.op.kind, 0); + case Type_Cast: + push_generic_token(p, v.tok.kind, 1); + push_generic_token(p, .Open_Paren, 0); + visit_expr(p, v.type); + push_generic_token(p, .Close_Paren, 0); + merge_next_token(p); + visit_expr(p, v.expr); + case Basic_Directive: + push_generic_token(p, v.tok.kind, 1); + push_ident_token(p, v.name, 0); + case Distinct_Type: + push_generic_token(p, .Distinct, 1); + visit_expr(p, v.type); + case Dynamic_Array_Type: + visit_expr(p, v.tag); + push_generic_token(p, .Open_Bracket, 1); + push_generic_token(p, .Dynamic, 0); + push_generic_token(p, .Close_Bracket, 0); + visit_expr(p, v.elem); + case Bit_Set_Type: + push_generic_token(p, .Bit_Set, 1); + push_generic_token(p, .Open_Bracket, 0); - visit_expr(p, v.elem); + visit_expr(p, v.elem); - if v.underlying != nil { - push_generic_token(p, .Semicolon, 0); - visit_expr(p, v.underlying); - } + if v.underlying != nil { + push_generic_token(p, .Semicolon, 0); + visit_expr(p, v.underlying); + } - push_generic_token(p, .Close_Bracket, 0); - case Union_Type: - push_generic_token(p, .Union, 1); + push_generic_token(p, .Close_Bracket, 0); + case Union_Type: + push_generic_token(p, .Union, 1); - if v.poly_params != nil { - push_generic_token(p, .Open_Paren, 0); - visit_field_list(p, v.poly_params, true, false); - push_generic_token(p, .Close_Paren, 0); - } + if v.poly_params != nil { + push_generic_token(p, .Open_Paren, 0); + visit_field_list(p, v.poly_params, true, false); + push_generic_token(p, .Close_Paren, 0); + } - if v.is_maybe { - push_ident_token(p, "#maybe", 1); - } + if v.is_maybe { + push_ident_token(p, "#maybe", 1); + } - if v.where_clauses != nil { - move_line(p, v.where_clauses[0].pos); - push_generic_token(p, .Where, 1); - visit_exprs(p, v.where_clauses, true); - } + if v.where_clauses != nil { + move_line(p, v.where_clauses[0].pos); + push_generic_token(p, .Where, 1); + visit_exprs(p, v.where_clauses, true); + } - if v.variants != nil && (len(v.variants) == 0 || v.pos.line == v.end.line) { - push_generic_token(p, .Open_Brace, 1); - visit_exprs(p, v.variants, true); - push_generic_token(p, .Close_Brace, 0); - } else { - visit_begin_brace(p, v.pos, .Generic); - newline_position(p, 1); - set_source_position(p, v.variants[0].pos); - visit_exprs(p, v.variants, true, true); - visit_end_brace(p, v.end); - } - case Enum_Type: - push_generic_token(p, .Enum, 1); + if v.variants != nil && (len(v.variants) == 0 || v.pos.line == v.end.line) { + push_generic_token(p, .Open_Brace, 1); + visit_exprs(p, v.variants, true); + push_generic_token(p, .Close_Brace, 0); + } else { + visit_begin_brace(p, v.pos, .Generic); + newline_position(p, 1); + set_source_position(p, v.variants[0].pos); + visit_exprs(p, v.variants, true, true); + visit_end_brace(p, v.end); + } + case Enum_Type: + push_generic_token(p, .Enum, 1); - if v.base_type != nil { - visit_expr(p, v.base_type); - } + if v.base_type != nil { + visit_expr(p, v.base_type); + } - if v.fields != nil && (len(v.fields) == 0 || v.pos.line == v.end.line) { - push_generic_token(p, .Open_Brace, 1); - visit_exprs(p, v.fields, true); - push_generic_token(p, .Close_Brace, 0); - } else { - visit_begin_brace(p, v.pos, .Generic); - newline_position(p, 1); - set_source_position(p, v.fields[0].pos); - visit_exprs(p, v.fields, true, true); - visit_end_brace(p, v.end); - } + if v.fields != nil && (len(v.fields) == 0 || v.pos.line == v.end.line) { + push_generic_token(p, .Open_Brace, 1); + visit_exprs(p, v.fields, true); + push_generic_token(p, .Close_Brace, 0); + } else { + visit_begin_brace(p, v.pos, .Generic); + newline_position(p, 1); + set_source_position(p, v.fields[0].pos); + visit_exprs(p, v.fields, true, true); + visit_end_brace(p, v.end); + } - set_source_position(p, v.end); - case Struct_Type: - push_generic_token(p, .Struct, 1); + set_source_position(p, v.end); + case Struct_Type: + push_generic_token(p, .Struct, 1); - hint_current_line(p,{.Struct}); + hint_current_line(p,{.Struct}); - if v.is_packed { - push_ident_token(p, "#packed", 1); - } + if v.is_packed { + push_ident_token(p, "#packed", 1); + } - if v.is_raw_union { - push_ident_token(p, "#raw_union", 1); - } + if v.is_raw_union { + push_ident_token(p, "#raw_union", 1); + } - if v.align != nil { - push_ident_token(p, "#align", 1); - visit_expr(p, v.align); - } + if v.align != nil { + push_ident_token(p, "#align", 1); + visit_expr(p, v.align); + } - if v.poly_params != nil { - push_generic_token(p, .Open_Paren, 0); - visit_field_list(p, v.poly_params, true, false); - push_generic_token(p, .Close_Paren, 0); - } + if v.poly_params != nil { + push_generic_token(p, .Open_Paren, 0); + visit_field_list(p, v.poly_params, true, false); + push_generic_token(p, .Close_Paren, 0); + } - if v.where_clauses != nil { - move_line(p, v.where_clauses[0].pos); - push_generic_token(p, .Where, 1); - visit_exprs(p, v.where_clauses, true); - } + if v.where_clauses != nil { + move_line(p, v.where_clauses[0].pos); + push_generic_token(p, .Where, 1); + visit_exprs(p, v.where_clauses, true); + } - if v.fields != nil && (len(v.fields.list) == 0 || v.pos.line == v.end.line) { - push_generic_token(p, .Open_Brace, 1); - set_source_position(p, v.fields.pos); - visit_field_list(p, v.fields, true); - push_generic_token(p, .Close_Brace, 0); - } else if v.fields != nil { - visit_begin_brace(p, v.pos, .Generic, len(v.fields.list)); - set_source_position(p, v.fields.pos); - visit_field_list(p, v.fields, true, true, true); - visit_end_brace(p, v.end); - } + if v.fields != nil && (len(v.fields.list) == 0 || v.pos.line == v.end.line) { + push_generic_token(p, .Open_Brace, 1); + set_source_position(p, v.fields.pos); + visit_field_list(p, v.fields, true); + push_generic_token(p, .Close_Brace, 0); + } else if v.fields != nil { + visit_begin_brace(p, v.pos, .Generic, len(v.fields.list)); + set_source_position(p, v.fields.pos); + visit_field_list(p, v.fields, true, true, true); + visit_end_brace(p, v.end); + } - set_source_position(p, v.end); - case Proc_Lit: + set_source_position(p, v.end); + case Proc_Lit: - if v.inlining == .Inline { - push_ident_token(p, "#force_inline", 0); - } + if v.inlining == .Inline { + push_ident_token(p, "#force_inline", 0); + } - visit_proc_type(p, v.type^); + visit_proc_type(p, v.type^); - if v.where_clauses != nil { - move_line(p, v.where_clauses[0].pos); - push_generic_token(p, .Where, 1); - visit_exprs(p, v.where_clauses, true); - } + if v.where_clauses != nil { + move_line(p, v.where_clauses[0].pos); + push_generic_token(p, .Where, 1); + visit_exprs(p, v.where_clauses, true); + } - if v.body != nil { - set_source_position(p, v.body.pos); - visit_stmt(p, v.body, .Proc); - } else { - push_generic_token(p, .Undef, 1); - } - case Proc_Type: - visit_proc_type(p, v); - case Basic_Lit: - push_generic_token(p, v.tok.kind, 1, v.tok.text); - case Binary_Expr: - visit_binary_expr(p, v); - case Implicit_Selector_Expr: - push_generic_token(p, .Period, 1); - push_ident_token(p, v.field.name, 0); - case Call_Expr: - visit_expr(p, v.expr); - push_generic_token(p, .Open_Paren, 0); - visit_call_exprs(p, v.args, v.ellipsis.kind == .Ellipsis); - push_generic_token(p, .Close_Paren, 0); - case Typeid_Type: - push_generic_token(p, .Typeid, 1); + if v.body != nil { + set_source_position(p, v.body.pos); + visit_stmt(p, v.body, .Proc); + } else { + push_generic_token(p, .Undef, 1); + } + case Proc_Type: + visit_proc_type(p, v); + case Basic_Lit: + push_generic_token(p, v.tok.kind, 1, v.tok.text); + case Binary_Expr: + visit_binary_expr(p, v); + case Implicit_Selector_Expr: + push_generic_token(p, .Period, 1); + push_ident_token(p, v.field.name, 0); + case Call_Expr: + visit_expr(p, v.expr); + push_generic_token(p, .Open_Paren, 0); + visit_call_exprs(p, v.args, v.ellipsis.kind == .Ellipsis); + push_generic_token(p, .Close_Paren, 0); + case Typeid_Type: + push_generic_token(p, .Typeid, 1); - if v.specialization != nil { - push_generic_token(p, .Quo, 0); - visit_expr(p, v.specialization); - } - case Selector_Expr: - visit_expr(p, v.expr); - push_generic_token(p, v.op.kind, 0); - visit_expr(p, v.field); - case Paren_Expr: - push_generic_token(p, .Open_Paren, 1); - visit_expr(p, v.expr); - push_generic_token(p, .Close_Paren, 0); - case Index_Expr: - visit_expr(p, v.expr); - push_generic_token(p, .Open_Bracket, 0); - visit_expr(p, v.index); - push_generic_token(p, .Close_Bracket, 0); - case Proc_Group: + if v.specialization != nil { + push_generic_token(p, .Quo, 0); + visit_expr(p, v.specialization); + } + case Selector_Expr: + visit_expr(p, v.expr); + push_generic_token(p, v.op.kind, 0); + visit_expr(p, v.field); + case Paren_Expr: + push_generic_token(p, .Open_Paren, 1); + visit_expr(p, v.expr); + push_generic_token(p, .Close_Paren, 0); + case Index_Expr: + visit_expr(p, v.expr); + push_generic_token(p, .Open_Bracket, 0); + visit_expr(p, v.index); + push_generic_token(p, .Close_Bracket, 0); + case Proc_Group: - push_generic_token(p, v.tok.kind, 0); + push_generic_token(p, v.tok.kind, 0); - if len(v.args) != 0 && v.pos.line != v.args[len(v.args) - 1].pos.line { - visit_begin_brace(p, v.pos, .Generic); - newline_position(p, 1); - set_source_position(p, v.args[0].pos); - visit_exprs(p, v.args, true, true); - visit_end_brace(p, v.end); - } else { - push_generic_token(p, .Open_Brace, 0); - visit_exprs(p, v.args, true); - push_generic_token(p, .Close_Brace, 0); - } + if len(v.args) != 0 && v.pos.line != v.args[len(v.args) - 1].pos.line { + visit_begin_brace(p, v.pos, .Generic); + newline_position(p, 1); + set_source_position(p, v.args[0].pos); + visit_exprs(p, v.args, true, true); + visit_end_brace(p, v.end); + } else { + push_generic_token(p, .Open_Brace, 0); + visit_exprs(p, v.args, true); + push_generic_token(p, .Close_Brace, 0); + } - case Comp_Lit: + case Comp_Lit: - if v.type != nil { - visit_expr(p, v.type); - } + if v.type != nil { + visit_expr(p, v.type); + } - if len(v.elems) != 0 && v.pos.line != v.elems[len(v.elems) - 1].pos.line { - visit_begin_brace(p, v.pos, .Comp_Lit); - newline_position(p, 1); - set_source_position(p, v.elems[0].pos); - visit_exprs(p, v.elems, true, true); - visit_end_brace(p, v.end); - } else { - push_generic_token(p, .Open_Brace, 0); - visit_exprs(p, v.elems, true); - push_generic_token(p, .Close_Brace, 0); - } + if len(v.elems) != 0 && v.pos.line != v.elems[len(v.elems) - 1].pos.line { + visit_begin_brace(p, v.pos, .Comp_Lit); + newline_position(p, 1); + set_source_position(p, v.elems[0].pos); + visit_exprs(p, v.elems, true, true); + visit_end_brace(p, v.end); + } else { + push_generic_token(p, .Open_Brace, 0); + visit_exprs(p, v.elems, true); + push_generic_token(p, .Close_Brace, 0); + } - case Unary_Expr: - push_generic_token(p, v.op.kind, 1); - merge_next_token(p); - visit_expr(p, v.expr); - case Field_Value: - visit_expr(p, v.field); - push_generic_token(p, .Eq, 1); - visit_expr(p, v.value); - case Type_Assertion: - visit_expr(p, v.expr); + case Unary_Expr: + push_generic_token(p, v.op.kind, 1); + merge_next_token(p); + visit_expr(p, v.expr); + case Field_Value: + visit_expr(p, v.field); + push_generic_token(p, .Eq, 1); + visit_expr(p, v.value); + case Type_Assertion: + visit_expr(p, v.expr); - if unary, ok := v.type.derived.(Unary_Expr); ok && unary.op.text == "?" { - push_generic_token(p, .Period, 0); - visit_expr(p, v.type); - } else { - push_generic_token(p, .Period, 0); - push_generic_token(p, .Open_Paren, 0); - visit_expr(p, v.type); - push_generic_token(p, .Close_Paren, 0); - } + if unary, ok := v.type.derived.(Unary_Expr); ok && unary.op.text == "?" { + push_generic_token(p, .Period, 0); + visit_expr(p, v.type); + } else { + push_generic_token(p, .Period, 0); + push_generic_token(p, .Open_Paren, 0); + visit_expr(p, v.type); + push_generic_token(p, .Close_Paren, 0); + } - case Pointer_Type: - push_generic_token(p, .Pointer, 1); - merge_next_token(p); - visit_expr(p, v.elem); - case Implicit: - push_generic_token(p, v.tok.kind, 1); - case Poly_Type: - push_generic_token(p, .Dollar, 1); - merge_next_token(p); - visit_expr(p, v.type); + case Pointer_Type: + push_generic_token(p, .Pointer, 1); + merge_next_token(p); + visit_expr(p, v.elem); + case Implicit: + push_generic_token(p, v.tok.kind, 1); + case Poly_Type: + push_generic_token(p, .Dollar, 1); + merge_next_token(p); + visit_expr(p, v.type); - if v.specialization != nil { - push_generic_token(p, .Quo, 0); - merge_next_token(p); - visit_expr(p, v.specialization); - } - case Array_Type: - visit_expr(p, v.tag); - push_generic_token(p, .Open_Bracket, 1); - visit_expr(p, v.len); - push_generic_token(p, .Close_Bracket, 0); - visit_expr(p, v.elem); - case Map_Type: - push_generic_token(p, .Map, 1); - push_generic_token(p, .Open_Bracket, 0); - visit_expr(p, v.key); - push_generic_token(p, .Close_Bracket, 0); - visit_expr(p, v.value); - case Helper_Type: - visit_expr(p, v.type); - case: - panic(fmt.aprint(expr.derived)); - } + if v.specialization != nil { + push_generic_token(p, .Quo, 0); + merge_next_token(p); + visit_expr(p, v.specialization); + } + case Array_Type: + visit_expr(p, v.tag); + push_generic_token(p, .Open_Bracket, 1); + visit_expr(p, v.len); + push_generic_token(p, .Close_Bracket, 0); + visit_expr(p, v.elem); + case Map_Type: + push_generic_token(p, .Map, 1); + push_generic_token(p, .Open_Bracket, 0); + visit_expr(p, v.key); + push_generic_token(p, .Close_Bracket, 0); + visit_expr(p, v.value); + case Helper_Type: + visit_expr(p, v.type); + case: + panic(fmt.aprint(expr.derived)); + } } visit_begin_brace :: proc(p: ^Printer, begin: tokenizer.Pos, type: Block_Type, count := 0) { - set_source_position(p, begin); + set_source_position(p, begin); - newline_braced := p.config.brace_style == .Allman; - newline_braced |= p.config.brace_style == .K_And_R && type == .Proc; - newline_braced &= p.config.brace_style != ._1TBS; + newline_braced := p.config.brace_style == .Allman; + 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 = "{", - }; + format_token := Format_Token { + kind = .Open_Brace, + parameter_count = count, + text = "{", + }; - if newline_braced { - newline_position(p, 1); - push_format_token(p, format_token); - indent(p); - } else { - format_token.spaces_before = 1; - push_format_token(p, format_token); - indent(p); - } + if newline_braced { + newline_position(p, 1); + push_format_token(p, format_token); + indent(p); + } else { + format_token.spaces_before = 1; + push_format_token(p, format_token); + indent(p); + } } visit_end_brace :: proc(p: ^Printer, end: tokenizer.Pos) { - set_source_position(p, end); - newline_position(p, 1); - push_generic_token(p, .Close_Brace, 0); - unindent(p); - p.current_line.depth = p.depth; + set_source_position(p, end); + newline_position(p, 1); + push_generic_token(p, .Close_Brace, 0); + unindent(p); + p.current_line.depth = p.depth; } visit_block_stmts :: proc(p: ^Printer, stmts: [] ^ast.Stmt, split := false) { - for stmt, i in stmts { - visit_stmt(p, stmt, .Generic, false, true); + for stmt, i in stmts { + visit_stmt(p, stmt, .Generic, false, true); - if split && i != len(stmts) - 1 && stmt.pos.line == stmts[i + 1].pos.line { - newline_position(p, 1); - } - } + if split && i != len(stmts) - 1 && stmt.pos.line == stmts[i + 1].pos.line { + newline_position(p, 1); + } + } } visit_field_list :: proc(p: ^Printer, list: ^ast.Field_List, add_comma := false, trailing := false, enforce_newline := false) { - if list.list == nil { - return; - } + if list.list == nil { + return; + } - for field, i in list.list { + for field, i in list.list { - if !move_line_limit(p, field.pos, 1) && enforce_newline { - newline_position(p, 1); - } + if !move_line_limit(p, field.pos, 1) && enforce_newline { + newline_position(p, 1); + } - if .Using in field.flags { - push_generic_token(p, .Using, 0); - } + if .Using in field.flags { + push_generic_token(p, .Using, 0); + } - visit_exprs(p, field.names, true); + visit_exprs(p, field.names, true); - if field.type != nil { - if len(field.names) != 0 { - push_generic_token(p, .Colon, 0); - } - visit_expr(p, field.type); - } else { - push_generic_token(p, .Colon, 1); - push_generic_token(p, .Eq, 0); - visit_expr(p, field.default_value); - } + if field.type != nil { + if len(field.names) != 0 { + push_generic_token(p, .Colon, 0); + } + visit_expr(p, field.type); + } else { + push_generic_token(p, .Colon, 1); + push_generic_token(p, .Eq, 0); + visit_expr(p, field.default_value); + } - if field.tag.text != "" { - push_generic_token(p, field.tag.kind, 1, field.tag.text); - } + if field.tag.text != "" { + push_generic_token(p, field.tag.kind, 1, field.tag.text); + } - if (i != len(list.list) - 1 || trailing) && add_comma { - push_generic_token(p, .Comma, 0); - } - } + if (i != len(list.list) - 1 || trailing) && add_comma { + push_generic_token(p, .Comma, 0); + } + } } visit_proc_type :: proc(p: ^Printer, proc_type: ast.Proc_Type) { - push_generic_token(p, .Proc, 1); + push_generic_token(p, .Proc, 1); - explicit_calling := false; + explicit_calling := false; - switch proc_type.calling_convention { - case .Odin: - case .Contextless: - push_string_token(p, "\"contextless\"", 1); - explicit_calling = true; - case .C_Decl: - push_string_token(p, "\"c\"", 1); - explicit_calling = true; - case .Std_Call: - push_string_token(p, "\"std\"", 1); - explicit_calling = true; - case .Fast_Call: - push_string_token(p, "\"fast\"", 1); - explicit_calling = true; - case .None: - //nothing i guess - case .Invalid: - //nothing i guess - case .Foreign_Block_Default: - } + switch proc_type.calling_convention { + case .Odin: + case .Contextless: + push_string_token(p, "\"contextless\"", 1); + explicit_calling = true; + case .C_Decl: + push_string_token(p, "\"c\"", 1); + explicit_calling = true; + case .Std_Call: + push_string_token(p, "\"std\"", 1); + explicit_calling = true; + case .Fast_Call: + push_string_token(p, "\"fast\"", 1); + explicit_calling = true; + case .None: + //nothing i guess + case .Invalid: + //nothing i guess + case .Foreign_Block_Default: + } - if explicit_calling { - push_generic_token(p, .Open_Paren, 1); - } else { - push_generic_token(p, .Open_Paren, 0); - } + if explicit_calling { + push_generic_token(p, .Open_Paren, 1); + } else { + push_generic_token(p, .Open_Paren, 0); + } - visit_signature_list(p, proc_type.params, false); + visit_signature_list(p, proc_type.params, false); - push_generic_token(p, .Close_Paren, 0); + push_generic_token(p, .Close_Paren, 0); - if proc_type.results != nil { - push_generic_token(p, .Sub, 1); - push_generic_token(p, .Gt, 0); + if proc_type.results != nil { + push_generic_token(p, .Sub, 1); + push_generic_token(p, .Gt, 0); - use_parens := false; - use_named := false; + use_parens := false; + use_named := false; - if len(proc_type.results.list) > 1 { - use_parens = true; - } else if len(proc_type.results.list) == 1 { + if len(proc_type.results.list) > 1 { + use_parens = true; + } else if len(proc_type.results.list) == 1 { - for name in proc_type.results.list[0].names { - if ident, ok := name.derived.(ast.Ident); ok { - if ident.name != "_" { - use_parens = true; - } - } - } - } + for name in proc_type.results.list[0].names { + if ident, ok := name.derived.(ast.Ident); ok { + if ident.name != "_" { + use_parens = true; + } + } + } + } - if use_parens { - push_generic_token(p, .Open_Paren, 1); - visit_signature_list(p, proc_type.results); - push_generic_token(p, .Close_Paren, 0); - } else { - visit_signature_list(p, proc_type.results); - } - } + if use_parens { + push_generic_token(p, .Open_Paren, 1); + visit_signature_list(p, proc_type.results); + push_generic_token(p, .Close_Paren, 0); + } else { + visit_signature_list(p, proc_type.results); + } + } } visit_binary_expr :: proc(p: ^Printer, binary: ast.Binary_Expr) { - move_line(p, binary.left.pos); + move_line(p, binary.left.pos); - if v, ok := binary.left.derived.(ast.Binary_Expr); ok { - visit_binary_expr(p, v); - } else { - visit_expr(p, binary.left); - } + if v, ok := binary.left.derived.(ast.Binary_Expr); ok { + visit_binary_expr(p, v); + } else { + visit_expr(p, binary.left); + } - if binary.op.kind == .Ellipsis || binary.op.kind == .Range_Half { - push_generic_token(p, binary.op.kind, 0); - } else { - push_generic_token(p, binary.op.kind, 1); - } + if binary.op.kind == .Ellipsis || binary.op.kind == .Range_Half { + push_generic_token(p, binary.op.kind, 0); + } else { + push_generic_token(p, binary.op.kind, 1); + } - move_line(p, binary.right.pos); + move_line(p, binary.right.pos); - if v, ok := binary.right.derived.(ast.Binary_Expr); ok { - visit_binary_expr(p, v); - } else { - visit_expr(p, binary.right); - } + if v, ok := binary.right.derived.(ast.Binary_Expr); ok { + visit_binary_expr(p, v); + } else { + visit_expr(p, binary.right); + } } visit_call_exprs :: proc(p: ^Printer, list: [] ^ast.Expr, ellipsis := false) { - if len(list) == 0 { - return; - } + if len(list) == 0 { + return; + } - //all the expression are on the line - if list[0].pos.line == list[len(list) - 1].pos.line { - for expr, i in list { + //all the expression are on the line + if list[0].pos.line == list[len(list) - 1].pos.line { + for expr, i in list { - if i == len(list) - 1 && ellipsis { - push_generic_token(p, .Ellipsis, 0); - } + if i == len(list) - 1 && ellipsis { + push_generic_token(p, .Ellipsis, 0); + } - visit_expr(p, expr); + visit_expr(p, expr); - if i != len(list) - 1 { - push_generic_token(p, .Comma, 0); - } - } - } else { - for expr, i in list { + if i != len(list) - 1 { + push_generic_token(p, .Comma, 0); + } + } + } else { + for expr, i in list { - //we have to newline the expressions to respect the source - move_line_limit(p, expr.pos, 1); + //we have to newline the expressions to respect the source + move_line_limit(p, expr.pos, 1); - if i == len(list) - 1 && ellipsis { - push_generic_token(p, .Ellipsis, 0); - } + if i == len(list) - 1 && ellipsis { + push_generic_token(p, .Ellipsis, 0); + } - visit_expr(p, expr); + visit_expr(p, expr); - if i != len(list) - 1 { - push_generic_token(p, .Comma, 0); - } - } - } + if i != len(list) - 1 { + push_generic_token(p, .Comma, 0); + } + } + } } visit_signature_list :: proc(p: ^Printer, list: ^ast.Field_List, remove_blank := true) { - if list.list == nil { - return; - } + if list.list == nil { + return; + } - for field, i in list.list { + for field, i in list.list { - move_line_limit(p, field.pos, 1); + move_line_limit(p, field.pos, 1); - if .Using in field.flags { - push_generic_token(p, .Using, 0); - } + if .Using in field.flags { + push_generic_token(p, .Using, 0); + } - named := false; + named := false; - for name in field.names { - if ident, ok := name.derived.(ast.Ident); ok { - //for some reason the parser uses _ to mean empty - if ident.name != "_" || !remove_blank { - named = true; - } - } else { - //alternative is poly names - named = true; - } - } + for name in field.names { + if ident, ok := name.derived.(ast.Ident); ok { + //for some reason the parser uses _ to mean empty + if ident.name != "_" || !remove_blank { + named = true; + } + } else { + //alternative is poly names + named = true; + } + } - if named { - visit_exprs(p, field.names, true); + if named { + visit_exprs(p, field.names, true); - if len(field.names) != 0 && field.type != nil { - push_generic_token(p, .Colon, 0); - } - } + if len(field.names) != 0 && field.type != nil { + push_generic_token(p, .Colon, 0); + } + } - if field.type != nil && field.default_value != nil { - visit_expr(p, field.type); - push_generic_token(p, .Eq, 1); - visit_expr(p, field.default_value); - } else if field.type != nil { - visit_expr(p, field.type); - } else { - push_generic_token(p, .Colon, 1); - push_generic_token(p, .Eq, 0); - visit_expr(p, field.default_value); - } + if field.type != nil && field.default_value != nil { + visit_expr(p, field.type); + push_generic_token(p, .Eq, 1); + visit_expr(p, field.default_value); + } else if field.type != nil { + visit_expr(p, field.type); + } else { + push_generic_token(p, .Colon, 1); + push_generic_token(p, .Eq, 0); + visit_expr(p, field.default_value); + } - if i != len(list.list) - 1 { - push_generic_token(p, .Comma, 0); - } - } + if i != len(list.list) - 1 { + push_generic_token(p, .Comma, 0); + } + } } \ No newline at end of file From f17fc05ff2431962572bd0fc2ebdc1207251c261 Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Fri, 16 Apr 2021 00:44:16 +0200 Subject: [PATCH 23/49] format call and binary expression --- core/odin/printer/printer.odin | 208 ++++++++++++++++++++++++++++----- core/odin/printer/visit.odin | 53 ++++++--- 2 files changed, 214 insertions(+), 47 deletions(-) diff --git a/core/odin/printer/printer.odin b/core/odin/printer/printer.odin index 3db48662c..98a7e9ade 100644 --- a/core/odin/printer/printer.odin +++ b/core/odin/printer/printer.odin @@ -8,12 +8,12 @@ import "core:fmt" import "core:unicode/utf8" import "core:mem" -Line_Type_Enum :: enum {Line_Comment, Value_Decl, Switch_Stmt, Struct} +Type_Enum :: enum {Line_Comment, Value_Decl, Switch_Stmt, Struct, Assign, Call, Enum} -Line_Type :: bit_set[Line_Type_Enum]; +Line_Type :: bit_set[Type_Enum]; Line :: struct { - format_tokens: [dynamic] Format_Token, + format_tokens: [dynamic]Format_Token, finalized: bool, used: bool, depth: int, @@ -23,6 +23,7 @@ Line :: struct { Format_Token :: struct { kind: tokenizer.Token_Kind, text: string, + type: Type_Enum, spaces_before: int, parameter_count: int, } @@ -31,13 +32,13 @@ Printer :: struct { string_builder: strings.Builder, config: Config, depth: int, //the identation depth - comments: [dynamic] ^ast.Comment_Group, + comments: [dynamic]^ast.Comment_Group, latest_comment_index: int, allocator: mem.Allocator, file: ^ast.File, source_position: tokenizer.Pos, last_source_position: tokenizer.Pos, - lines: [dynamic] Line, //need to look into a better data structure, one that can handle inserting lines rather than appending + 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, @@ -119,7 +120,7 @@ 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); + 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); @@ -188,15 +189,182 @@ print :: proc(p: ^Printer, file: ^ast.File) -> string { } fix_lines :: proc(p: ^Printer) { - align_var_decls(p); - align_blocks(p); + align_var_decls_and_assignments(p); + format_generic(p); align_comments(p); //align them last since they rely on the other alignments } -align_var_decls :: proc(p: ^Printer) { +format_value_decl :: proc(p: ^Printer, index: int) { + + eq_found := false; + eq_token: Format_Token; + eq_line: int; + largest := 0; + + found_eq: for line, line_index in p.lines[index:] { + for format_token in line.format_tokens { + + largest += len(format_token.text) + format_token.spaces_before; + + if format_token.kind == .Eq { + eq_token = format_token; + eq_line = line_index + index; + eq_found = true; + break found_eq; + } + } + } + + if !eq_found { + return; + } + + align_next := false; + + //check to see if there is a binary operator in the last token(this is guaranteed by the ast visit), otherwise it's not multilined + for line, line_index in p.lines[eq_line:] { + + if len(line.format_tokens) == 0 { + break; + } + + if align_next { + line.format_tokens[0].spaces_before += largest + 1; + align_next = false; + } + + kind := find_last_token(line.format_tokens).kind; + + if tokenizer.Token_Kind.B_Operator_Begin < kind && kind <= tokenizer.Token_Kind.Cmp_Or { + align_next = true; + } + + if !align_next { + break; + } + + } + } -align_switch_smt :: proc(p: ^Printer, index: int) { +find_last_token :: proc(format_tokens: [dynamic]Format_Token) -> Format_Token { + + for i := len(format_tokens)-1; i >= 0; i -= 1 { + + if format_tokens[i].kind != .Comment { + return format_tokens[i]; + } + + } + + panic("not possible"); +} + +format_assignment :: proc(p: ^Printer, index: int) { + +} + +format_call :: proc(p: ^Printer, index: int) { + + paren_found := false; + paren_token: Format_Token; + paren_line: int; + largest := 0; + + found_paren: for line, line_index in p.lines[index:] { + for format_token in line.format_tokens { + + largest += len(format_token.text) + format_token.spaces_before; + + if format_token.kind == .Open_Paren && format_token.type == .Call { + paren_token = format_token; + paren_line = line_index + index; + paren_found = true; + break found_paren; + } else if format_token.kind == .Open_Paren { + return; + } + } + } + + if !paren_found { + return; + } + + paren_count := 1; + done := false; + + for line, line_index in p.lines[paren_line+1:] { + + if len(line.format_tokens) == 0 { + continue; + } + + for format_token, i in line.format_tokens { + + if format_token.kind == .Open_Paren { + paren_count += 1; + } else if format_token.kind == .Close_Paren { + paren_count -= 1; + } + + if paren_count == 0 { + done = true; + } + + } + + line.format_tokens[0].spaces_before += largest; + + if done { + return; + } + + + } + + + +} + +format_generic :: proc(p: ^Printer) { + + for line, line_index in p.lines { + + if len(line.format_tokens) <= 0 { + continue; + } + + if .Switch_Stmt in line.types && p.config.align_switch { + align_switch_stmt(p, line_index); + } + + if .Struct in line.types && p.config.align_structs { + align_struct(p, line_index); + } + + if .Value_Decl in line.types { + format_value_decl(p, line_index); + } + + if .Assign in line.types { + format_assignment(p, line_index); + } + + if .Call in line.types { + format_call(p, line_index); + } + } +} + +align_var_decls_and_assignments :: proc(p: ^Printer) { + + + + +} + +align_switch_stmt :: proc(p: ^Printer, index: int) { switch_found := false; brace_token: Format_Token; @@ -375,24 +543,6 @@ align_struct :: proc(p: ^Printer, index: int) { } } -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 && p.config.align_switch { - align_switch_smt(p, line_index); - } - - if .Struct in line.types && p.config.align_structs { - align_struct(p, line_index); - } - } -} - align_comments :: proc(p: ^Printer) { Comment_Align_Info :: struct { @@ -402,7 +552,7 @@ align_comments :: proc(p: ^Printer) { depth: int, }; - comment_infos := make([dynamic] Comment_Align_Info, 0, context.temp_allocator); + comment_infos := make([dynamic]Comment_Align_Info, 0, context.temp_allocator); current_info: Comment_Align_Info; diff --git a/core/odin/printer/visit.odin b/core/odin/printer/visit.odin index ae3097f03..d8ec98e17 100644 --- a/core/odin/printer/visit.odin +++ b/core/odin/printer/visit.odin @@ -11,19 +11,19 @@ import "core:sort" //right the attribute order is not linearly parsed(bug?) @(private) -sort_attribute :: proc(s: ^[dynamic] ^ast.Attribute) -> sort.Interface { +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); + s := (^[dynamic]^ast.Attribute)(it.collection); return len(s^); }, less = proc(it: sort.Interface, i, j: int) -> bool { - s := (^[dynamic] ^ast.Attribute)(it.collection); + 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 := (^[dynamic]^ast.Attribute)(it.collection); s[i], s[j] = s[j], s[i]; }, }; @@ -72,7 +72,7 @@ push_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}); + hint_current_line(p, {.Line_Comment}); return 0; } else { @@ -82,7 +82,7 @@ push_comment :: proc(p: ^Printer, comment: tokenizer.Token) -> int { c_len := len(comment.text); trim_space := true; - multilines: [dynamic] string; + multilines: [dynamic]string; for i := 0; i < len(comment.text); i += 1 { @@ -185,7 +185,7 @@ push_comments :: proc(p: ^Printer, pos: tokenizer.Pos) { } if prev_comment != nil { - newline_position(p, min(p.config.newline_limit, p.source_position.line - prev_comment.pos.line)); + newline_position(p, min(p.config.newline_limit, p.source_position.line - prev_comment.pos.line - prev_comment_lines)); } } @@ -303,7 +303,7 @@ set_line :: proc(p: ^Printer, line: int) -> ^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); + new_line.format_tokens = make([dynamic]Format_Token, 0, 50, p.allocator); append(&p.lines, new_line); } unwrapped_line = &p.lines[line]; @@ -427,18 +427,20 @@ visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) { visit_exprs(p, v.names, true); if v.type != nil { - if !v.is_mutable && v.type != nil { + if !v.is_mutable { push_generic_token(p, .Colon, 0); } else { + hint_current_line(p, {.Value_Decl}); push_generic_token(p, .Colon, 0); } visit_expr(p, v.type); } else { - if !v.is_mutable && v.type == nil { + if !v.is_mutable { push_generic_token(p, .Colon, 1); push_generic_token(p, .Colon, 0); } else { + hint_current_line(p, {.Value_Decl}); push_generic_token(p, .Colon, 1); } } @@ -472,7 +474,7 @@ visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) { } @(private) -visit_exprs :: proc(p: ^Printer, list: [] ^ast.Expr, add_comma := false, trailing := false) { +visit_exprs :: proc(p: ^Printer, list: []^ast.Expr, add_comma := false, trailing := false) { if len(list) == 0 { return; @@ -492,7 +494,7 @@ visit_exprs :: proc(p: ^Printer, list: [] ^ast.Expr, add_comma := false, trailin } @(private) -visit_attributes :: proc(p: ^Printer, attributes: [dynamic] ^ast.Attribute) { +visit_attributes :: proc(p: ^Printer, attributes: [dynamic]^ast.Attribute) { if len(attributes) == 0 { return; @@ -637,7 +639,7 @@ 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}); + hint_current_line(p, {.Switch_Stmt}); if v.init != nil { p.skip_semicolon = true; @@ -694,6 +696,8 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener case Assign_Stmt: move_line(p, v.pos); + hint_current_line(p, {.Assign}); + visit_exprs(p, v.lhs, true); push_generic_token(p, v.op.kind, 1); @@ -730,11 +734,13 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener } if v.cond != nil { + move_line(p, v.cond.pos); visit_expr(p, v.cond); } if v.post != nil { push_generic_token(p, .Semicolon, 0); + move_line(p, v.post.pos); visit_stmt(p, v.post); } else if v.post == nil && v.cond != nil && v.init != nil { push_generic_token(p, .Semicolon, 0); @@ -946,6 +952,7 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr) { push_generic_token(p, .Open_Bracket, 1); push_generic_token(p, .Dynamic, 0); push_generic_token(p, .Close_Bracket, 0); + merge_next_token(p); visit_expr(p, v.elem); case Bit_Set_Type: push_generic_token(p, .Bit_Set, 1); @@ -1012,7 +1019,7 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr) { case Struct_Type: push_generic_token(p, .Struct, 1); - hint_current_line(p,{.Struct}); + hint_current_line(p, {.Struct}); if v.is_packed { push_ident_token(p, "#packed", 1); @@ -1083,7 +1090,15 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr) { push_ident_token(p, v.field.name, 0); case Call_Expr: visit_expr(p, v.expr); - push_generic_token(p, .Open_Paren, 0); + + push_format_token(p, Format_Token { + kind = .Open_Paren, + type = .Call, + text = "(", + }); + + hint_current_line(p, {.Call}); + visit_call_exprs(p, v.args, v.ellipsis.kind == .Ellipsis); push_generic_token(p, .Close_Paren, 0); case Typeid_Type: @@ -1135,7 +1150,7 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr) { visit_exprs(p, v.elems, true, true); visit_end_brace(p, v.end); } else { - push_generic_token(p, .Open_Brace, 0); + push_generic_token(p, .Open_Brace, 1); visit_exprs(p, v.elems, true); push_generic_token(p, .Close_Brace, 0); } @@ -1182,12 +1197,14 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr) { push_generic_token(p, .Open_Bracket, 1); visit_expr(p, v.len); push_generic_token(p, .Close_Bracket, 0); + merge_next_token(p); visit_expr(p, v.elem); case Map_Type: push_generic_token(p, .Map, 1); push_generic_token(p, .Open_Bracket, 0); visit_expr(p, v.key); push_generic_token(p, .Close_Bracket, 0); + merge_next_token(p); visit_expr(p, v.value); case Helper_Type: visit_expr(p, v.type); @@ -1229,7 +1246,7 @@ visit_end_brace :: proc(p: ^Printer, end: tokenizer.Pos) { p.current_line.depth = p.depth; } -visit_block_stmts :: proc(p: ^Printer, stmts: [] ^ast.Stmt, split := false) { +visit_block_stmts :: proc(p: ^Printer, stmts: []^ast.Stmt, split := false) { for stmt, i in stmts { visit_stmt(p, stmt, .Generic, false, true); @@ -1370,7 +1387,7 @@ visit_binary_expr :: proc(p: ^Printer, binary: ast.Binary_Expr) { } } -visit_call_exprs :: proc(p: ^Printer, list: [] ^ast.Expr, ellipsis := false) { +visit_call_exprs :: proc(p: ^Printer, list: []^ast.Expr, ellipsis := false) { if len(list) == 0 { return; From 5a8c7b4f90a3f48ed2bbd574cac0b38862e4742d Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Fri, 16 Apr 2021 02:15:29 +0200 Subject: [PATCH 24/49] support multiline for and if --- core/odin/printer/printer.odin | 131 ++++++++++++++++++++++++++++++++- core/odin/printer/visit.odin | 9 +++ 2 files changed, 137 insertions(+), 3 deletions(-) diff --git a/core/odin/printer/printer.odin b/core/odin/printer/printer.odin index 98a7e9ade..700d9ef63 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" -Type_Enum :: enum {Line_Comment, Value_Decl, Switch_Stmt, Struct, Assign, Call, Enum} +Type_Enum :: enum {Line_Comment, Value_Decl, Switch_Stmt, Struct, Assign, Call, Enum, If, For} Line_Type :: bit_set[Type_Enum]; @@ -320,13 +320,130 @@ format_call :: proc(p: ^Printer, index: int) { return; } + } +} + +format_for :: proc(p: ^Printer, index: int) { + + for_found := false; + for_token: Format_Token; + for_line: int; + largest := 0; + + found_for: for line, line_index in p.lines[index:] { + for format_token in line.format_tokens { + + largest += len(format_token.text) + format_token.spaces_before; + + if format_token.kind == .For { + for_token = format_token; + for_line = line_index + index; + for_found = true; + break found_for; + } + } + } + + if !for_found { + return; + } + + brace_count := 0; + done := false; + + for line, line_index in p.lines[for_line:] { + + if len(line.format_tokens) == 0 { + continue; + } + + for format_token, i in line.format_tokens { + + if format_token.kind == .Open_Brace { + brace_count += 1; + } else if format_token.kind == .Close_Brace { + brace_count -= 1; + } + + if brace_count == 1 { + done = true; + } + + } + + if line_index != 0 { + line.format_tokens[0].spaces_before += largest + 1; + } + + if done { + return; + } + + } + +} + +format_if :: proc(p: ^Printer, index: int) { + + if_found := false; + if_token: Format_Token; + if_line: int; + largest := 0; + + found_if: for line, line_index in p.lines[index:] { + for format_token in line.format_tokens { + + largest += len(format_token.text) + format_token.spaces_before; + + if format_token.kind == .If { + if_token = format_token; + if_line = line_index + index; + if_found = true; + break found_if; + } + } + } + + if !if_found { + return; + } + + brace_count := 0; + done := false; + + for line, line_index in p.lines[if_line:] { + + if len(line.format_tokens) == 0 { + continue; + } + + for format_token, i in line.format_tokens { + + if format_token.kind == .Open_Brace { + brace_count += 1; + } else if format_token.kind == .Close_Brace { + brace_count -= 1; + } + + if brace_count == 1 { + done = true; + } + + } + + if line_index != 0 { + line.format_tokens[0].spaces_before += largest + 1; + } + + if done { + break; + } } - - } + format_generic :: proc(p: ^Printer) { for line, line_index in p.lines { @@ -354,6 +471,14 @@ format_generic :: proc(p: ^Printer) { if .Call in line.types { format_call(p, line_index); } + + if .If in line.types { + format_if(p, line_index); + } + + if .For in line.types { + format_for(p, line_index); + } } } diff --git a/core/odin/printer/visit.odin b/core/odin/printer/visit.odin index d8ec98e17..36c8c42d9 100644 --- a/core/odin/printer/visit.odin +++ b/core/odin/printer/visit.odin @@ -587,6 +587,8 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener push_generic_token(p, .If, 1); + hint_current_line(p, {.If}); + if v.init != nil { p.skip_semicolon = true; visit_stmt(p, v.init); @@ -724,6 +726,8 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener push_generic_token(p, .For, 1); + hint_current_line(p, {.For}); + if v.init != nil { p.skip_semicolon = true; visit_stmt(p, v.init); @@ -759,6 +763,9 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener push_ident_token(p, "#unroll", 0); push_generic_token(p, .For, 1); + + hint_current_line(p, {.For}); + visit_expr(p, v.val0); if v.val1 != nil { @@ -781,6 +788,8 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener push_generic_token(p, .For, 1); + hint_current_line(p, {.For}); + if len(v.vals) >= 1 { visit_expr(p, v.vals[0]); } From a72180233709e47197bc6c737f18e9464e661d5d Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Sun, 18 Apr 2021 21:07:58 +0200 Subject: [PATCH 25/49] fixing calls in calls --- core/odin/printer/printer.odin | 170 ++++++++++++--------------------- 1 file changed, 59 insertions(+), 111 deletions(-) diff --git a/core/odin/printer/printer.odin b/core/odin/printer/printer.odin index 700d9ef63..ad17a63c4 100644 --- a/core/odin/printer/printer.odin +++ b/core/odin/printer/printer.odin @@ -229,7 +229,7 @@ format_value_decl :: proc(p: ^Printer, index: int) { } if align_next { - line.format_tokens[0].spaces_before += largest + 1; + line.format_tokens[0].spaces_before = largest + 1; align_next = false; } @@ -264,37 +264,41 @@ format_assignment :: proc(p: ^Printer, index: int) { } -format_call :: proc(p: ^Printer, index: int) { +format_call :: proc(p: ^Printer, line_index: int, format_index: int) { paren_found := false; paren_token: Format_Token; paren_line: int; + paren_token_index: int; largest := 0; - found_paren: for line, line_index in p.lines[index:] { - for format_token in line.format_tokens { + found_paren: for line, i in p.lines[line_index:] { + for format_token, j in line.format_tokens { largest += len(format_token.text) + format_token.spaces_before; + if i == 0 && j < format_index { + continue; + } + if format_token.kind == .Open_Paren && format_token.type == .Call { paren_token = format_token; - paren_line = line_index + index; + paren_line = line_index + i; paren_found = true; + paren_token_index = j; break found_paren; - } else if format_token.kind == .Open_Paren { - return; - } + } } } if !paren_found { - return; + panic("Should not be possible");; } paren_count := 1; done := false; - for line, line_index in p.lines[paren_line+1:] { + for line, line_index in p.lines[paren_line:] { if len(line.format_tokens) == 0 { continue; @@ -302,6 +306,10 @@ format_call :: proc(p: ^Printer, index: int) { for format_token, i in line.format_tokens { + if line_index == 0 && i <= paren_token_index { + continue; + } + if format_token.kind == .Open_Paren { paren_count += 1; } else if format_token.kind == .Close_Paren { @@ -314,44 +322,45 @@ format_call :: proc(p: ^Printer, index: int) { } - line.format_tokens[0].spaces_before += largest; + if line_index != 0 { + line.format_tokens[0].spaces_before = largest; + } if done { return; } - } } -format_for :: proc(p: ^Printer, index: int) { +format_keyword_to_brace :: proc(p: ^Printer, line_index: int, format_index: int, keyword: tokenizer.Token_Kind) { - for_found := false; - for_token: Format_Token; - for_line: int; + keyword_found := false; + keyword_token: Format_Token; + keyword_line: int; largest := 0; - found_for: for line, line_index in p.lines[index:] { - for format_token in line.format_tokens { - - largest += len(format_token.text) + format_token.spaces_before; - - if format_token.kind == .For { - for_token = format_token; - for_line = line_index + index; - for_found = true; - break found_for; - } - } - } - - if !for_found { - return; - } - brace_count := 0; done := false; - for line, line_index in p.lines[for_line:] { + found_keyword: for line, i in p.lines[line_index:] { + for format_token in line.format_tokens { + + largest += len(format_token.text) + format_token.spaces_before; + + if format_token.kind == keyword { + keyword_token = format_token; + keyword_line = line_index + i; + keyword_found = true; + break found_keyword; + } + } + } + + if !keyword_found { + panic("Should not be possible"); + } + + for line, line_index in p.lines[keyword_line:] { if len(line.format_tokens) == 0 { continue; @@ -372,7 +381,7 @@ format_for :: proc(p: ^Printer, index: int) { } if line_index != 0 { - line.format_tokens[0].spaces_before += largest + 1; + line.format_tokens[0].spaces_before = largest + 1; } if done { @@ -383,67 +392,6 @@ format_for :: proc(p: ^Printer, index: int) { } -format_if :: proc(p: ^Printer, index: int) { - - if_found := false; - if_token: Format_Token; - if_line: int; - largest := 0; - - found_if: for line, line_index in p.lines[index:] { - for format_token in line.format_tokens { - - largest += len(format_token.text) + format_token.spaces_before; - - if format_token.kind == .If { - if_token = format_token; - if_line = line_index + index; - if_found = true; - break found_if; - } - } - } - - if !if_found { - return; - } - - brace_count := 0; - done := false; - - for line, line_index in p.lines[if_line:] { - - if len(line.format_tokens) == 0 { - continue; - } - - for format_token, i in line.format_tokens { - - if format_token.kind == .Open_Brace { - brace_count += 1; - } else if format_token.kind == .Close_Brace { - brace_count -= 1; - } - - if brace_count == 1 { - done = true; - } - - } - - if line_index != 0 { - line.format_tokens[0].spaces_before += largest + 1; - } - - if done { - break; - } - - } - -} - - format_generic :: proc(p: ^Printer) { for line, line_index in p.lines { @@ -452,6 +400,17 @@ format_generic :: proc(p: ^Printer) { continue; } + for format_token, token_index in line.format_tokens { + + if format_token.kind == .For || format_token.kind == .If + || format_token.kind == .When || format_token.kind == .Switch { + format_keyword_to_brace(p, line_index, token_index, format_token.kind); + } else if format_token.type == .Call { + format_call(p, line_index, token_index); + } + + } + if .Switch_Stmt in line.types && p.config.align_switch { align_switch_stmt(p, line_index); } @@ -468,17 +427,6 @@ format_generic :: proc(p: ^Printer) { format_assignment(p, line_index); } - if .Call in line.types { - format_call(p, line_index); - } - - if .If in line.types { - format_if(p, line_index); - } - - if .For in line.types { - format_for(p, line_index); - } } } @@ -568,7 +516,7 @@ align_switch_stmt :: proc(p: ^Printer, index: int) { //this will only happen if the case is one lined if case_found && colon_found { - line.format_tokens[i].spaces_before += (largest - length); + line.format_tokens[i].spaces_before = (largest - length); break; } @@ -736,9 +684,9 @@ align_comments :: proc(p: ^Printer) { if format_token.kind == .Comment { if len(l.format_tokens) == 1 { - l.format_tokens[i].spaces_before += info.length + 1; + l.format_tokens[i].spaces_before = info.length + 1; } else { - l.format_tokens[i].spaces_before += info.length - length; + l.format_tokens[i].spaces_before = info.length - length + 1; } } From 11bd518f36fecf24d69443b257e369bd986645b7 Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Sun, 18 Apr 2021 21:52:00 +0200 Subject: [PATCH 26/49] fix bugs --- core/odin/printer/printer.odin | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/core/odin/printer/printer.odin b/core/odin/printer/printer.odin index ad17a63c4..bd77e9b7c 100644 --- a/core/odin/printer/printer.odin +++ b/core/odin/printer/printer.odin @@ -306,6 +306,10 @@ format_call :: proc(p: ^Printer, line_index: int, format_index: int) { for format_token, i in line.format_tokens { + if format_token.kind == .Comment { + continue; + } + if line_index == 0 && i <= paren_token_index { continue; } @@ -368,6 +372,14 @@ format_keyword_to_brace :: proc(p: ^Printer, line_index: int, format_index: int, for format_token, i in line.format_tokens { + if format_token.kind == .Comment { + continue; + } + + if line_index == 0 && i <= format_index { + continue; + } + if format_token.kind == .Open_Brace { brace_count += 1; } else if format_token.kind == .Close_Brace { From 2cbb3443d3051bea25dff8b1028c5ec6f71f3c0f Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Sun, 18 Apr 2021 21:53:52 +0200 Subject: [PATCH 27/49] ran odinfmt --- core/odin/printer/printer.odin | 38 +++++++++++----------------------- core/odin/printer/visit.odin | 12 +++++------ 2 files changed, 18 insertions(+), 32 deletions(-) diff --git a/core/odin/printer/printer.odin b/core/odin/printer/printer.odin index bd77e9b7c..928c0e07d 100644 --- a/core/odin/printer/printer.odin +++ b/core/odin/printer/printer.odin @@ -211,7 +211,7 @@ format_value_decl :: proc(p: ^Printer, index: int) { eq_line = line_index + index; eq_found = true; break found_eq; - } + } } } @@ -233,7 +233,7 @@ format_value_decl :: proc(p: ^Printer, index: int) { align_next = false; } - kind := find_last_token(line.format_tokens).kind; + kind := find_last_token(line.format_tokens).kind; if tokenizer.Token_Kind.B_Operator_Begin < kind && kind <= tokenizer.Token_Kind.Cmp_Or { align_next = true; @@ -242,26 +242,22 @@ format_value_decl :: proc(p: ^Printer, index: int) { if !align_next { break; } - } - } find_last_token :: proc(format_tokens: [dynamic]Format_Token) -> Format_Token { - for i := len(format_tokens)-1; i >= 0; i -= 1 { + for i := len(format_tokens) - 1; i >= 0; i -= 1 { if format_tokens[i].kind != .Comment { return format_tokens[i]; } - } panic("not possible"); } format_assignment :: proc(p: ^Printer, index: int) { - } format_call :: proc(p: ^Printer, line_index: int, format_index: int) { @@ -287,12 +283,12 @@ format_call :: proc(p: ^Printer, line_index: int, format_index: int) { paren_found = true; paren_token_index = j; break found_paren; - } + } } } if !paren_found { - panic("Should not be possible");; + panic("Should not be possible"); } paren_count := 1; @@ -305,7 +301,7 @@ format_call :: proc(p: ^Printer, line_index: int, format_index: int) { } for format_token, i in line.format_tokens { - + if format_token.kind == .Comment { continue; } @@ -323,7 +319,6 @@ format_call :: proc(p: ^Printer, line_index: int, format_index: int) { if paren_count == 0 { done = true; } - } if line_index != 0 { @@ -356,7 +351,7 @@ format_keyword_to_brace :: proc(p: ^Printer, line_index: int, format_index: int, keyword_line = line_index + i; keyword_found = true; break found_keyword; - } + } } } @@ -371,7 +366,7 @@ format_keyword_to_brace :: proc(p: ^Printer, line_index: int, format_index: int, } for format_token, i in line.format_tokens { - + if format_token.kind == .Comment { continue; } @@ -389,7 +384,6 @@ format_keyword_to_brace :: proc(p: ^Printer, line_index: int, format_index: int, if brace_count == 1 { done = true; } - } if line_index != 0 { @@ -399,9 +393,7 @@ format_keyword_to_brace :: proc(p: ^Printer, line_index: int, format_index: int, if done { return; } - } - } format_generic :: proc(p: ^Printer) { @@ -414,13 +406,12 @@ format_generic :: proc(p: ^Printer) { for format_token, token_index in line.format_tokens { - if format_token.kind == .For || format_token.kind == .If - || format_token.kind == .When || format_token.kind == .Switch { + if format_token.kind == .For || format_token.kind == .If || + format_token.kind == .When || format_token.kind == .Switch { format_keyword_to_brace(p, line_index, token_index, format_token.kind); } else if format_token.type == .Call { format_call(p, line_index, token_index); } - } if .Switch_Stmt in line.types && p.config.align_switch { @@ -438,15 +429,10 @@ format_generic :: proc(p: ^Printer) { if .Assign in line.types { format_assignment(p, line_index); } - } } - + align_var_decls_and_assignments :: proc(p: ^Printer) { - - - - } align_switch_stmt :: proc(p: ^Printer, index: int) { @@ -650,7 +636,7 @@ align_comments :: proc(p: ^Printer) { if .Line_Comment in line.types { if current_info.end + 1 != line_index || current_info.depth != line.depth || - (current_info.begin == current_info.end && current_info.length == 0) { + (current_info.begin == current_info.end && current_info.length == 0) { if (current_info.begin != 0 && current_info.end != 0) || current_info.length > 0 { append(&comment_infos, current_info); diff --git a/core/odin/printer/visit.odin b/core/odin/printer/visit.odin index 36c8c42d9..b1b1d2693 100644 --- a/core/odin/printer/visit.odin +++ b/core/odin/printer/visit.odin @@ -195,8 +195,8 @@ append_format_token :: proc(p: ^Printer, format_token: Format_Token) -> ^Format_ format_token := format_token; if p.last_token != nil && (p.last_token.kind == .Ellipsis || p.last_token.kind == .Range_Half || - p.last_token.kind == .Open_Paren || p.last_token.kind == .Period || - p.last_token.kind == .Open_Brace || p.last_token.kind == .Open_Bracket) { + p.last_token.kind == .Open_Paren || p.last_token.kind == .Period || + p.last_token.kind == .Open_Brace || p.last_token.kind == .Open_Bracket) { format_token.spaces_before = 0; } else if p.merge_next_token { format_token.spaces_before = 0; @@ -1101,10 +1101,10 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr) { visit_expr(p, v.expr); push_format_token(p, Format_Token { - kind = .Open_Paren, - type = .Call, - text = "(", - }); + kind = .Open_Paren, + type = .Call, + text = "(", + }); hint_current_line(p, {.Call}); From f7b8b3a3400a28c4f35a6e10885bb0f0142441c8 Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Sun, 18 Apr 2021 22:06:32 +0200 Subject: [PATCH 28/49] ensure that the comments gets pushed if it's in the beginning before package --- core/odin/printer/printer.odin | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/odin/printer/printer.odin b/core/odin/printer/printer.odin index 928c0e07d..600f0bfe3 100644 --- a/core/odin/printer/printer.odin +++ b/core/odin/printer/printer.odin @@ -123,6 +123,8 @@ print :: proc(p: ^Printer, file: ^ast.File) -> string { p.lines = make([dynamic]Line, 0, (file.decls[len(file.decls) - 1].end.line - file.decls[0].pos.line) * 2, context.temp_allocator); } + set_source_position(p, file.pkg_token.pos); + set_line(p, 0); push_generic_token(p, .Package, 0); @@ -514,7 +516,7 @@ align_switch_stmt :: proc(p: ^Printer, index: int) { //this will only happen if the case is one lined if case_found && colon_found { - line.format_tokens[i].spaces_before = (largest - length); + line.format_tokens[i].spaces_before = (largest - length) + 1; break; } From f1dc7c0b27f95df8999b6b12c5284476dc0bc64d Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Mon, 19 Apr 2021 19:38:08 +0200 Subject: [PATCH 29/49] more work --- core/odin/printer/printer.odin | 4 ++++ core/odin/printer/visit.odin | 8 +++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/core/odin/printer/printer.odin b/core/odin/printer/printer.odin index 600f0bfe3..c972be019 100644 --- a/core/odin/printer/printer.odin +++ b/core/odin/printer/printer.odin @@ -124,6 +124,8 @@ print :: proc(p: ^Printer, file: ^ast.File) -> string { } set_source_position(p, file.pkg_token.pos); + + p.last_source_position.line = 1; set_line(p, 0); @@ -187,6 +189,8 @@ print :: proc(p: ^Printer, file: ^ast.File) -> string { last_line = line_index; } + strings.write_string(&builder, newline); + return strings.to_string(builder); } diff --git a/core/odin/printer/visit.odin b/core/odin/printer/visit.odin index b1b1d2693..953e0951f 100644 --- a/core/odin/printer/visit.odin +++ b/core/odin/printer/visit.odin @@ -106,10 +106,8 @@ push_comment :: proc(p: ^Printer, comment: tokenizer.Token) -> int { } else if c == '/' && comment.text[min(c_len - 1, i + 1)] == '*' { strings.write_string(&builder, "/*"); trim_space = true; - p.depth += 1; i += 1; } else if c == '*' && comment.text[min(c_len - 1, i + 1)] == '/' { - p.depth -= 1; trim_space = true; strings.write_string(&builder, "*/"); i += 1; @@ -453,7 +451,11 @@ visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) { push_generic_token(p, .Colon, 0); } - visit_exprs(p, v.values, true); + if len(v.values) == 1 { + visit_expr(p, v.values[0]); //this is too ensure that one value are never newlined(procs, structs, etc.) + } else { + visit_exprs(p, v.values, true); + } add_semicolon := true; From 3464784e5eb5186b9eb2f3145f127095d0830c2f Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Mon, 19 Apr 2021 19:41:53 +0200 Subject: [PATCH 30/49] add proc to format multiline --- core/odin/printer/printer.odin | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/odin/printer/printer.odin b/core/odin/printer/printer.odin index c972be019..b7c87f111 100644 --- a/core/odin/printer/printer.odin +++ b/core/odin/printer/printer.odin @@ -413,7 +413,8 @@ format_generic :: proc(p: ^Printer) { for format_token, token_index in line.format_tokens { if format_token.kind == .For || format_token.kind == .If || - format_token.kind == .When || format_token.kind == .Switch { + format_token.kind == .When || format_token.kind == .Switch || + format_token.kind == .Proc { format_keyword_to_brace(p, line_index, token_index, format_token.kind); } else if format_token.type == .Call { format_call(p, line_index, token_index); From 25c3b6dc95847d530b8856478a2437ec17db698f Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Wed, 21 Apr 2021 23:21:45 +0200 Subject: [PATCH 31/49] align value decls --- core/odin/printer/printer.odin | 132 ++++++++++++++++++++++++++++++++- core/odin/printer/visit.odin | 13 +++- 2 files changed, 139 insertions(+), 6 deletions(-) diff --git a/core/odin/printer/printer.odin b/core/odin/printer/printer.odin index b7c87f111..0da6a9b38 100644 --- a/core/odin/printer/printer.odin +++ b/core/odin/printer/printer.odin @@ -124,7 +124,7 @@ print :: proc(p: ^Printer, file: ^ast.File) -> string { } set_source_position(p, file.pkg_token.pos); - + p.last_source_position.line = 1; set_line(p, 0); @@ -195,7 +195,7 @@ print :: proc(p: ^Printer, file: ^ast.File) -> string { } fix_lines :: proc(p: ^Printer) { - align_var_decls_and_assignments(p); + align_var_decls(p); format_generic(p); align_comments(p); //align them last since they rely on the other alignments } @@ -439,7 +439,131 @@ format_generic :: proc(p: ^Printer) { } } -align_var_decls_and_assignments :: proc(p: ^Printer) { +align_var_decls :: proc(p: ^Printer) { + + current_line: int; + current_typed: bool; + + largest_lhs := 0; + largest_rhs := 0; + + TokenAndLength :: struct { + format_token: ^Format_Token, + length: int, + }; + + colon_tokens := make([dynamic]TokenAndLength, 0, 10, context.temp_allocator); + type_tokens := make([dynamic]TokenAndLength, 0, 10, context.temp_allocator); + equal_tokens := make([dynamic]TokenAndLength, 0, 10, context.temp_allocator); + + for line, line_index in p.lines { + + //It is only possible to align value decls that are one one line, otherwise just ignore them + if .Value_Decl not_in line.types { + continue; + } + + typed := true; + + for i := 0; i < len(line.format_tokens) - 1; i += 1 { + if line.format_tokens[i].kind == .Colon && line.format_tokens[i + 1].kind == .Eq { + typed = false; + break; + } + } + + if line_index != current_line + 1 || typed != current_typed { + + if p.config.align_style == .Align_On_Colon_And_Equals || !current_typed { + for colon_token in colon_tokens { + colon_token.format_token.spaces_before = largest_lhs - colon_token.length + 1; + } + } else if p.config.align_style == .Align_On_Type_And_Equals { + for type_token in type_tokens { + type_token.format_token.spaces_before = largest_lhs - type_token.length + 1; + } + } + + if current_typed { + for equal_token in equal_tokens { + equal_token.format_token.spaces_before = largest_rhs - equal_token.length + 1; + } + } else { + for equal_token in equal_tokens { + equal_token.format_token.spaces_before = 0; + } + } + + clear(&colon_tokens); + clear(&type_tokens); + clear(&equal_tokens); + + largest_rhs = 0; + largest_lhs = 0; + current_typed = typed; + } + + current_line = line_index; + + current_token_index := 0; + lhs_length := 0; + rhs_length := 0; + + //calcuate the length of lhs of a value decl i.e. `a, b:` + for; current_token_index < len(line.format_tokens); current_token_index += 1 { + + lhs_length += len(line.format_tokens[current_token_index].text) + line.format_tokens[current_token_index].spaces_before; + + if line.format_tokens[current_token_index].kind == .Colon { + append(&colon_tokens, TokenAndLength {format_token = &line.format_tokens[current_token_index], length = lhs_length}); + + if len(line.format_tokens) > current_token_index && line.format_tokens[current_token_index + 1].kind != .Eq { + append(&type_tokens, TokenAndLength {format_token = &line.format_tokens[current_token_index + 1], length = lhs_length}); + } + + current_token_index += 1; + + break; + } + } + + //calcuate the length of the rhs i.e. `[dynamic]int = 123123` + for; current_token_index < len(line.format_tokens); current_token_index += 1 { + + rhs_length += len(line.format_tokens[current_token_index].text) + line.format_tokens[current_token_index].spaces_before; + + if line.format_tokens[current_token_index].kind == .Eq { + append(&equal_tokens, TokenAndLength {format_token = &line.format_tokens[current_token_index], length = rhs_length}); + break; + } + } + + largest_lhs = max(largest_lhs, lhs_length); + largest_rhs = max(largest_rhs, rhs_length); + } + + fmt.println(current_typed); + + //repeating myself, move to sub procedure + if p.config.align_style == .Align_On_Colon_And_Equals || !current_typed { + for colon_token in colon_tokens { + colon_token.format_token.spaces_before = largest_lhs - colon_token.length + 1; + } + } else if p.config.align_style == .Align_On_Type_And_Equals { + for type_token in type_tokens { + type_token.format_token.spaces_before = largest_lhs - type_token.length + 1; + } + } + + if current_typed { + for equal_token in equal_tokens { + equal_token.format_token.spaces_before = largest_rhs - equal_token.length + 1; + } + } else { + for equal_token in equal_tokens { + equal_token.format_token.spaces_before = 0; + } + } } align_switch_stmt :: proc(p: ^Printer, index: int) { @@ -699,4 +823,4 @@ align_comments :: proc(p: ^Printer) { } } } -} \ No newline at end of file +} diff --git a/core/odin/printer/visit.odin b/core/odin/printer/visit.odin index 953e0951f..67d0fdc50 100644 --- a/core/odin/printer/visit.odin +++ b/core/odin/printer/visit.odin @@ -485,7 +485,10 @@ visit_exprs :: proc(p: ^Printer, list: []^ast.Expr, add_comma := false, trailing //we have to newline the expressions to respect the source for expr, i in list { - move_line_limit(p, expr.pos, 1); + //Don't move the first expression, it looks bad + if i != 0 { + move_line_limit(p, expr.pos, 1); + } visit_expr(p, expr); @@ -614,7 +617,11 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener newline_position(p, 1); } + set_source_position(p, v.body.pos); + visit_stmt(p, v.body, .If_Stmt); + + set_source_position(p, v.body.end); } if v.else_stmt != nil { @@ -1445,7 +1452,9 @@ visit_signature_list :: proc(p: ^Printer, list: ^ast.Field_List, remove_blank := for field, i in list.list { - move_line_limit(p, field.pos, 1); + if i != 0 { + move_line_limit(p, field.pos, 1); + } if .Using in field.flags { push_generic_token(p, .Using, 0); From 6eb64f2bdc539786a1210f5048c346c75534e504 Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Wed, 21 Apr 2021 23:40:08 +0200 Subject: [PATCH 32/49] align enum --- core/odin/printer/printer.odin | 87 +++++++++++++++++++++++++++++++++- core/odin/printer/visit.odin | 4 +- 2 files changed, 88 insertions(+), 3 deletions(-) diff --git a/core/odin/printer/printer.odin b/core/odin/printer/printer.odin index 0da6a9b38..b81ef6481 100644 --- a/core/odin/printer/printer.odin +++ b/core/odin/printer/printer.odin @@ -61,6 +61,7 @@ Config :: struct { align_assignments: bool, align_structs: bool, align_style: Alignment_Style, + align_enums: bool, indent_cases: bool, newline_style: Newline_Style, } @@ -104,6 +105,7 @@ default_style := Config { indent_cases = false, align_switch = true, align_structs = true, + align_enums = true, newline_style = .CRLF, }; @@ -425,6 +427,10 @@ format_generic :: proc(p: ^Printer) { align_switch_stmt(p, line_index); } + if .Enum in line.types && p.config.align_enums { + align_enum(p, line_index); + } + if .Struct in line.types && p.config.align_structs { align_struct(p, line_index); } @@ -542,8 +548,6 @@ align_var_decls :: proc(p: ^Printer) { largest_rhs = max(largest_rhs, rhs_length); } - fmt.println(current_typed); - //repeating myself, move to sub procedure if p.config.align_style == .Align_On_Colon_And_Equals || !current_typed { for colon_token in colon_tokens { @@ -665,6 +669,85 @@ align_switch_stmt :: proc(p: ^Printer, index: int) { } } +align_enum :: proc(p: ^Printer, index: int) { + enum_found := false; + brace_token: Format_Token; + brace_line: int; + + found_enum_brace: for line, line_index in p.lines[index:] { + + for format_token in line.format_tokens { + + if format_token.kind == .Open_Brace && enum_found { + brace_token = format_token; + brace_line = line_index + index; + break found_enum_brace; + } else if format_token.kind == .Open_Brace { + break; + } else if format_token.kind == .Enum { + enum_found = true; + } + } + } + + if !enum_found { + return; + } + + largest := 0; + eq_count := 0; + + for line, line_index in p.lines[brace_line + 1:] { + + length := 0; + + for format_token in line.format_tokens { + + if format_token.kind == .Comment { + continue; + } + + if format_token.kind == .Eq { + eq_count += 1; + largest = max(length, largest); + break; + } + + length += len(format_token.text) + format_token.spaces_before; + } + + if eq_count >= brace_token.parameter_count { + break; + } + } + + eq_count = 0; + + for line, line_index in p.lines[brace_line + 1:] { + + length := 0; + + for format_token, i in line.format_tokens { + + if format_token.kind == .Comment { + continue; + } + + if format_token.kind == .Eq { + eq_count += 1; + line.format_tokens[i].spaces_before = largest - length + 1; + break; + } + + length += len(format_token.text) + format_token.spaces_before; + } + + if eq_count >= brace_token.parameter_count { + break; + } + } +} + align_struct :: proc(p: ^Printer, index: int) { struct_found := false; diff --git a/core/odin/printer/visit.odin b/core/odin/printer/visit.odin index 67d0fdc50..01272c60e 100644 --- a/core/odin/printer/visit.odin +++ b/core/odin/printer/visit.odin @@ -1017,6 +1017,8 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr) { case Enum_Type: push_generic_token(p, .Enum, 1); + hint_current_line(p, {.Enum}); + if v.base_type != nil { visit_expr(p, v.base_type); } @@ -1026,7 +1028,7 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr) { visit_exprs(p, v.fields, true); push_generic_token(p, .Close_Brace, 0); } else { - visit_begin_brace(p, v.pos, .Generic); + visit_begin_brace(p, v.pos, .Generic, len(v.fields)); newline_position(p, 1); set_source_position(p, v.fields[0].pos); visit_exprs(p, v.fields, true, true); From ca112c0b6d1ef0f7450922e354218017641dc8c2 Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Thu, 22 Apr 2021 00:04:01 +0200 Subject: [PATCH 33/49] better placing of the end brace --- core/odin/printer/printer.odin | 1 + core/odin/printer/visit.odin | 7 ++----- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/core/odin/printer/printer.odin b/core/odin/printer/printer.odin index b81ef6481..14b67507f 100644 --- a/core/odin/printer/printer.odin +++ b/core/odin/printer/printer.odin @@ -907,3 +907,4 @@ align_comments :: proc(p: ^Printer) { } } } + \ No newline at end of file diff --git a/core/odin/printer/visit.odin b/core/odin/printer/visit.odin index 01272c60e..84c4ebfd5 100644 --- a/core/odin/printer/visit.odin +++ b/core/odin/printer/visit.odin @@ -9,7 +9,7 @@ import "core:unicode/utf8" import "core:mem" import "core:sort" -//right the attribute order is not linearly parsed(bug?) +//right now the attribute order is not linearly parsed(bug?) @(private) sort_attribute :: proc(s: ^[dynamic]^ast.Attribute) -> sort.Interface { return sort.Interface { @@ -576,8 +576,6 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener visit_block_stmts(p, v.stmts, len(v.stmts) > 1 && p.config.split_multiple_stmts); - set_source_position(p, v.end); - if !empty_block { visit_end_brace(p, v.end); } @@ -1259,8 +1257,7 @@ visit_begin_brace :: proc(p: ^Printer, begin: tokenizer.Pos, type: Block_Type, c } visit_end_brace :: proc(p: ^Printer, end: tokenizer.Pos) { - set_source_position(p, end); - newline_position(p, 1); + move_line(p, end); push_generic_token(p, .Close_Brace, 0); unindent(p); p.current_line.depth = p.depth; From b18e8898d81a7358865d8601c28a3fb80ca9bcf2 Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Thu, 22 Apr 2021 00:07:07 +0200 Subject: [PATCH 34/49] ran odinfmt on source --- tools/odinfmt/flag/flag.odin | 451 +++++++++++++++++------------------ tools/odinfmt/main.odin | 275 ++++++++++----------- 2 files changed, 346 insertions(+), 380 deletions(-) diff --git a/tools/odinfmt/flag/flag.odin b/tools/odinfmt/flag/flag.odin index 543438678..041b69df0 100644 --- a/tools/odinfmt/flag/flag.odin +++ b/tools/odinfmt/flag/flag.odin @@ -1,232 +1,219 @@ -package flag - -import "core:runtime" -import "core:strings" -import "core:reflect" -import "core:fmt" -import "core:mem" -import "core:strconv" - -Flag_Error :: enum { - None, - No_Base_Struct, - Arg_Error, - Arg_Unsupported_Field_Type, - Arg_Not_Defined, - Arg_Non_Optional, - Value_Parse_Error, - Tag_Error, -} - -Flag :: struct { - optional: bool, - type: ^runtime.Type_Info, - data: rawptr, - tag_ptr: rawptr, - parsed: bool, -} - -Flag_Context :: struct { - seen_flags: map [string] Flag, -} - -parse_args :: proc(ctx: ^Flag_Context, args: []string) -> Flag_Error { - - using runtime; - - args := args; - - for true { - - if len(args) == 0 { - return .None; - } - - arg := args[0]; - - if len(arg) < 2 || arg[0] != '-' { - return .Arg_Error; - } - - minus_count := 1; - - if arg[1] == '-' { - minus_count += 1; - - if len(arg) == 2 { - return .Arg_Error; - } - } - - name := arg[minus_count:]; - - if len(name) == 0 { - return .Arg_Error; - } - - args = args[1:]; - - assign_index := strings.index(name, "="); - - value := ""; - - if assign_index > 0 { - value = name[assign_index + 1:]; - name = name[0:assign_index]; - } - - flag := &ctx.seen_flags[name]; - - if flag == nil { - return .Arg_Not_Defined; - } - - if reflect.is_boolean(flag.type) { - tmp := true; - mem.copy(flag.data, &tmp, flag.type.size); - flag.parsed = true; - continue; - } - - //must be in the next argument - else if value == "" { - - if len(args) == 0 { - return .Arg_Error; - } - - value = args[0]; - args = args[1:]; - } - - #partial switch in flag.type.variant { - case Type_Info_Integer: - if v, ok := strconv.parse_int(value); ok { - mem.copy(flag.data, &v, flag.type.size); - } - else { - return .Value_Parse_Error; - } - case Type_Info_String: - raw_string := cast(^mem.Raw_String)flag.data; - raw_string.data = strings.ptr_from_string(value); - raw_string.len = len(value); - case Type_Info_Float: - switch flag.type.size { - case 32: - if v, ok := strconv.parse_f32(value); ok { - mem.copy(flag.data, &v, flag.type.size); - } - else { - return .Value_Parse_Error; - } - case 64: - if v, ok := strconv.parse_f64(value); ok { - mem.copy(flag.data, &v, flag.type.size); - } - else { - return .Value_Parse_Error; - } - } - } - - flag.parsed = true; - } - - - - return .None; -} - -reflect_args_structure :: proc(ctx: ^Flag_Context, v: any) -> Flag_Error { - using runtime; - - if !reflect.is_struct(type_info_of(v.id)) { - return .No_Base_Struct; - } - - names := reflect.struct_field_names(v.id); - types := reflect.struct_field_types(v.id); - offsets := reflect.struct_field_offsets(v.id); - tags := reflect.struct_field_tags(v.id); - - for name, i in names { - - flag: Flag; - - type := types[i]; - - if named_type, ok := type.variant.(Type_Info_Named); ok { - - if union_type, ok := named_type.base.variant.(Type_Info_Union); ok && union_type.maybe && len(union_type.variants) == 1 { - flag.optional = true; - flag.tag_ptr = rawptr(uintptr(union_type.tag_offset) + uintptr(v.data) + uintptr(offsets[i])); - type = union_type.variants[0]; - } - - else { - return .Arg_Unsupported_Field_Type; - } - - } - - #partial switch in type.variant { - case Type_Info_Integer, Type_Info_String, Type_Info_Boolean, Type_Info_Float: - flag.type = type; - flag.data = rawptr(uintptr(v.data) + uintptr(offsets[i])); - case: - return .Arg_Unsupported_Field_Type; - } - - flag_name: string; - - if value, ok := reflect.struct_tag_lookup(tags[i], "flag"); ok { - flag_name = cast(string)value; - } - - else { - return .Tag_Error; - } - - ctx.seen_flags[flag_name] = flag; - } - - return .None; -} - -parse :: proc(v: any, args: []string) -> Flag_Error { - - if v == nil { - return .None; - } - - ctx: Flag_Context; - - if res := reflect_args_structure(&ctx, v); res != .None { - return res; - } - - if res := parse_args(&ctx, args); res != .None { - return res; - } - - //validate that the required flags were actually set - for k, v in ctx.seen_flags { - - if v.optional && v.parsed { - tag_value : i32 = 1; - mem.copy(v.tag_ptr, &tag_value, 4); //4 constant is probably not portable, but it works for me currently - } - - else if !v.parsed && !v.optional { - return .Arg_Non_Optional; - } - - } - - return .None; -} - -usage :: proc(v: any) -> string { - return "failed"; -} \ No newline at end of file +package flag + +import "core:runtime" +import "core:strings" +import "core:reflect" +import "core:fmt" +import "core:mem" +import "core:strconv" + +Flag_Error :: enum { + None, + No_Base_Struct, + Arg_Error, + Arg_Unsupported_Field_Type, + Arg_Not_Defined, + Arg_Non_Optional, + Value_Parse_Error, + Tag_Error, +} + +Flag :: struct { + optional: bool, + type: ^runtime.Type_Info, + data: rawptr, + tag_ptr: rawptr, + parsed: bool, +} + +Flag_Context :: struct { + seen_flags: map[string]Flag, +} + +parse_args :: proc(ctx: ^Flag_Context, args: []string) -> Flag_Error { + + using runtime; + + args := args; + + for true { + + if len(args) == 0 { + return .None; + } + + arg := args[0]; + + if len(arg) < 2 || arg[0] != '-' { + return .Arg_Error; + } + + minus_count := 1; + + if arg[1] == '-' { + minus_count += 1; + + if len(arg) == 2 { + return .Arg_Error; + } + } + + name := arg[minus_count:]; + + if len(name) == 0 { + return .Arg_Error; + } + + args = args[1:]; + + assign_index := strings.index(name, "="); + + value := ""; + + if assign_index > 0 { + value = name[assign_index + 1:]; + name = name[0:assign_index]; + } + + flag := &ctx.seen_flags[name]; + + if flag == nil { + return .Arg_Not_Defined; + } + + if reflect.is_boolean(flag.type) { + tmp := true; + mem.copy(flag.data, &tmp, flag.type.size); + flag.parsed = true; + continue; + } else + + //must be in the next argument + if value == "" { + + if len(args) == 0 { + return .Arg_Error; + } + + value = args[0]; + args = args[1:]; + } + + #partial switch _ in flag.type.variant { + case Type_Info_Integer: + if v, ok := strconv.parse_int(value); ok { + mem.copy(flag.data, &v, flag.type.size); + } else { + return .Value_Parse_Error; + } + case Type_Info_String: + raw_string := cast(^mem.Raw_String)flag.data; + raw_string.data = strings.ptr_from_string(value); + raw_string.len = len(value); + case Type_Info_Float: + switch flag.type.size { + case 32: + if v, ok := strconv.parse_f32(value); ok { + mem.copy(flag.data, &v, flag.type.size); + } else { + return .Value_Parse_Error; + } + case 64: + if v, ok := strconv.parse_f64(value); ok { + mem.copy(flag.data, &v, flag.type.size); + } else { + return .Value_Parse_Error; + } + } + } + + flag.parsed = true; + } + + return .None; +} + +reflect_args_structure :: proc(ctx: ^Flag_Context, v: any) -> Flag_Error { + using runtime; + + if !reflect.is_struct(type_info_of(v.id)) { + return .No_Base_Struct; + } + + names := reflect.struct_field_names(v.id); + types := reflect.struct_field_types(v.id); + offsets := reflect.struct_field_offsets(v.id); + tags := reflect.struct_field_tags(v.id); + + for name, i in names { + + flag: Flag; + + type := types[i]; + + if named_type, ok := type.variant.(Type_Info_Named); ok { + + if union_type, ok := named_type.base.variant.(Type_Info_Union); ok && union_type.maybe && len(union_type.variants) == 1 { + flag.optional = true; + flag.tag_ptr = rawptr(uintptr(union_type.tag_offset) + uintptr(v.data) + uintptr(offsets[i])); + type = union_type.variants[0]; + } else { + return .Arg_Unsupported_Field_Type; + } + } + + #partial switch _ in type.variant { + case Type_Info_Integer, Type_Info_String, Type_Info_Boolean, Type_Info_Float: + flag.type = type; + flag.data = rawptr(uintptr(v.data) + uintptr(offsets[i])); + case: + return .Arg_Unsupported_Field_Type; + } + + flag_name: string; + + if value, ok := reflect.struct_tag_lookup(tags[i], "flag"); ok { + flag_name = cast(string)value; + } else { + return .Tag_Error; + } + + ctx.seen_flags[flag_name] = flag; + } + + return .None; +} + +parse :: proc(v: any, args: []string) -> Flag_Error { + + if v == nil { + return .None; + } + + ctx: Flag_Context; + + if res := reflect_args_structure(&ctx, v); res != .None { + return res; + } + + if res := parse_args(&ctx, args); res != .None { + return res; + } + + //validate that the required flags were actually set + for k, v in ctx.seen_flags { + + if v.optional && v.parsed { + tag_value: i32 = 1; + mem.copy(v.tag_ptr, &tag_value, 4); //4 constant is probably not portable, but it works for me currently + } else if !v.parsed && !v.optional { + return .Arg_Non_Optional; + } + } + + return .None; +} + +usage :: proc(v: any) -> string { + return "failed"; +} diff --git a/tools/odinfmt/main.odin b/tools/odinfmt/main.odin index 4040fe4c2..29c1f6c1b 100644 --- a/tools/odinfmt/main.odin +++ b/tools/odinfmt/main.odin @@ -1,148 +1,127 @@ -package odinfmt - -import "core:os" -import "core:odin/format" -import "core:fmt" -import "core:strings" -import "core:path/filepath" -import "core:time" -import "core:mem" - -import "flag" - -Args :: struct { - write: Maybe(bool) `flag:"w" usage:"write the new format to file"`, -} - -print_help :: proc() { - -} - -print_arg_error :: proc(error: flag.Flag_Error) { - fmt.println(error); -} - -format_file :: proc(filepath: string) -> ([] u8, bool) { - - if data, ok := os.read_entire_file(filepath); ok { - return format.format(data, format.default_style); - } - - else { - return {}, false; - } - -} - -files: [dynamic] string; - -walk_files :: proc(info: os.File_Info, in_err: os.Errno) -> (err: os.Errno, skip_dir: bool) { - - if info.is_dir { - return 0, false; - } - - if filepath.ext(info.name) != ".odin" { - return 0, false; - } - - append(&files, strings.clone(info.fullpath)); - - return 0, false; -} - -main :: proc() { - - init_global_temporary_allocator(mem.megabytes(100)); - - args: Args; - - if len(os.args) < 2 { - print_help(); - os.exit(1); - } - - if res := flag.parse(args, os.args[1:len(os.args)-1]); res != .None { - print_arg_error(res); - os.exit(1); - } - - path := os.args[len(os.args)-1]; - - tick_time := time.tick_now(); - - if os.is_file(path) { - - if _, ok := args.write.(bool); ok { - - backup_path := strings.concatenate({path, "_bk"}, context.temp_allocator); - - if data, ok := format_file(path); ok { - - os.rename(path, backup_path); - - if os.write_entire_file(path, data) { - os.remove(backup_path); - } - - } - - else { - fmt.eprintf("failed to write %v", path); - } - - } - - else { - - if data, ok := format_file(path); ok { - fmt.println(transmute(string)data); - } - - } - - } - - else if os.is_dir(path) { - - filepath.walk(path, walk_files); - - for file in files { - - fmt.println(file); - - backup_path := strings.concatenate({file, "_bk"}, context.temp_allocator); - - if data, ok := format_file(file); ok { - - if _, ok := args.write.(bool); ok { - os.rename(file, backup_path); - - if os.write_entire_file(file, data) { - os.remove(backup_path); - } - } - - else { - fmt.println(transmute(string)data); - } - - - } else { - fmt.eprintf("failed to format %v", file); - } - - free_all(context.temp_allocator); - } - - fmt.printf("formatted %v files in %vms", len(files), time.duration_milliseconds(time.tick_lap_time(&tick_time))); - - } - - else{ - fmt.eprintf("%v is neither a directory nor a file \n", path); - os.exit(1); - } - - os.exit(0); -} \ No newline at end of file +package odinfmt + +import "core:os" +import "core:odin/format" +import "core:fmt" +import "core:strings" +import "core:path/filepath" +import "core:time" +import "core:mem" + +import "flag" + +Args :: struct { + write: Maybe(bool) `flag:"w" usage:"write the new format to file"`, +} + +print_help :: proc() { +} + +print_arg_error :: proc(error: flag.Flag_Error) { + fmt.println(error); +} + +format_file :: proc(filepath: string) -> ([]u8, bool) { + + if data, ok := os.read_entire_file(filepath); ok { + return format.format(data, format.default_style); + } else { + return {}, false; + } +} + +files: [dynamic]string; + +walk_files :: proc(info: os.File_Info, in_err: os.Errno) -> (err: os.Errno, skip_dir: bool) { + + if info.is_dir { + return 0, false; + } + + if filepath.ext(info.name) != ".odin" { + return 0, false; + } + + append(&files, strings.clone(info.fullpath)); + + return 0, false; +} + +main :: proc() { + + init_global_temporary_allocator(mem.megabytes(100)); + + args: Args; + + if len(os.args) < 2 { + print_help(); + os.exit(1); + } + + if res := flag.parse(args, os.args[1:len(os.args) - 1]); res != .None { + print_arg_error(res); + os.exit(1); + } + + path := os.args[len(os.args) - 1]; + + tick_time := time.tick_now(); + + if os.is_file(path) { + + if _, ok := args.write.(bool); ok { + + backup_path := strings.concatenate({path, "_bk"}, context.temp_allocator); + + if data, ok := format_file(path); ok { + + os.rename(path, backup_path); + + if os.write_entire_file(path, data) { + os.remove(backup_path); + } + } else { + fmt.eprintf("failed to write %v", path); + } + } else { + + if data, ok := format_file(path); ok { + fmt.println(transmute(string)data); + } + } + } else if os.is_dir(path) { + + filepath.walk(path, walk_files); + + for file in files { + + fmt.println(file); + + backup_path := strings.concatenate({file, "_bk"}, context.temp_allocator); + + if data, ok := format_file(file); ok { + + if _, ok := args.write.(bool); ok { + os.rename(file, backup_path); + + if os.write_entire_file(file, data) { + os.remove(backup_path); + } + } else { + fmt.println(transmute(string)data); + } + } else { + fmt.eprintf("failed to format %v", file); + } + + free_all(context.temp_allocator); + } + + fmt.printf("formatted %v files in %vms", len(files), time.duration_milliseconds(time.tick_lap_time(&tick_time))); + } else { + fmt.eprintf("%v is neither a directory nor a file \n", path); + os.exit(1); + } + + os.exit(0); +} From 9b8563dfc0ac54a270b0667b77047e0a4cba9e8d Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Thu, 22 Apr 2021 00:08:03 +0200 Subject: [PATCH 35/49] style --- tools/odinfmt/flag/flag.odin | 3 --- tools/odinfmt/main.odin | 5 ----- 2 files changed, 8 deletions(-) diff --git a/tools/odinfmt/flag/flag.odin b/tools/odinfmt/flag/flag.odin index 041b69df0..a943a5a1c 100644 --- a/tools/odinfmt/flag/flag.odin +++ b/tools/odinfmt/flag/flag.odin @@ -146,13 +146,11 @@ reflect_args_structure :: proc(ctx: ^Flag_Context, v: any) -> Flag_Error { tags := reflect.struct_field_tags(v.id); for name, i in names { - flag: Flag; type := types[i]; if named_type, ok := type.variant.(Type_Info_Named); ok { - if union_type, ok := named_type.base.variant.(Type_Info_Union); ok && union_type.maybe && len(union_type.variants) == 1 { flag.optional = true; flag.tag_ptr = rawptr(uintptr(union_type.tag_offset) + uintptr(v.data) + uintptr(offsets[i])); @@ -202,7 +200,6 @@ parse :: proc(v: any, args: []string) -> Flag_Error { //validate that the required flags were actually set for k, v in ctx.seen_flags { - if v.optional && v.parsed { tag_value: i32 = 1; mem.copy(v.tag_ptr, &tag_value, 4); //4 constant is probably not portable, but it works for me currently diff --git a/tools/odinfmt/main.odin b/tools/odinfmt/main.odin index 29c1f6c1b..a651aaff0 100644 --- a/tools/odinfmt/main.odin +++ b/tools/odinfmt/main.odin @@ -68,9 +68,7 @@ main :: proc() { tick_time := time.tick_now(); if os.is_file(path) { - if _, ok := args.write.(bool); ok { - backup_path := strings.concatenate({path, "_bk"}, context.temp_allocator); if data, ok := format_file(path); ok { @@ -84,17 +82,14 @@ main :: proc() { fmt.eprintf("failed to write %v", path); } } else { - if data, ok := format_file(path); ok { fmt.println(transmute(string)data); } } } else if os.is_dir(path) { - filepath.walk(path, walk_files); for file in files { - fmt.println(file); backup_path := strings.concatenate({file, "_bk"}, context.temp_allocator); From de1838c0cb71d3734699a610eb1a0848c45e225d Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Thu, 22 Apr 2021 00:23:17 +0200 Subject: [PATCH 36/49] align not mutable correctly --- core/odin/printer/printer.odin | 24 ++++++++++++++++++++---- core/odin/printer/visit.odin | 4 ++-- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/core/odin/printer/printer.odin b/core/odin/printer/printer.odin index 14b67507f..36b0052c3 100644 --- a/core/odin/printer/printer.odin +++ b/core/odin/printer/printer.odin @@ -449,6 +449,7 @@ align_var_decls :: proc(p: ^Printer) { current_line: int; current_typed: bool; + current_not_mutable: bool; largest_lhs := 0; largest_rhs := 0; @@ -470,17 +471,31 @@ align_var_decls :: proc(p: ^Printer) { } typed := true; + not_mutable := false; + continue_flag := false; for i := 0; i < len(line.format_tokens) - 1; i += 1 { if line.format_tokens[i].kind == .Colon && line.format_tokens[i + 1].kind == .Eq { typed = false; - break; } + + if line.format_tokens[i].kind == .Colon && line.format_tokens[i + 1].kind == .Colon { + not_mutable = true; + } + + if tokenizer.Token_Kind.B_Keyword_Begin <= line.format_tokens[i].kind && line.format_tokens[i].kind <= tokenizer.Token_Kind.B_Keyword_End { + continue_flag = true; + } + } - if line_index != current_line + 1 || typed != current_typed { + if continue_flag { + continue; + } - if p.config.align_style == .Align_On_Colon_And_Equals || !current_typed { + if line_index != current_line + 1 || typed != current_typed || not_mutable != current_not_mutable { + + if p.config.align_style == .Align_On_Colon_And_Equals || !current_typed || current_not_mutable { for colon_token in colon_tokens { colon_token.format_token.spaces_before = largest_lhs - colon_token.length + 1; } @@ -507,6 +522,7 @@ align_var_decls :: proc(p: ^Printer) { largest_rhs = 0; largest_lhs = 0; current_typed = typed; + current_not_mutable = not_mutable; } current_line = line_index; @@ -549,7 +565,7 @@ align_var_decls :: proc(p: ^Printer) { } //repeating myself, move to sub procedure - if p.config.align_style == .Align_On_Colon_And_Equals || !current_typed { + if p.config.align_style == .Align_On_Colon_And_Equals || !current_typed || current_not_mutable { for colon_token in colon_tokens { colon_token.format_token.spaces_before = largest_lhs - colon_token.length + 1; } diff --git a/core/odin/printer/visit.odin b/core/odin/printer/visit.odin index 84c4ebfd5..b07a75e06 100644 --- a/core/odin/printer/visit.odin +++ b/core/odin/printer/visit.odin @@ -424,11 +424,12 @@ visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) { visit_exprs(p, v.names, true); + hint_current_line(p, {.Value_Decl}); + if v.type != nil { if !v.is_mutable { push_generic_token(p, .Colon, 0); } else { - hint_current_line(p, {.Value_Decl}); push_generic_token(p, .Colon, 0); } @@ -438,7 +439,6 @@ visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) { push_generic_token(p, .Colon, 1); push_generic_token(p, .Colon, 0); } else { - hint_current_line(p, {.Value_Decl}); push_generic_token(p, .Colon, 1); } } From 43589a56b7300c83bc206bff8ff8e35ed2365499 Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Thu, 22 Apr 2021 00:32:36 +0200 Subject: [PATCH 37/49] odinfmt on printer --- core/odin/printer/printer.odin | 66 ++++++++++++---------------------- 1 file changed, 22 insertions(+), 44 deletions(-) diff --git a/core/odin/printer/printer.odin b/core/odin/printer/printer.odin index 36b0052c3..ba031f2b1 100644 --- a/core/odin/printer/printer.odin +++ b/core/odin/printer/printer.odin @@ -206,7 +206,7 @@ format_value_decl :: proc(p: ^Printer, index: int) { eq_found := false; eq_token: Format_Token; - eq_line: int; + eq_line: int; largest := 0; found_eq: for line, line_index in p.lines[index:] { @@ -271,8 +271,8 @@ format_assignment :: proc(p: ^Printer, index: int) { format_call :: proc(p: ^Printer, line_index: int, format_index: int) { paren_found := false; - paren_token: Format_Token; - paren_line: int; + paren_token: Format_Token; + paren_line: int; paren_token_index: int; largest := 0; @@ -300,7 +300,7 @@ format_call :: proc(p: ^Printer, line_index: int, format_index: int) { } paren_count := 1; - done := false; + done := false; for line, line_index in p.lines[paren_line:] { @@ -343,11 +343,11 @@ format_keyword_to_brace :: proc(p: ^Printer, line_index: int, format_index: int, keyword_found := false; keyword_token: Format_Token; - keyword_line: int; + keyword_line: int; largest := 0; brace_count := 0; - done := false; + done := false; found_keyword: for line, i in p.lines[line_index:] { for format_token in line.format_tokens { @@ -447,8 +447,8 @@ format_generic :: proc(p: ^Printer) { align_var_decls :: proc(p: ^Printer) { - current_line: int; - current_typed: bool; + current_line: int; + current_typed: bool; current_not_mutable: bool; largest_lhs := 0; @@ -470,8 +470,8 @@ align_var_decls :: proc(p: ^Printer) { continue; } - typed := true; - not_mutable := false; + typed := true; + not_mutable := false; continue_flag := false; for i := 0; i < len(line.format_tokens) - 1; i += 1 { @@ -528,8 +528,8 @@ align_var_decls :: proc(p: ^Printer) { current_line = line_index; current_token_index := 0; - lhs_length := 0; - rhs_length := 0; + lhs_length := 0; + rhs_length := 0; //calcuate the length of lhs of a value decl i.e. `a, b:` for; current_token_index < len(line.format_tokens); current_token_index += 1 { @@ -590,12 +590,10 @@ align_switch_stmt :: proc(p: ^Printer, index: int) { switch_found := false; brace_token: Format_Token; - brace_line: int; + 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 + index; @@ -612,15 +610,15 @@ align_switch_stmt :: proc(p: ^Printer, index: int) { return; } - largest := 0; + largest := 0; case_count := 0; //find all the switch cases that are one lined for line, line_index in p.lines[brace_line + 1:] { - case_found := false; + case_found := false; colon_found := false; - length := 0; + length := 0; for format_token in line.format_tokens { @@ -652,13 +650,11 @@ align_switch_stmt :: proc(p: ^Printer, index: int) { case_count = 0; for line, line_index in p.lines[brace_line + 1:] { - - case_found := false; + case_found := false; colon_found := false; - length := 0; + length := 0; for format_token, i in line.format_tokens { - if format_token.kind == .Comment { continue; } @@ -688,12 +684,10 @@ align_switch_stmt :: proc(p: ^Printer, index: int) { align_enum :: proc(p: ^Printer, index: int) { enum_found := false; brace_token: Format_Token; - brace_line: int; + brace_line: int; found_enum_brace: for line, line_index in p.lines[index:] { - for format_token in line.format_tokens { - if format_token.kind == .Open_Brace && enum_found { brace_token = format_token; brace_line = line_index + index; @@ -710,15 +704,13 @@ align_enum :: proc(p: ^Printer, index: int) { return; } - largest := 0; + largest := 0; eq_count := 0; for line, line_index in p.lines[brace_line + 1:] { - length := 0; for format_token in line.format_tokens { - if format_token.kind == .Comment { continue; } @@ -740,11 +732,9 @@ align_enum :: proc(p: ^Printer, index: int) { eq_count = 0; for line, line_index in p.lines[brace_line + 1:] { - length := 0; for format_token, i in line.format_tokens { - if format_token.kind == .Comment { continue; } @@ -768,12 +758,10 @@ align_struct :: proc(p: ^Printer, index: int) { struct_found := false; brace_token: Format_Token; - brace_line: int; + brace_line: int; found_struct_brace: for line, line_index in p.lines[index:] { - for format_token in line.format_tokens { - if format_token.kind == .Open_Brace && struct_found { brace_token = format_token; brace_line = line_index + index; @@ -790,15 +778,13 @@ align_struct :: proc(p: ^Printer, index: int) { return; } - largest := 0; + largest := 0; colon_count := 0; for line, line_index in p.lines[brace_line + 1:] { - length := 0; for format_token in line.format_tokens { - if format_token.kind == .Comment { continue; } @@ -820,11 +806,9 @@ align_struct :: proc(p: ^Printer, index: int) { colon_count = 0; for line, line_index in p.lines[brace_line + 1:] { - length := 0; for format_token, i in line.format_tokens { - if format_token.kind == .Comment { continue; } @@ -858,13 +842,11 @@ align_comments :: proc(p: ^Printer) { 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 || current_info.depth != line.depth || (current_info.begin == current_info.end && current_info.length == 0) { @@ -881,7 +863,6 @@ align_comments :: proc(p: ^Printer) { 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; @@ -903,13 +884,11 @@ align_comments :: proc(p: ^Printer) { } 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; @@ -923,4 +902,3 @@ align_comments :: proc(p: ^Printer) { } } } - \ No newline at end of file From ab53900c95cb68dd4579dc1dca3926eb50340f9d Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Thu, 22 Apr 2021 00:55:25 +0200 Subject: [PATCH 38/49] check comma count in enum instead --- core/odin/printer/printer.odin | 18 +++++++++++------- core/odin/printer/visit.odin | 2 +- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/core/odin/printer/printer.odin b/core/odin/printer/printer.odin index ba031f2b1..1515ae4e2 100644 --- a/core/odin/printer/printer.odin +++ b/core/odin/printer/printer.odin @@ -486,13 +486,15 @@ align_var_decls :: proc(p: ^Printer) { if tokenizer.Token_Kind.B_Keyword_Begin <= line.format_tokens[i].kind && line.format_tokens[i].kind <= tokenizer.Token_Kind.B_Keyword_End { continue_flag = true; } - } if continue_flag { continue; } + fmt.println(line); + fmt.println(largest_rhs); + if line_index != current_line + 1 || typed != current_typed || not_mutable != current_not_mutable { if p.config.align_style == .Align_On_Colon_And_Equals || !current_typed || current_not_mutable { @@ -705,7 +707,7 @@ align_enum :: proc(p: ^Printer, index: int) { } largest := 0; - eq_count := 0; + comma_count := 0; for line, line_index in p.lines[brace_line + 1:] { length := 0; @@ -716,20 +718,21 @@ align_enum :: proc(p: ^Printer, index: int) { } if format_token.kind == .Eq { - eq_count += 1; largest = max(length, largest); break; + } else if format_token.kind == .Comma { + comma_count += 1; } length += len(format_token.text) + format_token.spaces_before; } - if eq_count >= brace_token.parameter_count { + if comma_count >= brace_token.parameter_count { break; } } - eq_count = 0; + comma_count = 0; for line, line_index in p.lines[brace_line + 1:] { length := 0; @@ -740,15 +743,16 @@ align_enum :: proc(p: ^Printer, index: int) { } if format_token.kind == .Eq { - eq_count += 1; line.format_tokens[i].spaces_before = largest - length + 1; break; + } else if format_token.kind == .Comma { + comma_count += 1; } length += len(format_token.text) + format_token.spaces_before; } - if eq_count >= brace_token.parameter_count { + if comma_count >= brace_token.parameter_count { break; } } diff --git a/core/odin/printer/visit.odin b/core/odin/printer/visit.odin index b07a75e06..4fcd4d76e 100644 --- a/core/odin/printer/visit.odin +++ b/core/odin/printer/visit.odin @@ -31,7 +31,7 @@ sort_attribute :: proc(s: ^[dynamic]^ast.Attribute) -> sort.Interface { @(private) comment_before_position :: proc(p: ^Printer, pos: tokenizer.Pos) -> bool { - + if len(p.comments) <= p.latest_comment_index { return false; } From 40ed7e48d0e4a1f000efbd03d19a4eebe9b8e2f6 Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Thu, 22 Apr 2021 00:56:31 +0200 Subject: [PATCH 39/49] remove prints --- core/odin/printer/printer.odin | 3 --- 1 file changed, 3 deletions(-) diff --git a/core/odin/printer/printer.odin b/core/odin/printer/printer.odin index 1515ae4e2..c0d39f4ba 100644 --- a/core/odin/printer/printer.odin +++ b/core/odin/printer/printer.odin @@ -492,9 +492,6 @@ align_var_decls :: proc(p: ^Printer) { continue; } - fmt.println(line); - fmt.println(largest_rhs); - if line_index != current_line + 1 || typed != current_typed || not_mutable != current_not_mutable { if p.config.align_style == .Align_On_Colon_And_Equals || !current_typed || current_not_mutable { From 3f9ad6ba09176e022af756ae2b1856e2b2775f8c Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Fri, 23 Apr 2021 16:33:11 +0200 Subject: [PATCH 40/49] fix proc group, struct align with internal structs --- core/odin/printer/printer.odin | 51 +++++++++++++++++----------------- core/odin/printer/visit.odin | 14 +++++----- 2 files changed, 32 insertions(+), 33 deletions(-) diff --git a/core/odin/printer/printer.odin b/core/odin/printer/printer.odin index c0d39f4ba..21d94a3e9 100644 --- a/core/odin/printer/printer.odin +++ b/core/odin/printer/printer.odin @@ -483,7 +483,10 @@ align_var_decls :: proc(p: ^Printer) { not_mutable = true; } - if tokenizer.Token_Kind.B_Keyword_Begin <= line.format_tokens[i].kind && line.format_tokens[i].kind <= tokenizer.Token_Kind.B_Keyword_End { + if line.format_tokens[i].kind == tokenizer.Token_Kind.Proc || + line.format_tokens[i].kind == tokenizer.Token_Kind.Union || + line.format_tokens[i].kind == tokenizer.Token_Kind.Enum || + line.format_tokens[i].kind == tokenizer.Token_Kind.Struct { continue_flag = true; } } @@ -496,6 +499,7 @@ align_var_decls :: proc(p: ^Printer) { if p.config.align_style == .Align_On_Colon_And_Equals || !current_typed || current_not_mutable { for colon_token in colon_tokens { + fmt.println(colon_token); colon_token.format_token.spaces_before = largest_lhs - colon_token.length + 1; } } else if p.config.align_style == .Align_On_Type_And_Equals { @@ -703,7 +707,7 @@ align_enum :: proc(p: ^Printer, index: int) { return; } - largest := 0; + largest := 0; comma_count := 0; for line, line_index in p.lines[brace_line + 1:] { @@ -781,30 +785,14 @@ align_struct :: proc(p: ^Printer, index: int) { largest := 0; colon_count := 0; + seen_brace := false; - for line, line_index in p.lines[brace_line + 1:] { - length := 0; + TokenAndLength :: struct { + format_token: ^Format_Token, + length: int, + }; - for format_token in line.format_tokens { - if format_token.kind == .Comment { - continue; - } - - if format_token.kind == .Colon { - colon_count += 1; - largest = max(length, largest); - break; - } - - length += len(format_token.text) + format_token.spaces_before; - } - - if colon_count >= brace_token.parameter_count { - break; - } - } - - colon_count = 0; + format_tokens := make([] TokenAndLength, brace_token.parameter_count, context.temp_allocator); for line, line_index in p.lines[brace_line + 1:] { length := 0; @@ -812,12 +800,18 @@ align_struct :: proc(p: ^Printer, index: int) { for format_token, i in line.format_tokens { if format_token.kind == .Comment { continue; + } else if format_token.kind == .Open_Brace { + seen_brace = true; + } else if format_token.kind == .Close_Brace { + seen_brace = false; + } else if seen_brace { + continue; } if format_token.kind == .Colon { + format_tokens[colon_count] = { format_token = &line.format_tokens[i + 1], length = length }; colon_count += 1; - line.format_tokens[i + 1].spaces_before = largest - length + 1; - break; + largest = max(length, largest); } length += len(format_token.text) + format_token.spaces_before; @@ -827,6 +821,11 @@ align_struct :: proc(p: ^Printer, index: int) { break; } } + + for token in format_tokens { + token.format_token.spaces_before = largest - token.length + 1; + } + } align_comments :: proc(p: ^Printer) { diff --git a/core/odin/printer/visit.odin b/core/odin/printer/visit.odin index 4fcd4d76e..9bfcc3427 100644 --- a/core/odin/printer/visit.odin +++ b/core/odin/printer/visit.odin @@ -31,7 +31,7 @@ sort_attribute :: proc(s: ^[dynamic]^ast.Attribute) -> sort.Interface { @(private) comment_before_position :: proc(p: ^Printer, pos: tokenizer.Pos) -> bool { - + if len(p.comments) <= p.latest_comment_index { return false; } @@ -42,7 +42,7 @@ comment_before_position :: proc(p: ^Printer, pos: tokenizer.Pos) -> bool { } @(private) -next_comment_group :: proc(p: ^Printer) { +next_comment_group :: proc(p: ^Printer) { p.latest_comment_index += 1; } @@ -79,7 +79,7 @@ push_comment :: proc(p: ^Printer, comment: tokenizer.Token) -> int { builder := strings.make_builder(context.temp_allocator); - c_len := len(comment.text); + c_len := len(comment.text); trim_space := true; multilines: [dynamic]string; @@ -157,7 +157,7 @@ push_comment :: proc(p: ^Printer, comment: tokenizer.Token) -> int { @(private) push_comments :: proc(p: ^Printer, pos: tokenizer.Pos) { - prev_comment: ^tokenizer.Token; + prev_comment: ^tokenizer.Token; prev_comment_lines: int; for comment_before_position(p, pos) { @@ -1141,7 +1141,7 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr) { push_generic_token(p, .Close_Bracket, 0); case Proc_Group: - push_generic_token(p, v.tok.kind, 0); + push_generic_token(p, v.tok.kind, 1); if len(v.args) != 0 && v.pos.line != v.args[len(v.args) - 1].pos.line { visit_begin_brace(p, v.pos, .Generic); @@ -1354,7 +1354,7 @@ visit_proc_type :: proc(p: ^Printer, proc_type: ast.Proc_Type) { push_generic_token(p, .Gt, 0); use_parens := false; - use_named := false; + use_named := false; if len(proc_type.results.list) > 1 { use_parens = true; @@ -1497,4 +1497,4 @@ visit_signature_list :: proc(p: ^Printer, list: ^ast.Field_List, remove_blank := push_generic_token(p, .Comma, 0); } } -} \ No newline at end of file +} From 3b5b845ea6be2eb2fe4efd884124259eaeb62e3a Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Fri, 23 Apr 2021 16:45:55 +0200 Subject: [PATCH 41/49] refractor --- core/odin/printer/printer.odin | 80 ++++++++++------------------------ 1 file changed, 24 insertions(+), 56 deletions(-) diff --git a/core/odin/printer/printer.odin b/core/odin/printer/printer.odin index 21d94a3e9..bf0fe207b 100644 --- a/core/odin/printer/printer.odin +++ b/core/odin/printer/printer.odin @@ -616,6 +616,13 @@ align_switch_stmt :: proc(p: ^Printer, index: int) { largest := 0; case_count := 0; + TokenAndLength :: struct { + format_token: ^Format_Token, + length: int, + }; + + format_tokens := make([dynamic] TokenAndLength, 0, brace_token.parameter_count, context.temp_allocator); + //find all the switch cases that are one lined for line, line_index in p.lines[brace_line + 1:] { @@ -623,7 +630,7 @@ align_switch_stmt :: proc(p: ^Printer, index: int) { colon_found := false; length := 0; - for format_token in line.format_tokens { + for format_token, i in line.format_tokens { if format_token.kind == .Comment { continue; @@ -631,6 +638,7 @@ align_switch_stmt :: proc(p: ^Printer, index: int) { //this will only happen if the case is one lined if case_found && colon_found { + append(&format_tokens, TokenAndLength { format_token = &line.format_tokens[i], length = length }); largest = max(length, largest); break; } @@ -650,38 +658,10 @@ align_switch_stmt :: proc(p: ^Printer, index: int) { } } - case_count = 0; - - 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) + 1; - break; - } - - if format_token.kind == .Case { - case_found = true; - case_count += 1; - } else if format_token.kind == .Colon { - colon_found = true; - } - - length += len(format_token.text) + format_token.spaces_before; - } - - if case_count >= brace_token.parameter_count { - break; - } + for token in format_tokens { + token.format_token.spaces_before = largest - token.length + 1; } + } align_enum :: proc(p: ^Printer, index: int) { @@ -710,15 +690,23 @@ align_enum :: proc(p: ^Printer, index: int) { largest := 0; comma_count := 0; + TokenAndLength :: struct { + format_token: ^Format_Token, + length: int, + }; + + format_tokens := make([dynamic] TokenAndLength, 0, brace_token.parameter_count, context.temp_allocator); + for line, line_index in p.lines[brace_line + 1:] { length := 0; - for format_token in line.format_tokens { + for format_token, i in line.format_tokens { if format_token.kind == .Comment { continue; } if format_token.kind == .Eq { + append(&format_tokens, TokenAndLength { format_token = &line.format_tokens[i], length = length }); largest = max(length, largest); break; } else if format_token.kind == .Comma { @@ -733,30 +721,10 @@ align_enum :: proc(p: ^Printer, index: int) { } } - comma_count = 0; - - for line, line_index in p.lines[brace_line + 1:] { - length := 0; - - for format_token, i in line.format_tokens { - if format_token.kind == .Comment { - continue; - } - - if format_token.kind == .Eq { - line.format_tokens[i].spaces_before = largest - length + 1; - break; - } else if format_token.kind == .Comma { - comma_count += 1; - } - - length += len(format_token.text) + format_token.spaces_before; - } - - if comma_count >= brace_token.parameter_count { - break; - } + for token in format_tokens { + token.format_token.spaces_before = largest - token.length + 1; } + } align_struct :: proc(p: ^Printer, index: int) { From 951e940470223c9cd2485f8b75f474182b7d2d4c Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Fri, 23 Apr 2021 21:52:27 +0200 Subject: [PATCH 42/49] handle comments in stupid places --- core/odin/printer/printer.odin | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/core/odin/printer/printer.odin b/core/odin/printer/printer.odin index bf0fe207b..2b4a94eb6 100644 --- a/core/odin/printer/printer.odin +++ b/core/odin/printer/printer.odin @@ -376,7 +376,7 @@ format_keyword_to_brace :: proc(p: ^Printer, line_index: int, format_index: int, for format_token, i in line.format_tokens { if format_token.kind == .Comment { - continue; + break; } if line_index == 0 && i <= format_index { @@ -483,10 +483,14 @@ align_var_decls :: proc(p: ^Printer) { not_mutable = true; } - if line.format_tokens[i].kind == tokenizer.Token_Kind.Proc || - line.format_tokens[i].kind == tokenizer.Token_Kind.Union || - line.format_tokens[i].kind == tokenizer.Token_Kind.Enum || - line.format_tokens[i].kind == tokenizer.Token_Kind.Struct { + if line.format_tokens[i].kind == .Proc || + line.format_tokens[i].kind == .Union || + line.format_tokens[i].kind == .Enum || + line.format_tokens[i].kind == .Struct { + continue_flag = true; + } + + if line.format_tokens[i].kind == .Comment { continue_flag = true; } } @@ -633,7 +637,7 @@ align_switch_stmt :: proc(p: ^Printer, index: int) { for format_token, i in line.format_tokens { if format_token.kind == .Comment { - continue; + break; } //this will only happen if the case is one lined @@ -702,7 +706,7 @@ align_enum :: proc(p: ^Printer, index: int) { for format_token, i in line.format_tokens { if format_token.kind == .Comment { - continue; + break; } if format_token.kind == .Eq { @@ -767,7 +771,7 @@ align_struct :: proc(p: ^Printer, index: int) { for format_token, i in line.format_tokens { if format_token.kind == .Comment { - continue; + break; } else if format_token.kind == .Open_Brace { seen_brace = true; } else if format_token.kind == .Close_Brace { From aafbf5bac7b6aec6a1a11a6ac48d064319432891 Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Fri, 23 Apr 2021 22:55:59 +0200 Subject: [PATCH 43/49] odinfmt --- core/odin/printer/printer.odin | 20 ++++++++++---------- core/odin/printer/visit.odin | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/core/odin/printer/printer.odin b/core/odin/printer/printer.odin index 2b4a94eb6..1ee7d7a62 100644 --- a/core/odin/printer/printer.odin +++ b/core/odin/printer/printer.odin @@ -460,7 +460,7 @@ align_var_decls :: proc(p: ^Printer) { }; colon_tokens := make([dynamic]TokenAndLength, 0, 10, context.temp_allocator); - type_tokens := make([dynamic]TokenAndLength, 0, 10, context.temp_allocator); + type_tokens := make([dynamic]TokenAndLength, 0, 10, context.temp_allocator); equal_tokens := make([dynamic]TokenAndLength, 0, 10, context.temp_allocator); for line, line_index in p.lines { @@ -483,10 +483,11 @@ align_var_decls :: proc(p: ^Printer) { not_mutable = true; } - if line.format_tokens[i].kind == .Proc || + if line.format_tokens[i].kind == .Proc || line.format_tokens[i].kind == .Union || line.format_tokens[i].kind == .Enum || - line.format_tokens[i].kind == .Struct { + line.format_tokens[i].kind == .Struct || + line.format_tokens[i].kind == .For { continue_flag = true; } @@ -503,7 +504,6 @@ align_var_decls :: proc(p: ^Printer) { if p.config.align_style == .Align_On_Colon_And_Equals || !current_typed || current_not_mutable { for colon_token in colon_tokens { - fmt.println(colon_token); colon_token.format_token.spaces_before = largest_lhs - colon_token.length + 1; } } else if p.config.align_style == .Align_On_Type_And_Equals { @@ -625,7 +625,7 @@ align_switch_stmt :: proc(p: ^Printer, index: int) { length: int, }; - format_tokens := make([dynamic] TokenAndLength, 0, brace_token.parameter_count, context.temp_allocator); + format_tokens := make([dynamic]TokenAndLength, 0, brace_token.parameter_count, context.temp_allocator); //find all the switch cases that are one lined for line, line_index in p.lines[brace_line + 1:] { @@ -642,7 +642,7 @@ align_switch_stmt :: proc(p: ^Printer, index: int) { //this will only happen if the case is one lined if case_found && colon_found { - append(&format_tokens, TokenAndLength { format_token = &line.format_tokens[i], length = length }); + append(&format_tokens, TokenAndLength {format_token = &line.format_tokens[i], length = length}); largest = max(length, largest); break; } @@ -699,7 +699,7 @@ align_enum :: proc(p: ^Printer, index: int) { length: int, }; - format_tokens := make([dynamic] TokenAndLength, 0, brace_token.parameter_count, context.temp_allocator); + format_tokens := make([dynamic]TokenAndLength, 0, brace_token.parameter_count, context.temp_allocator); for line, line_index in p.lines[brace_line + 1:] { length := 0; @@ -710,7 +710,7 @@ align_enum :: proc(p: ^Printer, index: int) { } if format_token.kind == .Eq { - append(&format_tokens, TokenAndLength { format_token = &line.format_tokens[i], length = length }); + append(&format_tokens, TokenAndLength {format_token = &line.format_tokens[i], length = length}); largest = max(length, largest); break; } else if format_token.kind == .Comma { @@ -764,7 +764,7 @@ align_struct :: proc(p: ^Printer, index: int) { length: int, }; - format_tokens := make([] TokenAndLength, brace_token.parameter_count, context.temp_allocator); + format_tokens := make([]TokenAndLength, brace_token.parameter_count, context.temp_allocator); for line, line_index in p.lines[brace_line + 1:] { length := 0; @@ -781,7 +781,7 @@ align_struct :: proc(p: ^Printer, index: int) { } if format_token.kind == .Colon { - format_tokens[colon_count] = { format_token = &line.format_tokens[i + 1], length = length }; + format_tokens[colon_count] = {format_token = &line.format_tokens[i + 1], length = length}; colon_count += 1; largest = max(length, largest); } diff --git a/core/odin/printer/visit.odin b/core/odin/printer/visit.odin index 9bfcc3427..3fdb77615 100644 --- a/core/odin/printer/visit.odin +++ b/core/odin/printer/visit.odin @@ -42,7 +42,7 @@ comment_before_position :: proc(p: ^Printer, pos: tokenizer.Pos) -> bool { } @(private) -next_comment_group :: proc(p: ^Printer) { +next_comment_group :: proc(p: ^Printer) { p.latest_comment_index += 1; } From 5fba548aa032ada33fce0ba0dc6ca0876e0fceb1 Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Fri, 23 Apr 2021 23:22:48 +0200 Subject: [PATCH 44/49] more fixes with wierd comment placements --- core/odin/printer/printer.odin | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/core/odin/printer/printer.odin b/core/odin/printer/printer.odin index 1ee7d7a62..13c8dbf6b 100644 --- a/core/odin/printer/printer.odin +++ b/core/odin/printer/printer.odin @@ -12,6 +12,9 @@ Type_Enum :: enum {Line_Comment, Value_Decl, Switch_Stmt, Struct, Assign, Call, Line_Type :: bit_set[Type_Enum]; +/* + Represents an unwrapped line +*/ Line :: struct { format_tokens: [dynamic]Format_Token, finalized: bool, @@ -20,6 +23,9 @@ Line :: struct { types: Line_Type, //for performance, so you don't have to verify what types are in it by going through the tokens - might give problems when adding linebreaking } +/* + Represents an singular token in a unwrapped line +*/ Format_Token :: struct { kind: tokenizer.Token_Kind, text: string, @@ -474,12 +480,12 @@ align_var_decls :: proc(p: ^Printer) { not_mutable := false; continue_flag := false; - for i := 0; i < len(line.format_tokens) - 1; i += 1 { - if line.format_tokens[i].kind == .Colon && line.format_tokens[i + 1].kind == .Eq { + for i := 0; i < len(line.format_tokens); i += 1 { + if line.format_tokens[i].kind == .Colon && line.format_tokens[min(i + 1, len(line.format_tokens) - 1)].kind == .Eq { typed = false; } - if line.format_tokens[i].kind == .Colon && line.format_tokens[i + 1].kind == .Colon { + if line.format_tokens[i].kind == .Colon && line.format_tokens[min(i + 1, len(line.format_tokens) - 1)].kind == .Colon { not_mutable = true; } From 87bfd3166482eaa3d89387bde03852f23c6f0629 Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Fri, 23 Apr 2021 23:42:53 +0200 Subject: [PATCH 45/49] force all enums newlined if there is more than one line --- core/odin/printer/printer.odin | 2 +- core/odin/printer/visit.odin | 17 ++++++++++++----- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/core/odin/printer/printer.odin b/core/odin/printer/printer.odin index 13c8dbf6b..e1d9f5b7d 100644 --- a/core/odin/printer/printer.odin +++ b/core/odin/printer/printer.odin @@ -24,7 +24,7 @@ Line :: struct { } /* - Represents an singular token in a unwrapped line + Represents a singular token in a unwrapped line */ Format_Token :: struct { kind: tokenizer.Token_Kind, diff --git a/core/odin/printer/visit.odin b/core/odin/printer/visit.odin index 3fdb77615..a6b6759de 100644 --- a/core/odin/printer/visit.odin +++ b/core/odin/printer/visit.odin @@ -476,7 +476,7 @@ visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) { } @(private) -visit_exprs :: proc(p: ^Printer, list: []^ast.Expr, add_comma := false, trailing := false) { +visit_exprs :: proc(p: ^Printer, list: []^ast.Expr, add_comma := false, trailing := false, force_newline := false) { if len(list) == 0 { return; @@ -484,9 +484,12 @@ visit_exprs :: proc(p: ^Printer, list: []^ast.Expr, add_comma := false, trailing //we have to newline the expressions to respect the source for expr, i in list { - //Don't move the first expression, it looks bad - if i != 0 { + if i != 0 && force_newline { + newline_position(p, 1); + } + + else if i != 0 { move_line_limit(p, expr.pos, 1); } @@ -496,6 +499,10 @@ visit_exprs :: proc(p: ^Printer, list: []^ast.Expr, add_comma := false, trailing push_generic_token(p, .Comma, 0); } } + + if len(list) > 1 && force_newline { + newline_position(p, 1); + } } @(private) @@ -506,7 +513,6 @@ visit_attributes :: proc(p: ^Printer, attributes: [dynamic]^ast.Attribute) { } for attribute, i in attributes { - move_line_limit(p, attribute.pos, 1); push_generic_token(p, .At, 0); @@ -1029,7 +1035,8 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr) { visit_begin_brace(p, v.pos, .Generic, len(v.fields)); newline_position(p, 1); set_source_position(p, v.fields[0].pos); - visit_exprs(p, v.fields, true, true); + visit_exprs(p, v.fields, true, true, true); + set_source_position(p, v.end); visit_end_brace(p, v.end); } From 088f4b503994feb7c5abe64b8956d827ef9ae36f Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Wed, 28 Apr 2021 12:53:04 +0200 Subject: [PATCH 46/49] fix out of bounds with empty struct --- core/odin/printer/printer.odin | 7 ++++++- core/odin/printer/visit.odin | 4 +--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/core/odin/printer/printer.odin b/core/odin/printer/printer.odin index e1d9f5b7d..63c0c5fc7 100644 --- a/core/odin/printer/printer.odin +++ b/core/odin/printer/printer.odin @@ -493,7 +493,8 @@ align_var_decls :: proc(p: ^Printer) { line.format_tokens[i].kind == .Union || line.format_tokens[i].kind == .Enum || line.format_tokens[i].kind == .Struct || - line.format_tokens[i].kind == .For { + line.format_tokens[i].kind == .For || + line.format_tokens[i].kind == .If { continue_flag = true; } @@ -772,6 +773,10 @@ align_struct :: proc(p: ^Printer, index: int) { format_tokens := make([]TokenAndLength, brace_token.parameter_count, context.temp_allocator); + if brace_token.parameter_count == 0 { + return; + } + for line, line_index in p.lines[brace_line + 1:] { length := 0; diff --git a/core/odin/printer/visit.odin b/core/odin/printer/visit.odin index a6b6759de..003bb8332 100644 --- a/core/odin/printer/visit.odin +++ b/core/odin/printer/visit.odin @@ -487,9 +487,7 @@ visit_exprs :: proc(p: ^Printer, list: []^ast.Expr, add_comma := false, trailing //Don't move the first expression, it looks bad if i != 0 && force_newline { newline_position(p, 1); - } - - else if i != 0 { + } else if i != 0 { move_line_limit(p, expr.pos, 1); } From 9c6ab059810624043b0ebab9cc1b87a110457e7a Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Thu, 29 Apr 2021 00:51:24 +0200 Subject: [PATCH 47/49] fix tokenizer for ~= and better struct aligning --- core/odin/printer/printer.odin | 19 ++++++++++++------- core/odin/printer/visit.odin | 9 ++++++++- core/odin/tokenizer/tokenizer.odin | 2 +- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/core/odin/printer/printer.odin b/core/odin/printer/printer.odin index 63c0c5fc7..407e5a415 100644 --- a/core/odin/printer/printer.odin +++ b/core/odin/printer/printer.odin @@ -350,8 +350,8 @@ format_keyword_to_brace :: proc(p: ^Printer, line_index: int, format_index: int, keyword_found := false; keyword_token: Format_Token; keyword_line: int; - largest := 0; + largest := 0; brace_count := 0; done := false; @@ -385,6 +385,10 @@ format_keyword_to_brace :: proc(p: ^Printer, line_index: int, format_index: int, break; } + if format_token.kind == .Undef || format_token.kind == .Comma { + return; + } + if line_index == 0 && i <= format_index { continue; } @@ -489,18 +493,20 @@ align_var_decls :: proc(p: ^Printer) { not_mutable = true; } - if line.format_tokens[i].kind == .Proc || - line.format_tokens[i].kind == .Union || + if line.format_tokens[i].kind == .Union || line.format_tokens[i].kind == .Enum || line.format_tokens[i].kind == .Struct || line.format_tokens[i].kind == .For || - line.format_tokens[i].kind == .If { + line.format_tokens[i].kind == .If || + line.format_tokens[i].kind == .Comment { continue_flag = true; } - if line.format_tokens[i].kind == .Comment { + //enforced undef is always on the last line, if it exists + if line.format_tokens[i].kind == .Proc && line.format_tokens[len(line.format_tokens)-1].kind != .Undef { continue_flag = true; } + } if continue_flag { @@ -601,7 +607,6 @@ align_var_decls :: proc(p: ^Printer) { } align_switch_stmt :: proc(p: ^Printer, index: int) { - switch_found := false; brace_token: Format_Token; brace_line: int; @@ -739,7 +744,6 @@ align_enum :: proc(p: ^Printer, index: int) { } align_struct :: proc(p: ^Printer, index: int) { - struct_found := false; brace_token: Format_Token; brace_line: int; @@ -795,6 +799,7 @@ align_struct :: proc(p: ^Printer, index: int) { format_tokens[colon_count] = {format_token = &line.format_tokens[i + 1], length = length}; colon_count += 1; largest = max(length, largest); + break; } length += len(format_token.text) + format_token.spaces_before; diff --git a/core/odin/printer/visit.odin b/core/odin/printer/visit.odin index 003bb8332..a8f7068c8 100644 --- a/core/odin/printer/visit.odin +++ b/core/odin/printer/visit.odin @@ -461,8 +461,10 @@ visit_decl :: proc(p: ^Printer, decl: ^ast.Decl, called_in_stmt := false) { for value in v.values { switch a in value.derived { - case Proc_Lit, Union_Type, Enum_Type, Struct_Type: + case Union_Type, Enum_Type, Struct_Type: add_semicolon = false || called_in_stmt; + case Proc_Lit: + add_semicolon = false; } } @@ -532,6 +534,9 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener } switch v in stmt.derived { + case Import_Decl: + visit_decl(p, cast(^Decl)stmt, true); + return; case Value_Decl: visit_decl(p, cast(^Decl)stmt, true); return; @@ -693,6 +698,8 @@ visit_stmt :: proc(p: ^Printer, stmt: ^ast.Stmt, block_type: Block_Type = .Gener case Type_Switch_Stmt: move_line(p, v.pos); + hint_current_line(p, {.Switch_Stmt}); + if v.label != nil { visit_expr(p, v.label); push_generic_token(p, .Colon, 0); diff --git a/core/odin/tokenizer/tokenizer.odin b/core/odin/tokenizer/tokenizer.odin index 58f546191..b1b446192 100644 --- a/core/odin/tokenizer/tokenizer.odin +++ b/core/odin/tokenizer/tokenizer.odin @@ -608,7 +608,7 @@ scan :: proc(t: ^Tokenizer) -> Token { kind = switch3(t, .And, .And_Eq, '&', .Cmp_And); } case '|': kind = switch3(t, .Or, .Or_Eq, '|', .Cmp_Or); - case '~': kind = .Xor; + case '~': kind = switch2(t, .Xor, .Xor_Eq); case '<': kind = switch4(t, .Lt, .Lt_Eq, '<', .Shl, .Shl_Eq); case '>': kind = switch4(t, .Gt, .Gt_Eq, '>', .Shr,.Shr_Eq); From 87a18338628fc42ba49c24d095b37e351e779ede Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Sat, 1 May 2021 21:26:40 +0200 Subject: [PATCH 48/49] fix weird behavior of nesting proc types in structs --- core/odin/printer/printer.odin | 56 ++++++++++++++++++++++++++-------- core/odin/printer/visit.odin | 19 ++++++++++-- 2 files changed, 59 insertions(+), 16 deletions(-) diff --git a/core/odin/printer/printer.odin b/core/odin/printer/printer.odin index 407e5a415..bef1235e9 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" -Type_Enum :: enum {Line_Comment, Value_Decl, Switch_Stmt, Struct, Assign, Call, Enum, If, For} +Type_Enum :: enum {Line_Comment, Value_Decl, Switch_Stmt, Struct, Assign, Call, Enum, If, For, Proc_Lit} Line_Type :: bit_set[Type_Enum]; @@ -68,6 +68,7 @@ Config :: struct { align_structs: bool, align_style: Alignment_Style, align_enums: bool, + align_length_break: int, indent_cases: bool, newline_style: Newline_Style, } @@ -113,6 +114,7 @@ default_style := Config { align_structs = true, align_enums = true, newline_style = .CRLF, + align_length_break = 9, }; make_printer :: proc(config: Config, allocator := context.allocator) -> Printer { @@ -383,11 +385,9 @@ format_keyword_to_brace :: proc(p: ^Printer, line_index: int, format_index: int, if format_token.kind == .Comment { break; - } - - if format_token.kind == .Undef || format_token.kind == .Comma { + } else if format_token.kind == .Undef { return; - } + } if line_index == 0 && i <= format_index { continue; @@ -416,6 +416,8 @@ format_keyword_to_brace :: proc(p: ^Printer, line_index: int, format_index: int, format_generic :: proc(p: ^Printer) { + next_struct_line := 0; + for line, line_index in p.lines { if len(line.format_tokens) <= 0 { @@ -423,10 +425,9 @@ format_generic :: proc(p: ^Printer) { } for format_token, token_index in line.format_tokens { - if format_token.kind == .For || format_token.kind == .If || format_token.kind == .When || format_token.kind == .Switch || - format_token.kind == .Proc { + (format_token.kind == .Proc && format_token.type == .Proc_Lit) { format_keyword_to_brace(p, line_index, token_index, format_token.kind); } else if format_token.type == .Call { format_call(p, line_index, token_index); @@ -441,8 +442,8 @@ format_generic :: proc(p: ^Printer) { align_enum(p, line_index); } - if .Struct in line.types && p.config.align_structs { - align_struct(p, line_index); + if .Struct in line.types && p.config.align_structs && next_struct_line <= 0 { + next_struct_line = align_struct(p, line_index); } if .Value_Decl in line.types { @@ -452,6 +453,8 @@ format_generic :: proc(p: ^Printer) { if .Assign in line.types { format_assignment(p, line_index); } + + next_struct_line -= 1; } } @@ -743,7 +746,7 @@ align_enum :: proc(p: ^Printer, index: int) { } -align_struct :: proc(p: ^Printer, index: int) { +align_struct :: proc(p: ^Printer, index: int) -> int { struct_found := false; brace_token: Format_Token; brace_line: int; @@ -763,11 +766,12 @@ align_struct :: proc(p: ^Printer, index: int) { } if !struct_found { - return; + return 0; } largest := 0; colon_count := 0; + nested := false; seen_brace := false; TokenAndLength :: struct { @@ -778,15 +782,21 @@ align_struct :: proc(p: ^Printer, index: int) { format_tokens := make([]TokenAndLength, brace_token.parameter_count, context.temp_allocator); if brace_token.parameter_count == 0 { - return; + return 0; } + end_line_index := 0; + for line, line_index in p.lines[brace_line + 1:] { length := 0; for format_token, i in line.format_tokens { + + //give up on nested structs if format_token.kind == .Comment { break; + } else if format_token.kind == .Open_Paren { + break; } else if format_token.kind == .Open_Brace { seen_brace = true; } else if format_token.kind == .Close_Brace { @@ -797,23 +807,43 @@ align_struct :: proc(p: ^Printer, index: int) { if format_token.kind == .Colon { format_tokens[colon_count] = {format_token = &line.format_tokens[i + 1], length = length}; + + if format_tokens[colon_count].format_token.kind == .Struct { + nested = true; + } + colon_count += 1; largest = max(length, largest); - break; } length += len(format_token.text) + format_token.spaces_before; } + if nested { + end_line_index = line_index + brace_line + 1; + } + if colon_count >= brace_token.parameter_count { break; } + } + + //give up aligning nested, it never looks good + if nested { + for line, line_index in p.lines[end_line_index:] { + for format_token in line.format_tokens { + if format_token.kind == .Close_Brace { + return end_line_index + line_index - index; + } + } + } } for token in format_tokens { token.format_token.spaces_before = largest - token.length + 1; } + return 0; } align_comments :: proc(p: ^Printer) { diff --git a/core/odin/printer/visit.odin b/core/odin/printer/visit.odin index a8f7068c8..c2bd8eaf8 100644 --- a/core/odin/printer/visit.odin +++ b/core/odin/printer/visit.odin @@ -1095,7 +1095,7 @@ visit_expr :: proc(p: ^Printer, expr: ^ast.Expr) { push_ident_token(p, "#force_inline", 0); } - visit_proc_type(p, v.type^); + visit_proc_type(p, v.type^, true); if v.where_clauses != nil { move_line(p, v.where_clauses[0].pos); @@ -1324,9 +1324,22 @@ visit_field_list :: proc(p: ^Printer, list: ^ast.Field_List, add_comma := false, } } -visit_proc_type :: proc(p: ^Printer, proc_type: ast.Proc_Type) { +visit_proc_type :: proc(p: ^Printer, proc_type: ast.Proc_Type, is_proc_lit := false) { - push_generic_token(p, .Proc, 1); + if is_proc_lit { + push_format_token(p, Format_Token { + kind = .Proc, + type = .Proc_Lit, + text = "proc", + spaces_before = 1, + }); + } else { + push_format_token(p, Format_Token { + kind = .Proc, + text = "proc", + spaces_before = 1, + }); + } explicit_calling := false; From 50035f257eb33769211ca49a30c51f9a20440a0e Mon Sep 17 00:00:00 2001 From: Daniel Gavin Date: Thu, 20 May 2021 12:13:23 +0200 Subject: [PATCH 49/49] don't factor in the rhs length for lines that don't have Equal tokens. --- core/odin/printer/printer.odin | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/core/odin/printer/printer.odin b/core/odin/printer/printer.odin index bef1235e9..2a0be1c3c 100644 --- a/core/odin/printer/printer.odin +++ b/core/odin/printer/printer.odin @@ -567,7 +567,7 @@ align_var_decls :: proc(p: ^Printer) { } current_token_index += 1; - + largest_lhs = max(largest_lhs, lhs_length); break; } } @@ -579,12 +579,11 @@ align_var_decls :: proc(p: ^Printer) { if line.format_tokens[current_token_index].kind == .Eq { append(&equal_tokens, TokenAndLength {format_token = &line.format_tokens[current_token_index], length = rhs_length}); + largest_rhs = max(largest_rhs, rhs_length); break; } } - - largest_lhs = max(largest_lhs, lhs_length); - largest_rhs = max(largest_rhs, rhs_length); + } //repeating myself, move to sub procedure