-
Notifications
You must be signed in to change notification settings - Fork 185
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
Make 'from' parameter in TokenList.slice/find inclusive #534
Make 'from' parameter in TokenList.slice/find inclusive #534
Conversation
def leading(token: Token): SeqView[Token, IndexedSeq[Token]] = | ||
tokens.view(0, tok2idx(token)).drop(1).reverse | ||
tokens.view(0, tok2idx(token)).reverse |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe the goal here was to have the token
element dropped from the result. However, this is already handled by the .view
method as the end
parameter is exclusive
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Woah, this was surprising :D
@ tokens.view(0, tok2idx(token)).reverse.mkString
res19: String = "(list { a object"
@ tokens.view(0, tok2idx(token)).drop(1).reverse.mkString
res20: String = "(list { a object"
Yes, the objective was to drop the token.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
val tokens = "foo bar".tokenize.get
tokens: scala.meta.tokens.Tokens = Tokens(, foo, , bar, )
val barIdx = 3
tokens.view(0, barIdx).reverse.mkString("|")
res11: String = " |foo|"
tokens.view(0, barIdx).drop(1).reverse.mkString("|")
res12: String = " |foo"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see, drop(1)
was removing the BOF
token, which is wrong behaviour but probably never surfaced as a problem because it's zero length. Good catch!
b9856fc
to
a15c9b0
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for this contribution @marcelocenerine ! Everything looks good except the slice signature change 👍
def leading(token: Token): SeqView[Token, IndexedSeq[Token]] = | ||
tokens.view(0, tok2idx(token)).drop(1).reverse | ||
tokens.view(0, tok2idx(token)).reverse |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Woah, this was surprising :D
@ tokens.view(0, tok2idx(token)).reverse.mkString
res19: String = "(list { a object"
@ tokens.view(0, tok2idx(token)).drop(1).reverse.mkString
res20: String = "(list { a object"
Yes, the objective was to drop the token.
} | ||
builder.result() | ||
} | ||
def slice(from: Token, to: Token): SeqView[Token, IndexedSeq[Token]] = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this signature change necessary? I think we can keep the signature to avoid a binary breaking change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In fact it is not. Given that the method now returns a view, I wanted to make this fact explicit as well as have the return type consistent the leading*
/trailing*
methods. It wouldn't cause compilation errors but indeed it would break binary compatibility. I'm gonna change it back to Seq
to avoid that.
builder.result() | ||
} | ||
def slice(from: Token, to: Token): Seq[Token] = | ||
tokens.view(tok2idx(from), tok2idx(to)) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
given that the method no longer says that the returned collection is a view, I was going to change the implementation and delegate to Tokens.slice
instead which should be slightly faster as it is backed by an array and does not involve any copying. But then I realized that Tokens.length
is buggy, which breaks isEmpty
:
"foo".tokenize.get.slice(1, 0).isEmpty
res4: Boolean = false
I'm gonna file an issue or submit a PR to Scalameta.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
iirc someone reported a similar problem with Tokens.length
the other day. Length is implemented like this
def length: Int = end - start
Should it be this instead?
def length: Int = math.max(0, end - start)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The root cause is in Tokens.slice
: scalameta/scalameta#1207
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 👍 Thank you for fixing this @marcelocenerine
Addresses Make
from
in TokenList.slice(from, to) inclusive #516. The original goal was to do this only forTokenList.slice
but then I realized thatfind
was also inconsistent.find
is not used anywhere in the reposlice
is used in 2 places:ProcedureSyntax
&ExplicitResultTypes
. For both of them this change won't cause any harm.Fixes a bug in
TokenList.leading
that was causing the first element in the token list (usuallyToken.BOF
) being incorrectly dropped.