Skip to content

tc39/proposal-regexp-legacy-features

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

30 Commits
 
 
 
 
 
 
 
 

Legacy static properties of the RegExp constructor in JavaScript

This is a specification draft for the RegExp legacy static properties in JavaScript. See: tc39/ecma262#137

This does not reflect what the implementations do, but what the editor thinks to be the least bad thing they ought to do in order to maintain web compatibility.

  • The values returned by those properties are updated each time a successful match is done.
  • They may be deleted. (This is important for secured environments that want to avoid global side-effects.)

The proposal includes another feature that needs consensus and implementation experience before being specced:

  • RegExp legacy static properties as well as RegExp.prototype.compile are disabled for instances of proper subclasses of RegExp as well as for cross-realm regexpes. See the detailed motivation here.

See also the differences between this spec and the current implementations.


The amendments are relative to the last ECMAScript specification draft found at: http://tc39.github.io/ecma262/ Changes relative to existing algorithms are marked in bold.

All the amendments are part of Annex B, including those that modify objects or algorithm defined in other parts of the spec.

The %RegExp% instrinsic object, which is the builtin RegExp constructor, has the following additional internal slots:

  • [[RegExpInput]]
  • [[RegExpLastMatch]]
  • [[RegExpLastParen]]
  • [[RegExpLeftContext]]
  • [[RegExpRightContext]]
  • [[RegExpParen1]]
  • [[RegExpParen2]]
  • [[RegExpParen3]]
  • [[RegExpParen4]]
  • [[RegExpParen5]]
  • [[RegExpParen6]]
  • [[RegExpParen7]]
  • [[RegExpParen8]]
  • [[RegExpParen9]]

The initial value of all these internal slots is the empty String.

RegExp instances have an additional slot which optionally keeps a reference to its constructor. It is used for deciding whether a nonstandard legacy feature is enabled for that regexp. The RegExpAlloc abstract operation is modified as follows:

  1. Let obj be ? OrdinaryCreateFromConstructor(newTarget, "%RegExpPrototype%", Β«[[RegExpMatcher]], [[OriginalSource]], [[OriginalFlags]], [[LegacyRegExpConstructor]]Β»).
  2. If newTarget is an Object that has a [[RegExpInput]] internal slot, then
    1. Set the value of obj's [[LegacyRegExpConstructor]] internal slot to newTarget.
  3. Else,
    1. Set the value of obj's [[LegacyRegExpConstructor]] internal slot to undefined.
  4. Let status be DefinePropertyOrThrow(obj, "lastIndex", PropertyDescriptor {[[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false}).
  5. Assert: status is not an abrupt completion.
  6. Return obj.

In the RegExpBuiltInExec abstract operation, a hook is added for updating the static properties of %RegExp% after a successful match. The last three steps of the algorithm are modified as follows:

  1. ...
  2. Perform CreateDataProperty(A, "0", matchedSubstr).
  3. Let capturedValues be an new empty List.
  4. For each integer i such that i > 0 and i ≀ n
    1. ...
    2. Perform CreateDataProperty(A, ToString(i) , capturedValue).
    3. Append capturedValue to the end of capturedValues.
  5. Let LegacyRegExpConstructor be the value of R’s [[LegacyRegExpConstructor]] internal slot.
  6. If SameValue(LegacyRegExpConstructor, %RegExp%) is true, then
    1. Perform UpdateLegacyRegExpStaticProperties(%RegExp%, S, lastIndex, e, capturedValues).
  7. Else,
    1. Perform InvalidateLegacyRegExpStaticProperties(%RegExp%).
  8. Return A.

UpdateLegacyRegExpStaticProperties ( C, S, startIndex, endIndex, capturedValues )

The abstract operation UpdateLegacyRegExpStaticProperties updates the values of the static properties of %RegExp% after a successful match.

  1. Assert: C is an Object that has a [[RegExpInput]] internal slot.
  2. Assert: Type(S) is String.
  3. Let len be the number of code units in S.
  4. Assert: startIndex and endIndex are integers such that 0 ≀ startIndex ≀ endIndex ≀ len.
  5. Assert: capturedValues is a List of Strings.
  6. Let n be the number of elements in capturedValues.
  7. Set the value of C’s [[RegExpInput]] internal slot to S.
  8. Set the value of C’s [[RegExpLastMatch]] internal slot to a String whose length is endIndex - startIndex and containing the code units from S with indices startIndex through endIndex - 1, in ascending order.
  9. If n > 0, set the value of C’s [[RegExpLastParen]] internal slot to the last element of capturedValues.
  10. Else, set the value of C’s [[RegExpLastParen]] internal slot to the empty String.
  11. Set the value of C’s [[RegExpLeftContext]] internal slot to a String whose length is startIndex and containing the code units from S with indices 0 through startIndex - 1, in ascending order.
  12. Set the value of C’s [[RegExpRightContext]] internal slot to a String whose length is len - endIndex and containing the code units from S with indices endIndex through len - 1, in ascending order.
  13. For each integer i such that 1 ≀ i ≀ 9
    1. If i ≀ n, set the value of C’s [[RegExpPareni]] internal slot to the ith element of capturedValues.
    2. Else, set the value of C’s [[RegExpPareni]] internal slot to the empty String.

InvalidateLegacyRegExpStaticProperties ( C)

The abstract operation InvalidateLegacyRegExpStaticProperties marks the values of the static properties of %RegExp% as non-available.

  1. Assert: C is an Object that has a [[RegExpInput]] internal slot.
  2. Set the value of C’s [[RegExpInput]] internal slot to empty.
  3. Set the value of C’s [[RegExpLastMatch]] internal slot to empty.
  4. Set the value of C’s [[RegExpLastParen]] internal slot to empty.
  5. Set the value of C’s [[RegExpLeftContext]] internal slot to empty.
  6. Set the value of C’s [[RegExpRightContext]] internal slot to empty.
  7. Set the value of C’s [[RegExpParen1]] internal slot to empty.
  8. Set the value of C’s [[RegExpParen2]] internal slot to empty.
  9. Set the value of C’s [[RegExpParen3]] internal slot to empty.
  10. Set the value of C’s [[RegExpParen4]] internal slot to empty.
  11. Set the value of C’s [[RegExpParen5]] internal slot to empty.
  12. Set the value of C’s [[RegExpParen6]] internal slot to empty.
  13. Set the value of C’s [[RegExpParen7]] internal slot to empty.
  14. Set the value of C’s [[RegExpParen8]] internal slot to empty.
  15. Set the value of C’s [[RegExpParen9]] internal slot to empty.

Additional properties of the RegExp constructor

All the below properties have the attributes { [[Enumerable]]: false, [[Configurable]]: true }. Moreover, for the properties whose setter is not explicitely defined, the [[Set]] attribute is set to undefined.

RegExp.input

get RegExp.input

  1. Let v be the value of %RegExp%’s [[RegExpInput]] internal slot.
  2. If v is empty, throw a TypeError exception.
  3. Return v.

set RegExp.input = val

  1. Let strVal be ? ToString(val).
  2. Set the value of %RegExp%’s [[RegExpInput]] internal slot to strVal.

RegExp.$_

get RegExp.$_

  1. Let v be the value of %RegExp%’s [[RegExpInput]] internal slot.
  2. If v is empty, throw a TypeError exception.
  3. Return v.

set RegExp.$_ = val

  1. Let strVal be ? ToString(val).
  2. Set the value of %RegExp%’s [[RegExpInput]] internal slot to strVal.

get RegExp.lastMatch

  1. Let v be the value of %RegExp%’s [[RegExpLastMatch]] internal slot.
  2. If v is empty, throw a TypeError exception.
  3. Return v.

get RegExp.$&

  1. Let v be the value of %RegExp%’s [[RegExpLastMatch]] internal slot.
  2. If v is empty, throw a TypeError exception.
  3. Return v.

get RegExp.lastParen

  1. Let v be the value of %RegExp%’s [[RegExpLastParen]] internal slot.
  2. If v is empty, throw a TypeError exception.
  3. Return v.

get RegExp.$+

  1. Let v be the value of %RegExp%’s [[RegExpLastParen]] internal slot.
  2. If v is empty, throw a TypeError exception.
  3. Return v.

get RegExp.leftContext

  1. Let v be the value of %RegExp%’s [[RegExpLeftContext]] internal slot.
  2. If v is empty, throw a TypeError exception.
  3. Return v.

get RegExp.$`

  1. Let v be the value of %RegExp%’s [[RegExpLeftContext]] internal slot.
  2. If v is empty, throw a TypeError exception.
  3. Return v.

get RegExp.rightContext

  1. Let v be the value of %RegExp%’s [[RegExpRightContext]] internal slot.
  2. If v is empty, throw a TypeError exception.
  3. Return v.

get RegExp.$'

  1. Let v be the value of %RegExp%’s [[RegExpRightContext]] internal slot.
  2. If v is empty, throw a TypeError exception.
  3. Return v.

get RegExp.$1

  1. Let v be the value of %RegExp%’s [[RegExpParen1]] internal slot.
  2. If v is empty, throw a TypeError exception.
  3. Return v.

get RegExp.$2

  1. Let v be the value of %RegExp%’s [[RegExpParen2]] internal slot.
  2. If v is empty, throw a TypeError exception.
  3. Return v.

get RegExp.$3

  1. Let v be the value of %RegExp%’s [[RegExpParen3]] internal slot.
  2. If v is empty, throw a TypeError exception.
  3. Return v.

get RegExp.$4

  1. Let v be the value of %RegExp%’s [[RegExpParen4]] internal slot.
  2. If v is empty, throw a TypeError exception.
  3. Return v.

get RegExp.$5

  1. Let v be the value of %RegExp%’s [[RegExpParen5]] internal slot.
  2. If v is empty, throw a TypeError exception.
  3. Return v.

get RegExp.$6

  1. Let v be the value of %RegExp%’s [[RegExpParen6]] internal slot.
  2. If v is empty, throw a TypeError exception.
  3. Return v.

get RegExp.$7

  1. Let v be the value of %RegExp%’s [[RegExpParen7]] internal slot.
  2. If v is empty, throw a TypeError exception.
  3. Return v.

get RegExp.$8

  1. Let v be the value of %RegExp%’s [[RegExpParen8]] internal slot.
  2. If v is empty, throw a TypeError exception.
  3. Return v.

get RegExp.$9

  1. Let v be the value of %RegExp%’s [[RegExpParen9]] internal slot.
  2. If v is empty, throw a TypeError exception.
  3. Return v.

The modification below will disable RegExp.prototype.compile for objects that are not direct instances of RegExp.

  1. Let O be the this value.
  2. If Type(O) is not Object or Type(O) is Object and O does not have a [[RegExpMatcher]] internal slot, then
    1. Throw a TypeError exception.
  3. Let LegacyRegExpConstructor be the value of O’s [[LegacyRegExpConstructor]] internal slot.
  4. If SameValue(LegacyRegExpConstructor, %RegExp%) is false, then
    1. Throw a TypeError exception.
  5. If Type(pattern) is Object and pattern has a [[RegExpMatcher]] internal slot, then
    1. If flags is not undefined, throw a TypeError exception.
    2. Let P be the value of pattern's [[OriginalSource]] internal slot.
    3. Let F be the value of pattern's [[OriginalFlags]] internal slot.
  6. Else,
    1. Let P be pattern.
    2. Let F be flags.
  7. Return RegExpInitialize(O, P, F).

About

Legacy static properties of the RegExp constructor in JavaScript

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks