Any information about adding a trailing comma in ast CompositeLit (for structs)

191 views
Skip to first unread message

Tajmeet Singh

unread,
Oct 22, 2022, 10:00:00 PM10/22/22
to golang-nuts
Hello,

I've been working on a utility to generate constructors for me when I provide it with a path to the file containing the struct and it `Ident`. The idea was that I would just create a ast.Node (FuncDecl) with all the necessary fields but I'm not able to figure out the positioning of the commas.

The function that I'm working on looks something like this:

```Go
func generateConstructor(typeName string, fields ...*ast.Field) *ast.FuncDecl {
    var elts []ast.Expr

    for _, field := range fields {
        elts = append(elts, &ast.KeyValueExpr{
            Key:   field.Names[0],
            Value: field.Names[0],
        })
    }
    return &ast.FuncDecl{
        Doc:  nil,
        Recv: nil,
        Name: ast.NewIdent("New" + typeName),
        Type: &ast.FuncType{
            TypeParams: nil,
            Params: &ast.FieldList{
                List: fields,
            },
            Results: nil,
        },
        Body: &ast.BlockStmt{
            Lbrace: 1,
            List: []ast.Stmt{
                &ast.ReturnStmt{
                    Results: []ast.Expr{
                        &ast.UnaryExpr{
                            Op: token.AND,
                            X: &ast.CompositeLit{
                                Type:   ast.NewIdent(typeName),
                                Elts:   elts,
                                Rbrace: 1,
                            },
                        },
                    },
                },
            },
            Rbrace: 2,
        },
    }
}
```

And when I provide it with a struct like this:

```Go
type Data struct {
    something string
    data      string
    dd        int
}
```
I get this when I do `format.Node` on the generated node `functionDecl`.

```Go
func NewData(something string,
    data string,
    dd int) {
    return &Data{something: something,
        data: data,
        dd: dd}
}
```

However, I was thinking that it would look something like this.

```Go
func NewData(something string,
    data string,
    dd int,
) {
    return &Data{something: something,
        data: data,
        dd: dd,
    }
}
```
(wishful thinking :joy:)

Anyways, I tried to figure out how the `token.COMMA` is used in the parser and how the ast is affected but I couldn't figure it out. Maybe it is related to the `Lbrace` and `Rbrace` values which I'm deliberately missing. Any help would be much appreciated :smile: :pray:
 
PS: I'm not aware of any utility out there so have to roll my own :joy: and learn whilst at it; if people are aware of it, please let me know and I'll inspect their code and figure things out :smile:

David Finkel

unread,
Oct 24, 2022, 8:07:23 PM10/24/22
to Tajmeet Singh, golang-nuts
Looking at the code, I think you're on the right track with Rbrace's location being the determining factor when to insert a comma and move put the closing brace on a new line.
My recommendation would be to use `SetLines` on the (hopefully clean) `token.FileSet` you're passing to `format.Node` to declare some new-line offsets. I don't think the offsets have to make sense as they would in a file that was parsed, but the formatter needs to see the last expression and close brace as being on different lines
 
 
PS: I'm not aware of any utility out there so have to roll my own :joy: and learn whilst at it; if people are aware of it, please let me know and I'll inspect their code and figure things out :smile:

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/ffa312d0-5652-4c2d-9c71-c74bc4bfc56bn%40googlegroups.com.

Tajmeet Singh

unread,
Oct 24, 2022, 9:27:20 PM10/24/22
to golang-nuts
Thanks for looking at it :smile:

Could you elaborate more on how the `SetLines` would work on a `token.FileSet`? I thought that `SetLines` is only for the `os.File` types :sweat: Do you mean that I should create offsets (using SetLines) before I create the FileSet out of it?

David Finkel

unread,
Oct 26, 2022, 12:45:52 PM10/26/22
to Tajmeet Singh, golang-nuts
On Mon, Oct 24, 2022 at 9:27 PM Tajmeet Singh <tjgur...@gmail.com> wrote:
Thanks for looking at it :smile:

Could you elaborate more on how the `SetLines` would work on a `token.FileSet`? I thought that `SetLines` is only for the `os.File` types :sweat: Do you mean that I should create offsets (using SetLines) before I create the FileSet out of it?
Sure, so what I was thinking is that you'd use a different fileset than the one used to parse the AST, and only give it synthetic line-boundaries (the line-widths don't actually have to make sense), and then, when picking the token locations for the different elements in the CompositeLiteral, you'd override the locations of those tokens in the AST so nodes you want to appear on the same line will appear on the same line. (up to formatting constraints)

Another other option (which is much simpler -- and I wish I had thought of before) is to pass the ast.FieldList from the StructType instead of the slice of fields, then you can use the token.Pos from the Closing field. If you use Pos() for the field to set the `Colon` field on the KeyValueExpr, the formatter will see the line boundaries in between fields as appropriate and match the formatting of the struct definition. (AFAICT)
 
Reply all
Reply to author
Forward
0 new messages