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; } } }