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); - } -} */