fmt: keep newlines between toplevel stmts (#8383)

pull/8410/head
Lukas Neubert 2021-01-29 11:17:59 +01:00 committed by GitHub
parent afddcda7a3
commit e47c13903b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 84 additions and 26 deletions

View File

@ -61,14 +61,10 @@ pub fn fmt(file ast.File, table &table.Table, is_debug bool) string {
}
f.process_file_imports(file)
f.set_current_module_name('main')
for stmt in file.stmts {
if stmt is ast.Import {
// Just remember the position of the imports for now
f.import_pos = f.out.len
// f.imports(f.file.imports)
}
f.stmt(stmt)
}
// As these are toplevel stmts, the indent increase done in f.stmts() has to be compensated
f.indent--
f.stmts(file.stmts)
f.indent++
// for comment in file.comments { println('$comment.line_nr $comment.text') }
f.imports(f.file.imports) // now that we have all autoimports, handle them
res := f.out.str().trim_space() + '\n'
@ -271,20 +267,39 @@ pub fn (f Fmt) imp_stmt_str(imp ast.Import) string {
return '$imp.mod$imp_alias_suffix'
}
pub fn (mut f Fmt) stmts(stmts []ast.Stmt) {
f.indent++
mut prev_line_nr := 0
if stmts.len >= 1 {
prev_pos := stmts[0].position()
prev_line_nr = util.imax(prev_pos.line_nr, prev_pos.last_line)
fn (mut f Fmt) should_insert_newline_before_stmt(stmt ast.Stmt, prev_stmt ast.Stmt) bool {
prev_line_nr := prev_stmt.position().last_line
// The stmt either has or shouldn't have a newline before
if stmt.position().line_nr - prev_line_nr <= 1 || f.out.last_n(2) == '\n\n' {
return false
}
// Imports are handled special hence they are ignored here
if stmt is ast.Import || prev_stmt is ast.Import {
return false
}
// Attributes are not respected in the stmts position, so we have to check it manually
if stmt is ast.StructDecl {
if stmt.attrs.len > 0 && stmt.attrs[0].pos.line_nr - prev_line_nr <= 1 {
return false
}
}
if stmt is ast.FnDecl {
if stmt.attrs.len > 0 && stmt.attrs[0].pos.line_nr - prev_line_nr <= 1 {
return false
}
}
return true
}
pub fn (mut f Fmt) stmts(stmts []ast.Stmt) {
mut prev_stmt := if stmts.len > 0 { stmts[0] } else { ast.Stmt{} }
f.indent++
for stmt in stmts {
if stmt.position().line_nr - prev_line_nr > 1 {
if f.should_insert_newline_before_stmt(stmt, prev_stmt) {
f.out.writeln('')
}
f.stmt(stmt)
prev_pos := stmt.position()
prev_line_nr = util.imax(prev_pos.line_nr, prev_pos.last_line)
prev_stmt = stmt
}
f.indent--
}
@ -362,6 +377,8 @@ pub fn (mut f Fmt) stmt(node ast.Stmt) {
}
ast.Import {
// Imports are handled after the file is formatted, to automatically add necessary modules
// Just remember the position of the imports for now
f.import_pos = f.out.len
// f.imports(f.file.imports)
}
ast.InterfaceDecl {

View File

@ -1,5 +1,6 @@
import semver
// as semver
fn main() {
}

View File

@ -0,0 +1,8 @@
// comment above HashStmts
#flag linux -lsdl2
#include "stdio.h"
// comment between with newlines around
#include "header.h"
#include "sqlite3.h"

View File

@ -0,0 +1,5 @@
// import time This should be commented out
import os
import rand
// another comment after imports

View File

@ -0,0 +1,19 @@
// Module with attribute
[manualfree]
module websocket
fn main() {}
// This should stay between both functions
fn x() {}
// doc comment above an attributed function
[inline]
fn y_with_attr() {
}
// doc comment above an attributed struct
[typedef]
struct Foo {
}

View File

@ -13,6 +13,7 @@ type MyInt = int
pub type Abc = f32
// Fn type decl
type EmptyFn = fn ()
type OneArgFn = fn (i int)

View File

@ -16,7 +16,7 @@ const (
// // #include, #flag, #v
fn (mut p Parser) hash() ast.HashStmt {
mut pos := p.prev_tok.position()
pos := p.tok.position()
val := p.tok.lit
kind := val.all_before(' ')
p.next()

View File

@ -15,12 +15,11 @@ fn (mut p Parser) if_expr(is_comptime bool) ast.IfExpr {
p.inside_ct_if_expr = was_inside_ct_if_expr
}
p.inside_if_expr = true
mut pos := if is_comptime {
mut pos := p.tok.position()
if is_comptime {
p.inside_ct_if_expr = true
p.next() // `$`
p.prev_tok.position().extend(p.tok.position())
} else {
p.tok.position()
pos = p.prev_tok.position().extend(p.tok.position())
}
mut branches := []ast.IfBranch{}
mut has_else := false

View File

@ -204,7 +204,11 @@ pub fn (mut p Parser) parse() ast.File {
}
// module
module_decl := p.module_decl()
stmts << module_decl
if module_decl.is_skipped {
stmts.insert(0, ast.Stmt(module_decl))
} else {
stmts << module_decl
}
// imports
for {
if p.tok.kind == .key_import {
@ -513,8 +517,10 @@ pub fn (mut p Parser) top_stmt() ast.Stmt {
return p.struct_decl()
}
.dollar {
if_expr := p.if_expr(true)
return ast.ExprStmt{
expr: p.if_expr(true)
expr: if_expr
pos: if_expr.pos
}
}
.hash {
@ -1753,6 +1759,7 @@ fn (mut p Parser) parse_number_literal() ast.Expr {
fn (mut p Parser) module_decl() ast.Module {
mut module_attrs := []table.Attr{}
mut attrs_pos := p.tok.position()
if p.tok.kind == .lsbr {
p.attributes()
module_attrs = p.attrs
@ -1788,7 +1795,7 @@ fn (mut p Parser) module_decl() ast.Module {
return mod_node
}
}
module_pos = module_pos.extend(name_pos)
module_pos = attrs_pos.extend(name_pos)
}
full_name := util.qualify_module(name, p.file_name)
p.mod = full_name

View File

@ -154,10 +154,11 @@ pub fn (mut s Scanner) set_current_tidx(cidx int) {
fn (mut s Scanner) new_token(tok_kind token.Kind, lit string, len int) token.Token {
cidx := s.tidx
s.tidx++
line_offset := if tok_kind == .hash { 0 } else { 1 }
return token.Token{
kind: tok_kind
lit: lit
line_nr: s.line_nr + 1
line_nr: s.line_nr + line_offset
pos: s.pos - len + 1
len: len
tidx: cidx