-
Notifications
You must be signed in to change notification settings - Fork 17.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
go/format: normalize number prefixes and exponents, like cmd/gofmt does #37476
Comments
I wonder if this should just be done in the go/printer; possibly with a flag to control it (of course, the flag won't be exposed to |
I suspect |
A flag to control this behavior is possible, but I don't think it would be helpful, and so I prefer it's not added unless there is a good reason. We can never remove the flag and it'll adding some complexity. If someone wants to "disable" this behavior, or produce Go code that is formatted in a way that is compatible with an older version of Go, a better way of accomplishing that is by using the |
I've investigated this briefly, and want to share my early findings. I looked into how it'd look if the responsibility of formatting numbers was moved from The func (p *printer) spec(spec ast.Spec, n int, doIndent bool) {
switch s := spec.(type) {
case *ast.ImportSpec:
// ...
p.expr(sanitizeImportPath(s.Path))
// ...
}
func sanitizeImportPath(lit *ast.BasicLit) *ast.BasicLit { ... } I realize that printing import paths (especially ones that need to be sanitized) happens much less frequently that numbers may need to be formatted, so it's very possible the same approach would not work for this. But I wanted to try it as a first step, and see if it would at least produce correct results or not. It was easy to perform a simple code transformation and move func (p *printer) expr1(expr ast.Expr, prec1, depth int) {
p.print(expr.Pos())
switch x := expr.(type) {
case *ast.BasicLit:
- p.print(x)
+ switch x.Kind {
+ case token.INT, token.FLOAT, token.IMAG:
+ p.print(normalizeNumber(x))
+ default:
+ p.print(x)
+ }
} // normalizeNumber rewrites base prefixes and exponents to
// use lower-case letters, and removes leading 0's from
// integer imaginary literals. It leaves hexadecimal digits
// alone.
func normalizeNumber(lit *ast.BasicLit) *ast.BasicLit {
if len(lit.Value) < 2 {
return lit // only one digit (common case) - nothing to do
}
// len(lit.Value) >= 2
// ... handle all the cases, return lit if there's no change, or a new &ast.BasicLit if there is
} What I found so far:
|
@dmitshur Thanks for the analysis. I am not concerned about 2). The whole point of What I am concerned is that |
Makes sense, thanks. The current implementation in
I'm open to the possibility of adding a flag, if it is needed. I just have some questions that I'd like to clarify first. Note that the implementation I described above does not update or modify the AST that a user passes into func normalizeNumber(lit *ast.BasicLit) *ast.BasicLit {
// ...
// don't modify the original lit, return a copy with a modified Value
return &ast.BasicLit{ValuePos: lit.ValuePos, Kind: lit.Kind, Value: x}
} I agree one of primary tasks of
Given that Edit: Import sorting is not done as part of the "pretty-printing" process in |
The only reason for the flag would be that some (Semicolons are not even recorded in the AST, so it's harder to argue that we changed something. The printer in the compiler's |
Thanks for elaborating, that's very helpful. I'll think more about this. I have another question for now. Suppose we add a new Put differently, you said:
Is "approved changes" meant to include only the current non-space/semicolon modifications, or is it expected to include future ones too? |
I would use the same flag. Basically, the flag means that |
Change https://golang.org/cl/231461 mentions this issue: |
Normalization of number prefixes and exponents was added in CL 160184 directly in cmd/gofmt. The same behavior change needs to be applied in the go/format package. This is done by moving the normalization code into go/printer, behind a new StdFormat mode, which is then re-used by both cmd/gofmt and go/format. Note that formatting of Go source code changes over time, so the exact byte output produced by go/printer may change between versions of Go when using StdFormat mode. What is guaranteed is that the new formatting is equivalent Go code. Clients looking to format Go code with standard formatting consistent with cmd/gofmt and go/format would need to start using this flag, but a better alternative is to use the go/format package instead. Benchstat numbers on go test go/printer -bench=BenchmarkPrint: name old time/op new time/op delta Print-8 4.56ms ± 1% 4.57ms ± 0% ~ (p=0.700 n=3+3) name old alloc/op new alloc/op delta Print-8 467kB ± 0% 467kB ± 0% ~ (p=1.000 n=3+3) name old allocs/op new allocs/op delta Print-8 17.2k ± 0% 17.2k ± 0% ~ (all equal) That benchmark data doesn't contain any numbers that need to be normalized. More work needs to be performed when formatting Go code with numbers, but it is unavoidable to produce standard formatting. Fixes golang#37476. For golang#37453. Change-Id: If50bde4035c3ee6e6ff0ece5691f6d3566ffe8d5 Reviewed-on: https://go-review.googlesource.com/c/go/+/231461 Run-TryBot: Dmitri Shuralyov <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Robert Griesemer <[email protected]>
Change https://golang.org/cl/237740 mentions this issue: |
For #37419 For #37453 For #37476 Change-Id: Ia032ec844773af421bc4217d5dd6e60996d8e91f Reviewed-on: https://go-review.googlesource.com/c/go/+/237740 Reviewed-by: Robert Griesemer <[email protected]> Reviewed-by: Dmitri Shuralyov <[email protected]>
Change https://golang.org/cl/240683 mentions this issue: |
The StdFormat flag was added as part of CL 231461, where the primary aim was to fix the bug #37476. It's expected that the existing printer modes only adjust spacing but do not change any of the code text itself. A new printing flag served as a way for cmd/gofmt and go/format to delegate a part of formatting work to the printer—where it's more more convenient and efficient to perform—while maintaining current low-level printing behavior of go/printer unmodified. We already have cmd/gofmt and the go/format API that implement standard formatting of Go source code, so there isn't a need to expose StdFormat flag to the world, as it can only cause confusion. Consider that to format source in canonical gofmt style completely it may require tasks A, B, C to be done. In one version of Go, the printer may do both A and B, while cmd/gofmt and go/format will do the remaining task C. In another version, the printer may take on doing just A, while cmd/gofmt and go/format will perform B and C. This makes it hard to add a gofmt-like mode to the printer without compromising on above fluidity. This change prefers to shift back some complexity to the implementation of the standard library, allowing us to avoid creating the new exported printing flag just for the internal needs of gofmt and go/format today. We may still want to re-think the API and consider if something better should be added, but unfortunately there isn't time for Go 1.15. We are not adding new APIs now, so we can defer this decision until Go 1.16 or later, when there is more time. For #37476. For #37453. For #39489. For #37419. Change-Id: I0bb07156dca852b043487099dcf05c5350b29e20 Reviewed-on: https://go-review.googlesource.com/c/go/+/240683 Reviewed-by: Robert Griesemer <[email protected]> Reviewed-by: Russ Cox <[email protected]>
CL 160184 implemented a change to
cmd/gofmt
for Go 1.13 to normalize number prefixes and exponents.The same change should be applied to the
go/format
package (or one of its dependencies, depending on where it's most appropriate to implement).Also see #37453.
/cc @griesemer @cespare @heschik
The text was updated successfully, but these errors were encountered: