Gofmt сохранение новых строк

При форматировании идет исходный код с помощью gofmt, он сохраняет символы новой строки, поэтому вы можете группировать элементы вместе. Мне интересно, как это на самом деле реализовано. Я пытался смотреть на исходный код в репозитории GitHub golang/go, но не смог найти его сразу. Если вы посмотрите на https://github.com/golang/go/blob/master/src/go/printer/printer.go#L979:

// intersperse extra newlines if present in the source

Как принтер узнает, что эти дополнительные символы новой строки присутствуют в источнике? Может ли кто-нибудь указать мне правильное направление?

3 ответа

Решение

Гофмт работает на АСТ. Когда вы посмотрите на https://golang.org/pkg/go/ast вы увидите, что у каждого узла есть функции Pos() и End(), которые возвращают token.Pos начала и конца соответственно. По сути, это смещения в исходном файле и, как таковые, ничего не знают о номерах строк / разрывах.

Но в сочетании с token.Fileset такой token.Pos может быть преобразован в token.Position, который включает номер строки. Gofmt делает это в функции printer.go:lineFor().

Фактическая вставка разрывов строки выполняется в node.go:linebreak(). Первым аргументом linebreak () является номер строки, полученный путем вызова вышеупомянутой lineFor () в соответствующем токене.Pos. Функция вычисляет разницу между этим номером строки и номером строки последнего напечатанного токена (отслеживается в поле pos структуры struct printer). Это говорит о том, что токен, который должен быть напечатан сейчас, находится на той же строке во входном файле, что и предыдущий токен. Если это не так, это означает, что программист включил один или несколько разрывов строк в исходный код, и linebreak () выведет не более 1 пустой строки. Хотя он может сохранить все входные разрывы строк, политика gofmt заключается в сжатии серии пустых строк до одной пустой строки.

Если причина, по которой вы задаете этот вопрос, заключается в том, что вы хотите настроить gofmt, взгляните на https://github.com/mbenkmann/goformat

В отличие от большинства лексеров, лексер go включает в себя токены, которые часто удаляются или исключаются лексером компилятора. Поток токенов, испускаемых лексером, включает, помимо прочего, токены для комментариев, подразумеваемые точки с запятой, переводы строк, форм-каналы (FF) и другие пробелы. Это позволяет использовать один и тот же поток токенов для регенерации источника и создания структур, требуемых компилятором, таких как AST.

В internal.go пакет `линия 40-41 есть это:

// Вставляем, используя;; не перевод строки, чтобы номера строк

// в psrc совпадают с src.

И тогда это:

psrc := append([]byte("package p;"), src...)
file, err = parser.ParseFile(fset, filename, psrc, parserMode)

это то, что вы ищете? Если я правильно понял ваш вопрос.

Другие вопросы по тегам