Skip to content
Draft
Show file tree
Hide file tree
Changes from 79 commits
Commits
Show all changes
92 commits
Select commit Hold shift + click to select a range
d8066a5
stop consuming trivia as tokens
bartolomej Jul 26, 2024
76f7107
compute leading and trailing trivia
bartolomej Jul 26, 2024
95438a8
partially fix trivia sourcing
bartolomej Jul 26, 2024
a6619eb
add draft test case
bartolomej Jul 28, 2024
5cffdbf
test doc comments in AST
bartolomej Jul 29, 2024
44c666b
refactor trivia parsing
bartolomej Jul 30, 2024
0539fa3
start tracking comments in ast, add sample tests
bartolomej Jul 31, 2024
1fd5a6f
update comments
bartolomej Jul 31, 2024
96e7347
parse block trailing comments
bartolomej Aug 1, 2024
ff4f9d8
update old parser, remove DocField field on FunctionDeclaration
bartolomej Aug 1, 2024
86bd62b
Merge branch 'refs/heads/master' into preserve-comments
bartolomej Aug 1, 2024
e4a1073
fix existing lexer tests
bartolomej Aug 2, 2024
4158ce8
introduce `isFollowedByTrivia`
bartolomej Aug 10, 2024
e0d8714
remove custom meta left denotations
bartolomej Aug 10, 2024
8fe1b5f
keep emiting space/newline tokens to make the parsing logic work
bartolomej Aug 10, 2024
213ae48
Revert "remove custom meta left denotations"
bartolomej Aug 10, 2024
2d7093d
Revert "introduce `isFollowedByTrivia`"
bartolomej Aug 10, 2024
4c106aa
remove comment parsing logic and token types
bartolomej Aug 10, 2024
ae6525c
combine space and newline trivia types
bartolomej Aug 10, 2024
d1592df
do not track trivia on space tokens
bartolomej Aug 10, 2024
8d2ce86
track leading comment for special function declarations
bartolomej Aug 12, 2024
de4f950
track only comments as trivia in lexer
bartolomej Aug 12, 2024
d98ab21
update tests
bartolomej Aug 12, 2024
05ed569
test eof comment
bartolomej Aug 13, 2024
dcff58b
fix parser tests
bartolomej Aug 13, 2024
4c7047e
Revert "fix existing lexer tests"
bartolomej Aug 13, 2024
2be52ed
remove trivia structs
bartolomej Aug 13, 2024
1c28707
include comments in event declaration
bartolomej Aug 16, 2024
1f1c78f
update variable declaration parsing
bartolomej Sep 21, 2024
79ecacf
update parameter parsing
bartolomej Sep 25, 2024
28604a6
Merge branch 'refs/heads/master' into preserve-comments
bartolomej Sep 25, 2024
63155ed
update variable declaration parsing
bartolomej Sep 27, 2024
b9bd76a
update event parsing tests
bartolomej Sep 27, 2024
f65f9d5
fix old parser declaration tests
bartolomej Sep 28, 2024
a145552
update parsing for composite declaration, declaration field, declarat…
bartolomej Sep 29, 2024
39457a8
update attachment declaration parsing
bartolomej Sep 29, 2024
1c66016
update interface declaration, transaction declaration parsing
bartolomej Sep 29, 2024
3575509
update entitlement parsing
bartolomej Sep 29, 2024
716a3f4
update return statement parsing
bartolomej Oct 6, 2024
da65123
Merge branch 'refs/heads/master' into preserve-comments
bartolomej Apr 23, 2025
de4bb91
fix merge issues
bartolomej May 11, 2025
8f05ada
fix type errors
bartolomej May 11, 2025
0412649
clarify legacy field usage
bartolomej May 11, 2025
1cf6bfd
fix parser test issues
bartolomej May 11, 2025
a9d9924
add todo
bartolomej May 11, 2025
1471e54
update if statement parsing
bartolomej May 12, 2025
27b320a
update if comments test case
bartolomej May 12, 2025
bb4952f
update return, continue, break parsing
bartolomej May 14, 2025
1c7e1a7
update switch/case parsing
bartolomej May 14, 2025
ef4fab5
update while parsing
bartolomej May 15, 2025
6a956b0
update remove from parsing
bartolomej May 15, 2025
9486f3c
update emit statement parsing
bartolomej May 15, 2025
d8c32df
update for statement parsing, start attaching comments to identifiers
bartolomej May 15, 2025
b7feec6
update function declaration or expression stmt parsing
bartolomej Jun 10, 2025
d7ea0a3
Merge branch 'master' into preserve-comments
bartolomej Jun 10, 2025
db9f216
fix lexer tests
bartolomej Jun 10, 2025
3707776
fix pooled lexer reset for comments & other smaller stuff
bartolomej Jun 10, 2025
ef73932
fix leading inline comments for parameters
bartolomej Jul 16, 2025
60eddf3
fix access token comments for variable declaration
bartolomej Jul 16, 2025
50ba770
attach comments to identifier expressions
bartolomej Jul 17, 2025
522daba
remove legacy DocString fields
bartolomej Aug 5, 2025
19ebdab
fix tests
bartolomej Aug 5, 2025
7d19248
Merge branch 'master' into preserve-comments
bartolomej Nov 18, 2025
14834e4
fixed all lint issues
bartolomej Nov 18, 2025
8260761
replaces all usages of `ast.Comments{}` with `ast.EmptyComments`
bartolomej Nov 18, 2025
01ba32b
fix invalid arguments
bartolomej Nov 19, 2025
88a6550
fix json format assertions to include comments field
bartolomej Nov 19, 2025
62cb4a8
revert all comment tracking changes in the old parser, tests passing
bartolomej Nov 21, 2025
99de326
remove NewNominalTypeWithComments
bartolomej Nov 21, 2025
f0eb847
resolve small todos
bartolomej Nov 21, 2025
dcd9b8b
cleanup comments parsing in lexer
bartolomej Nov 21, 2025
64663e3
fix missing comment end error
turbolent Nov 21, 2025
96eb1d2
remove UnexpectedTokenInBlockCommentError
turbolent Nov 21, 2025
3e177c5
make comment tracking configurable
bartolomej Nov 23, 2025
43b4adf
Merge branch 'preserve-comments' of https://github.com/bartolomej/cad…
bartolomej Nov 23, 2025
1992948
rename parser config field
bartolomej Nov 23, 2025
a9352af
fix lexer init in parser
bartolomej Nov 23, 2025
39571f2
avoid unecessary slice allocation
bartolomej Nov 23, 2025
fb5324a
add back IsValidIdentifier
bartolomej Nov 23, 2025
e0f7aa4
break the arguments into multiple lines
bartolomej Nov 23, 2025
8f71c39
add back empty comments test case, small allocation fix, add comment
bartolomej Dec 2, 2025
094ec78
reset trackComments in clear func
bartolomej Dec 2, 2025
73fd987
reuse existing comments slice allocation
bartolomej Dec 2, 2025
6880089
remove unecessary if condition
bartolomej Dec 2, 2025
9cb7e62
Merge branch 'preserve-comments' of https://github.com/bartolomej/cad…
bartolomej Dec 2, 2025
a91c792
fix tests
bartolomej Dec 9, 2025
41b9972
ignore edge case func param comments for simplicity
bartolomej Dec 11, 2025
9941b2e
resolve all unit tests
bartolomej Dec 11, 2025
dd67e6e
Merge branch 'master' into preserve-comments
bartolomej Dec 11, 2025
9457798
move some test cases around
bartolomej Dec 11, 2025
43544d0
refactored to named `Comments Comments` struct field
bartolomej Dec 11, 2025
d1ded08
fix comments json serialization
bartolomej Dec 12, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions ast/access_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func TestMappedAccess_MarshalJSON(t *testing.T) {

t.Parallel()

e := NewNominalType(nil, NewIdentifier(nil, "E", Position{Offset: 1, Line: 2, Column: 3}), []Identifier{})
e := NewNominalType(nil, NewIdentifier(nil, "E", Position{Offset: 1, Line: 2, Column: 3}), []Identifier{}, EmptyComments)

access := NewMappedAccess(e, Position{Offset: 0, Line: 0, Column: 0})
actual, err := json.Marshal(access)
Expand All @@ -68,8 +68,8 @@ func TestEntitlementAccess_MarshalJSON(t *testing.T) {

t.Parallel()

e := NewNominalType(nil, NewIdentifier(nil, "E", Position{Offset: 0, Line: 0, Column: 0}), []Identifier{})
f := NewNominalType(nil, NewIdentifier(nil, "F", Position{Offset: 1, Line: 2, Column: 3}), []Identifier{})
e := NewNominalType(nil, NewIdentifier(nil, "E", Position{Offset: 0, Line: 0, Column: 0}), []Identifier{}, EmptyComments)
f := NewNominalType(nil, NewIdentifier(nil, "F", Position{Offset: 1, Line: 2, Column: 3}), []Identifier{}, EmptyComments)

t.Run("conjunction", func(t *testing.T) {
t.Parallel()
Expand Down
17 changes: 11 additions & 6 deletions ast/attachment.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ type AttachmentDeclaration struct {
BaseType *NominalType
Conformances []*NominalType
Members *Members
DocString string
Range
Comments
}

var _ Element = &AttachmentDeclaration{}
Expand All @@ -50,8 +50,8 @@ func NewAttachmentDeclaration(
baseType *NominalType,
conformances []*NominalType,
members *Members,
docString string,
declarationRange Range,
comments Comments,
) *AttachmentDeclaration {
common.UseMemory(memoryGauge, common.AttachmentDeclarationMemoryUsage)

Expand All @@ -61,8 +61,8 @@ func NewAttachmentDeclaration(
BaseType: baseType,
Conformances: conformances,
Members: members,
DocString: docString,
Range: declarationRange,
Comments: comments,
}
}

Expand Down Expand Up @@ -99,7 +99,7 @@ func (d *AttachmentDeclaration) DeclarationMembers() *Members {
}

func (d *AttachmentDeclaration) DeclarationDocString() string {
return d.DocString
return d.Comments.LeadingDocString()
}

func (*AttachmentDeclaration) Kind() common.CompositeKind {
Expand Down Expand Up @@ -193,9 +193,11 @@ func (d *AttachmentDeclaration) MarshalJSON() ([]byte, error) {
return json.Marshal(&struct {
Type string
*Alias
DocString string
}{
Type: "AttachmentDeclaration",
Alias: (*Alias)(d),
Type: "AttachmentDeclaration",
Alias: (*Alias)(d),
DocString: d.DeclarationDocString(),
})
}

Expand Down Expand Up @@ -290,6 +292,7 @@ type RemoveStatement struct {
Attachment *NominalType
Value Expression
StartPos Position `json:"-"`
Comments
}

var _ Element = &RemoveStatement{}
Expand All @@ -300,13 +303,15 @@ func NewRemoveStatement(
attachment *NominalType,
value Expression,
startPos Position,
comments Comments,
) *RemoveStatement {
common.UseMemory(gauge, common.RemoveStatementMemoryUsage)

return &RemoveStatement{
Attachment: attachment,
Value: value,
StartPos: startPos,
Comments: comments,
}
}

Expand Down
23 changes: 21 additions & 2 deletions ast/attachment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ func TestAttachmentDeclaration_MarshallJSON(t *testing.T) {
Position{Offset: 1, Line: 2, Column: 3},
),
[]Identifier{},
EmptyComments,
),
Conformances: []*NominalType{
{
Expand All @@ -56,8 +57,12 @@ func TestAttachmentDeclaration_MarshallJSON(t *testing.T) {
),
},
},
Members: NewMembers(nil, []Declaration{}),
DocString: "test",
Members: NewMembers(nil, []Declaration{}),
Comments: Comments{
Leading: []*Comment{
NewComment(nil, []byte("///test")),
},
},
Range: Range{
StartPos: Position{Offset: 1, Line: 2, Column: 3},
EndPos: Position{Offset: 4, Line: 5, Column: 6},
Expand Down Expand Up @@ -138,6 +143,11 @@ func TestAttachmentDeclaration_Doc(t *testing.T) {
},
},
Members: NewMembers(nil, []Declaration{}),
Comments: Comments{
Leading: []*Comment{
NewComment(nil, []byte("///test")),
},
},
}

require.Equal(
Expand Down Expand Up @@ -260,6 +270,7 @@ func TestAttachExpressionMarshallJSON(t *testing.T) {
"foo",
Position{Offset: 1, Line: 2, Column: 3},
),
Comments{},
),
Attachment: NewInvocationExpression(
nil,
Expand All @@ -270,6 +281,7 @@ func TestAttachExpressionMarshallJSON(t *testing.T) {
"bar",
Position{Offset: 1, Line: 2, Column: 3},
),
Comments{},
),
[]*TypeAnnotation{},
Arguments{},
Expand All @@ -291,6 +303,7 @@ func TestAttachExpressionMarshallJSON(t *testing.T) {
"EndPos": {"Offset": 3, "Line": 2, "Column": 5},
"Base": {
"Type": "IdentifierExpression",
"Comments": {},
"Identifier": {
"Identifier": "foo",
"StartPos": {"Offset": 1, "Line": 2, "Column": 3},
Expand All @@ -303,6 +316,7 @@ func TestAttachExpressionMarshallJSON(t *testing.T) {
"Type": "InvocationExpression",
"InvokedExpression": {
"Type": "IdentifierExpression",
"Comments": {},
"Identifier": {
"Identifier": "bar",
"StartPos": {"Offset": 1, "Line": 2, "Column": 3},
Expand Down Expand Up @@ -437,6 +451,7 @@ func TestRemoveStatement_MarshallJSON(t *testing.T) {
Position{Offset: 1, Line: 2, Column: 3},
),
[]Identifier{},
EmptyComments,
),
Value: NewIdentifierExpression(
nil,
Expand All @@ -445,6 +460,7 @@ func TestRemoveStatement_MarshallJSON(t *testing.T) {
"baz",
Position{Offset: 1, Line: 2, Column: 3},
),
Comments{},
),
StartPos: Position{Offset: 1, Line: 2, Column: 3},
}
Expand All @@ -461,6 +477,7 @@ func TestRemoveStatement_MarshallJSON(t *testing.T) {
"EndPos": {"Offset": 3, "Line": 2, "Column": 5},
"Value": {
"Type": "IdentifierExpression",
"Comments": {},
"Identifier": {
"Identifier": "baz",
"StartPos": {"Offset": 1, "Line": 2, "Column": 3},
Expand Down Expand Up @@ -503,6 +520,7 @@ func TestRemoveStatement_Doc(t *testing.T) {
Identifier{
Identifier: "baz",
},
Comments{},
),
}

Expand Down Expand Up @@ -563,6 +581,7 @@ func TestRemoveStatement_String(t *testing.T) {
Identifier{
Identifier: "baz",
},
Comments{},
),
}

Expand Down
9 changes: 8 additions & 1 deletion ast/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,23 @@ import (
type Block struct {
Statements []Statement
Range
Comments
}

var _ Element = &Block{}

func NewBlock(memoryGauge common.MemoryGauge, statements []Statement, astRange Range) *Block {
func NewBlock(
memoryGauge common.MemoryGauge,
statements []Statement,
astRange Range,
comments Comments,
) *Block {
common.UseMemory(memoryGauge, common.BlockMemoryUsage)

return &Block{
Statements: statements,
Range: astRange,
Comments: comments,
}
}

Expand Down
1 change: 1 addition & 0 deletions ast/block_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,7 @@ func TestFunctionBlock_MarshalJSON(t *testing.T) {
"Type": "InvocationExpression",
"InvokedExpression": {
"Type": "IdentifierExpression",
"Comments": {},
"Identifier": {
"Identifier": "foobar",
"StartPos": {"Offset": 31, "Line": 32, "Column": 33},
Expand Down
101 changes: 101 additions & 0 deletions ast/comments.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package ast

import (
"bytes"
"strings"

"github.com/onflow/cadence/common"
)

type Comments struct {
Leading []*Comment `json:"-"`
Trailing []*Comment `json:"-"`
}

var EmptyComments = Comments{}

// All combines Leading and Trailing comments in a single array.
func (c Comments) All() []*Comment {
var comments []*Comment
comments = append(comments, c.Leading...)
comments = append(comments, c.Trailing...)
return comments
}

// LeadingDocString prints the leading doc comments to string
func (c Comments) LeadingDocString() string {
var s strings.Builder
for _, comment := range c.Leading {
if comment.IsDoc() {
if s.Len() > 0 {
s.WriteRune('\n')
}
s.Write(comment.Text())
}
}
return s.String()
}

type Comment struct {
source []byte
}

func NewComment(memoryGauge common.MemoryGauge, source []byte) *Comment {
common.UseMemory(memoryGauge, common.NewRawStringMemoryUsage(len(source)))
return &Comment{
source: source,
}
}

var blockCommentDocStringPrefix = []byte("/**")
var blockCommentStringPrefix = []byte("/*")
var lineCommentDocStringPrefix = []byte("///")
var lineCommentStringPrefix = []byte("//")
var blockCommentStringSuffix = []byte("*/")

func (c Comment) Multiline() bool {
return bytes.HasPrefix(c.source, blockCommentStringPrefix)
}

func (c Comment) IsDoc() bool {
if c.Multiline() {
return bytes.HasPrefix(c.source, blockCommentDocStringPrefix)
} else {
return bytes.HasPrefix(c.source, lineCommentDocStringPrefix)
}
}

var commentPrefixes = [][]byte{
blockCommentDocStringPrefix, // must be before blockCommentStringPrefix
blockCommentStringPrefix,
lineCommentDocStringPrefix, // must be before lineCommentStringPrefix
lineCommentStringPrefix,
}

var commentSuffixes = [][]byte{
blockCommentStringSuffix,
}

// Text without opening/closing comment characters /*, /**, */, //
func (c Comment) Text() []byte {
withoutPrefixes := cutOptionalPrefixes(c.source, commentPrefixes)
return cutOptionalSuffixes(withoutPrefixes, commentSuffixes)
}
Comment thread
bartolomej marked this conversation as resolved.

func cutOptionalPrefixes(input []byte, prefixes [][]byte) (output []byte) {
output = input
for _, prefix := range prefixes {
cut, _ := bytes.CutPrefix(output, prefix)
output = cut
}
return
}

func cutOptionalSuffixes(input []byte, suffixes [][]byte) (output []byte) {
output = input
for _, suffix := range suffixes {
cut, _ := bytes.CutSuffix(output, suffix)
output = cut
}
return
}
Loading