Skip to content
This repository has been archived by the owner on Feb 19, 2021. It is now read-only.

Add minimal specification #13

Closed
wants to merge 4 commits into from
Closed

Add minimal specification #13

wants to merge 4 commits into from

Conversation

mathiasbynens
Copy link
Member

@mathiasbynens mathiasbynens commented Mar 5, 2019

diff sans whitespace

This is the smallest possible delta compared to String#replace that I could think of. This approach takes the searchValue and turns it into a global regular expression if it isn't already, carefully escaping special characters when needed. It throws when RegExp.prototype[Symbol.replace] is not callable (e.g. when it has been deleted).

This way, we avoid the introduction of RegExp.prototype[Symbol.replaceAll] which would basically do the same thing as RegExp.prototype[Symbol.replace] for global regular expressions anyway.

Thoughts? @psmarshall @schuay @ljharb

This is the smallest possible delta compared to String#replace that I could think of. This approach takes the _searchValue_ and turns it into a global regular expression if it isn't already, carefully escaping special characters when needed. It throws when RegExp.prototype[Symbol.replace] is not callable (e.g. when it has been deleted).

This way, we avoid the introduction of RegExp.prototype[Symbol.replaceAll] which would basically do the same thing as RegExp.prototype[Symbol.replace] for global regular expressions anyway.
It's redundant, since `Call` already throws when needed.
@mathiasbynens
Copy link
Member Author

Some more context:

https://tc39.github.io/ecma262/#sec-well-known-symbols currently says:

@@replace "Symbol.replace" A regular expression method that replaces matched substrings of a string. Called by the String.prototype.replace method.

That description matches perfectly with not just replace but also replaceAll. Therefore, I think it would be preferable to not have to introduce @@replaceAll.

@schuay
Copy link
Collaborator

schuay commented Mar 5, 2019

Preserving offline discussion: I think we should keep the string-pattern-matching-only path (= what String.p.replace currently does when searchValue doesn't have a @@replace symbol).

Passing a string searchValue should not have side effects, and constructing a RegExp + calling exec on it is observable through global properties set on RegExp (e.g. RegExp.input, RegExp.lastMatch, ...).

@mathiasbynens
Copy link
Member Author

I was hoping to avoid it, but forgot about the global RegExp state indeed. :(

1. If _isRegExp_ is *true*, then
1. Let _flags_ be _searchValue_.[[OriginalFlags]].
1. If _flags_ does not contain `"g"`, then
1. Set _flags_ to a copy of _flags_.
Copy link
Member

Choose a reason for hiding this comment

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

Why is this needed? This is a value, not a reference to the internal slot on searchValue.

Alternatively, there’s an existing form of “to the concatenation of a and b” that’s probably better here.

Copy link
Member Author

Choose a reason for hiding this comment

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

This is a value, not a reference to the internal slot on searchValue.

That’s not what https://tc39.github.io/ecma262/#sec-algorithm-conventions says:

Algorithm steps may declare named aliases for any value using the form “Let x be someValue”. These aliases are reference-like in that both x and someValue refer to the same underlying data and modifications to either are visible to both. Algorithm steps that want to avoid this reference-like behaviour should explicitly make a copy of the right-hand side: “Let x be a copy of someValue” creates a shallow copy of someValue.

Copy link
Member

Choose a reason for hiding this comment

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

Interesting, that seems terrifying :-) either way i think the concatenation language would be simpler (it’s what matchAll uses)

1. Let _newString_ be the string-concatenation of the first _pos_ code units of _string_, _replStr_, and the trailing substring of _string_ starting at index _tailPos_. If _pos_ is 0, the first element of the concatenation will be the empty String.
1. Return _newString_.
1. Let _searchString_ be ? ToString(_searchValue_).
1. Set _escapedPattern_ to EscapeRegExpPattern(_src_, `"g"`).
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
1. Set _escapedPattern_ to EscapeRegExpPattern(_src_, `"g"`).
1. Set _escapedPattern_ to EscapeRegExpPattern(_searchString_, `"g"`).

spec.html Outdated Show resolved Hide resolved
1. Set _searchValue_ to ? RegExpCreate(_escapedPattern_, `"g"`).
1. Assert: ? IsRegExp(_searchValue_) is *true*.
1. Let _replacer_ be ? GetMethod(_searchValue_, @@replace).
1. Return ? Call(_replacer_, _searchValue_, « _O_, _replaceValue_ »).
Copy link
Member

Choose a reason for hiding this comment

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

this could also just call Invoke directly?

Co-Authored-By: mathiasbynens <mathias@qiwi.be>
1. Return _newString_.
1. Let _searchString_ be ? ToString(_searchValue_).
1. Set _escapedPattern_ to EscapeRegExpPattern(_src_, `"g"`).
1. Set _searchValue_ to ? RegExpCreate(_escapedPattern_, `"g"`).
Copy link
Contributor

Choose a reason for hiding this comment

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

So... We add g flag and don't create a copy of regexp with required flags, just use original regexp?

@mathiasbynens
Copy link
Member Author

Closing this PR since we'll have to go with a more involved solution anyhow.

@mathiasbynens mathiasbynens deleted the initial-spec-idea branch March 11, 2019 12:11
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants