Skip to content
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

Implement backwards iteration for token.Cursor #429

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

emcfarlane
Copy link
Contributor

@emcfarlane emcfarlane commented Jan 22, 2025

This adds methods to token.Cursor to implement backwards iteration with Prev and PrevSkippable. Methods Pop and PopSkippable have been renamed to Next and NextSkippable to match the backward counterparts. The constructor has been altered to NewCursorAt which takes a single starting cursor. The bounds of the cursor iteration are now delimited by the open and closing token when iterating.

These methods will be useful for reading attached and trailing comments.

@emcfarlane emcfarlane requested a review from mcy January 22, 2025 17:41
This adds methods to token.Cursor to implement backwards iteration with
Prev and PrevSkippable. Methods Pop and PopSkippable have been renamed
to Next and NextSkippable to match the backward counterparts.
Seeking is implemented with the method Seek.

This methods will be useful for reading attached and trailing comments.
This removes the Seek method in favor of a new constructor that sets the
cursor at a given ID. The start and end bounds of the cursor are found
when iterating through and encountering a close or open token.
@emcfarlane emcfarlane changed the title Implement backwards iteration and seeking for token.Cursor Implement backwards iteration for token.Cursor Jan 23, 2025
return Zero, report.Span{}
}

// Seek to the end.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is now a range over the cursor to calculate the end. Is that okay? The callers might be able to be updated to infer the end from either knowing the cursor is over a stream or decl.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think all uses of this wind up exhausting the cursor.

I think that if it's seeking to the end, we should just make it a mutating operation, and rename it to something like SeekToEnd().

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

// This may return a skippable token.
//
// Returns the zero token if this cursor is at the beginning of the stream.
func (c *Cursor) BeforeSkippable() Token {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I would prefer if this was named something like PeekPrevSkippable or similar.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed.

return c.stream[c.idx-1].In(c.Context())
}
idx := c.idx - 1
if c.isBackwards && c.idx >= 1 && c.idx <= len(c.Context().Stream().nats) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you spill c.Context().Stream() into its own variable somewhere? It would help make this a little more readable.

Also, one way that you can simplify this is to use slicesx.Get(s.nats, idx).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Switched to slicesx.Get.

Comment on lines 139 to 141
if offset := impl.Offset(); offset < 0 {
idx += offset
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe something like

if impl.IsClose() {
  idx += impl.Offset()
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use IsClose and IsOpen.

Comment on lines 137 to 138
current := ID(c.idx).In(c.Context())
impl := current.nat()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

current is only used once; merge these lines.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

idx int
// The idx is the current token ID if this is a cursor over natural tokens,
// or the index into stream if this is a cursor over synthetic tokens.
idx int
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the code below might be simplified if this is specified to be an index into stream.nats (i.e., a token ID minus one).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment on lines +197 to +199
mark := c.Mark()
tok := c.Next()
c.Rewind(mark)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a fan of this. I would prefer it if Peek did not perform a mutation, because that means it's not thread safe.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Before Peek would mutate the cursor to advance over any skippable tokens, now it remembers the previous place to avoid mutating. But its not thread safe, easy for the caller to copy the cursor if its needed?

return Zero, report.Span{}
}

// Seek to the end.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think all uses of this wind up exhausting the cursor.

I think that if it's seeking to the end, we should just make it a mutating operation, and rename it to something like SeekToEnd().

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants