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)
это то, что вы ищете? Если я правильно понял ваш вопрос.