fmt: keep empty lines in const blocks (#9071)

pull/9084/head
Lukas Neubert 2021-03-03 08:23:11 +01:00 committed by GitHub
parent b89c6d7826
commit 8a0b5bad94
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 75 additions and 42 deletions

View File

@ -2448,7 +2448,11 @@ pub fn (mut c Checker) const_decl(mut node ast.ConstDecl) {
for i, field in node.fields { for i, field in node.fields {
// TODO Check const name once the syntax is decided // TODO Check const name once the syntax is decided
if field.name in c.const_names { if field.name in c.const_names {
c.error('duplicate const `$field.name`', field.pos) name_pos := token.Position{
...field.pos
len: util.no_cur_mod(field.name, c.mod).len
}
c.error('duplicate const `$field.name`', name_pos)
} }
c.const_names << field.name c.const_names << field.name
field_names << field.name field_names << field.name

View File

@ -310,40 +310,49 @@ pub fn (f Fmt) imp_stmt_str(imp ast.Import) string {
return '$imp.mod$imp_alias_suffix' return '$imp.mod$imp_alias_suffix'
} }
fn (f Fmt) should_insert_newline_before_stmt(stmt ast.Stmt, prev_stmt ast.Stmt) bool { fn (f Fmt) should_insert_newline_before_node(node ast.Node, prev_node ast.Node) bool {
prev_line_nr := prev_stmt.position().last_line
// No need to insert a newline if there is already one // No need to insert a newline if there is already one
if f.out.last_n(2) == '\n\n' { if f.out.last_n(2) == '\n\n' {
return false return false
} }
// Force a newline after a block of HashStmts prev_line_nr := prev_node.position().last_line
if prev_stmt is ast.HashStmt && stmt !is ast.HashStmt && stmt !is ast.ExprStmt { // The nodes are Stmts
return true if node is ast.Stmt && prev_node is ast.Stmt {
} stmt := node as ast.Stmt
// Force a newline after a block of function declarations prev_stmt := prev_node as ast.Stmt
if prev_stmt is ast.FnDecl { // Force a newline after a block of HashStmts
if prev_stmt.no_body && stmt !is ast.FnDecl { if prev_stmt is ast.HashStmt && stmt !is ast.HashStmt && stmt !is ast.ExprStmt {
return true return true
} }
} // Force a newline after a block of function declarations
// The stmt shouldn't have a newline before if prev_stmt is ast.FnDecl {
if stmt.position().line_nr - prev_line_nr <= 1 { if prev_stmt.no_body && stmt !is ast.FnDecl {
return false return true
} }
// Imports are handled special hence they are ignored here }
if stmt is ast.Import || prev_stmt is ast.Import { // The stmt shouldn't have a newline before
return false // if stmt.position().line_nr - prev_line_nr <= 1 {
} // return false
// Attributes are not respected in the stmts position, so this requires a manual check // }
if stmt is ast.StructDecl { // Imports are handled special hence they are ignored here
if stmt.attrs.len > 0 && stmt.attrs[0].pos.line_nr - prev_line_nr <= 1 { if stmt is ast.Import || prev_stmt is ast.Import {
return false return false
} }
} // Attributes are not respected in the stmts position, so this requires a manual check
if stmt is ast.FnDecl { if stmt is ast.StructDecl {
if stmt.attrs.len > 0 && stmt.attrs[0].pos.line_nr - prev_line_nr <= 1 { if stmt.attrs.len > 0 && stmt.attrs[0].pos.line_nr - prev_line_nr <= 1 {
return false return false
}
} }
if stmt is ast.FnDecl {
if stmt.attrs.len > 0 && stmt.attrs[0].pos.line_nr - prev_line_nr <= 1 {
return false
}
}
}
// The node shouldn't have a newline before
if node.position().line_nr - prev_line_nr <= 1 {
return false
} }
return true return true
} }
@ -352,7 +361,7 @@ pub fn (mut f Fmt) stmts(stmts []ast.Stmt) {
mut prev_stmt := if stmts.len > 0 { stmts[0] } else { ast.Stmt{} } mut prev_stmt := if stmts.len > 0 { stmts[0] } else { ast.Stmt{} }
f.indent++ f.indent++
for stmt in stmts { for stmt in stmts {
if !f.pref.building_v && f.should_insert_newline_before_stmt(stmt, prev_stmt) { if !f.pref.building_v && f.should_insert_newline_before_node(stmt, prev_stmt) {
f.out.writeln('') f.out.writeln('')
} }
f.stmt(stmt) f.stmt(stmt)
@ -2241,13 +2250,17 @@ pub fn (mut f Fmt) const_decl(it ast.ConstDecl) {
} }
} }
f.indent++ f.indent++
mut prev_field := if it.fields.len > 0 { ast.Node(it.fields[0]) } else { ast.Node{} }
for field in it.fields { for field in it.fields {
comments := field.comments if field.comments.len > 0 {
mut j := 0 if f.should_insert_newline_before_node(ast.Expr(field.comments[0]), prev_field) {
for j < comments.len && comments[j].pos.pos < field.pos.pos { f.writeln('')
f.comment(comments[j], inline: true) }
f.comments(field.comments, inline: true)
prev_field = ast.Expr(field.comments.last())
}
if f.should_insert_newline_before_node(field, prev_field) {
f.writeln('') f.writeln('')
j++
} }
name := field.name.after('.') name := field.name.after('.')
f.write('$name ') f.write('$name ')
@ -2255,6 +2268,7 @@ pub fn (mut f Fmt) const_decl(it ast.ConstDecl) {
f.write('= ') f.write('= ')
f.expr(field.expr) f.expr(field.expr)
f.writeln('') f.writeln('')
prev_field = field
} }
f.comments_after_last_field(it.end_comments) f.comments_after_last_field(it.end_comments)
f.indent-- f.indent--

View File

@ -1,3 +1,26 @@
// Keep empty lines in const blocks
const (
_ = SomeStruct{
val: 'Multiline field exprs should cause no problems'
}
_ = 1
_ = 'Keep this empty line before'
// Comment before a field
_ = 2
// The empty line above should stay too
_ = 3
// This comment doesn't really belong anywhere
_ = 'A multiline string with a StringInterLiteral...
$foo
...and the ending brace on a newline had a wrong pos.last_line.
'
_ = 4
)
fn keep_single_empty_line() { fn keep_single_empty_line() {
println('a') println('a')
println('b') println('b')

View File

@ -1772,7 +1772,7 @@ fn (mut p Parser) string_expr() ast.Expr {
fills: fills fills: fills
fmts: fmts fmts: fmts
fmt_poss: fposs fmt_poss: fposs
pos: pos pos: pos.extend(p.prev_tok.position())
} }
// need_fmts: prelimery - until checker finds out if really needed // need_fmts: prelimery - until checker finds out if really needed
p.inside_str_interp = false p.inside_str_interp = false
@ -2012,12 +2012,6 @@ fn (mut p Parser) const_decl() ast.ConstDecl {
const_pos := p.tok.position() const_pos := p.tok.position()
p.check(.key_const) p.check(.key_const)
is_block := p.tok.kind == .lpar is_block := p.tok.kind == .lpar
/*
if p.tok.kind != .lpar {
p.error_with_pos('const declaration is missing parentheses `( ... )`', const_pos)
return ast.ConstDecl{}
}
*/
if is_block { if is_block {
p.next() // ( p.next() // (
} }
@ -2039,8 +2033,6 @@ fn (mut p Parser) const_decl() ast.ConstDecl {
pos) pos)
} }
full_name := p.prepend_mod(name) full_name := p.prepend_mod(name)
// name := p.check_name()
// println('!!const: $name')
p.check(.assign) p.check(.assign)
if p.tok.kind == .key_fn { if p.tok.kind == .key_fn {
p.error('const initializer fn literal is not a constant') p.error('const initializer fn literal is not a constant')
@ -2052,7 +2044,7 @@ fn (mut p Parser) const_decl() ast.ConstDecl {
mod: p.mod mod: p.mod
is_pub: is_pub is_pub: is_pub
expr: expr expr: expr
pos: pos pos: pos.extend(expr.position())
comments: comments comments: comments
} }
fields << field fields << field