Skip to content

Commit

Permalink
Support d flag for regular expressions
Browse files Browse the repository at this point in the history
Signed-off-by: Zoltan Herczeg [email protected]
  • Loading branch information
Zoltan Herczeg committed Sep 15, 2022
1 parent 3a0b874 commit 48100fa
Show file tree
Hide file tree
Showing 7 changed files with 83 additions and 41 deletions.
12 changes: 12 additions & 0 deletions src/builtins/BuiltinRegExp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -610,6 +610,11 @@ static Value builtinRegExpDotAllGetter(ExecutionState& state, Value thisValue, s
return builtinRegExpOptionGetterHelper(state, thisValue, RegExpObject::Option::DotAll);
}

static Value builtinRegExpHasIndicesGetter(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
return builtinRegExpOptionGetterHelper(state, thisValue, RegExpObject::Option::HasIndices);
}

static Value builtinRegExpIgnoreCaseGetter(ExecutionState& state, Value thisValue, size_t argc, Value* argv, Optional<Object*> newTarget)
{
return builtinRegExpOptionGetterHelper(state, thisValue, RegExpObject::Option::IgnoreCase);
Expand Down Expand Up @@ -854,6 +859,13 @@ void GlobalObject::installRegExp(ExecutionState& state)
m_regexpPrototype->directDefineOwnProperty(state, ObjectPropertyName(state, strings->dotAll), desc);
}

{
Value getter = new NativeFunctionObject(state, NativeFunctionInfo(strings->getHasIndices, builtinRegExpHasIndicesGetter, 0, NativeFunctionInfo::Strict));
JSGetterSetter gs(getter, Value());
ObjectPropertyDescriptor desc(gs, ObjectPropertyDescriptor::ConfigurablePresent);
m_regexpPrototype->directDefineOwnProperty(state, ObjectPropertyName(state, strings->hasIndices), desc);
}

{
Value getter = new NativeFunctionObject(state, NativeFunctionInfo(strings->getIgnoreCase, builtinRegExpIgnoreCaseGetter, 0, NativeFunctionInfo::Strict));
JSGetterSetter gs(getter, Value());
Expand Down
75 changes: 63 additions & 12 deletions src/runtime/RegExpObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ bool RegExpObject::defineOwnProperty(ExecutionState& state, const ObjectProperty
|| name->equals(state.context()->staticStrings().unicode.string())
|| name->equals(state.context()->staticStrings().sticky.string())
|| name->equals(state.context()->staticStrings().dotAll.string())
|| name->equals(state.context()->staticStrings().hasIndices.string())
|| name->equals(state.context()->staticStrings().source.string())
|| name->equals(state.context()->staticStrings().flags.string())) {
m_hasOwnPropertyWhichHasDefinedFromRegExpPrototype = true;
Expand All @@ -203,6 +204,11 @@ RegExpObject::Option RegExpObject::parseOption(ExecutionState& state, String* op
auto bufferAccessData = optionString->bufferAccessData();
for (size_t i = 0; i < bufferAccessData.length; i++) {
switch (bufferAccessData.charAt(i)) {
case 'd':
if (tempOption & Option::HasIndices)
ErrorObject::throwBuiltinError(state, ErrorObject::SyntaxError, "RegExp has multiple 'd' flags");
tempOption = (Option)(tempOption | Option::HasIndices);
break;
case 'g':
if (tempOption & Option::Global)
ErrorObject::throwBuiltinError(state, ErrorObject::SyntaxError, "RegExp has multiple 'g' flags");
Expand Down Expand Up @@ -263,7 +269,7 @@ RegExpObject::RegExpCacheEntry& RegExpObject::getCacheEntryAndCompileIfNeeded(Ex
JSC::Yarr::YarrPattern* yarrPattern = nullptr;
try {
JSC::Yarr::ErrorCode errorCode = JSC::Yarr::ErrorCode::NoError;
yarrPattern = JSC::Yarr::YarrPattern::createYarrPattern(source, (JSC::Yarr::RegExpFlags)option, errorCode);
yarrPattern = JSC::Yarr::YarrPattern::createYarrPattern(source, static_cast<JSC::Yarr::RegExpFlags>(static_cast<int>(option) & ~Option::HasIndices), errorCode);
yarrError = JSC::Yarr::errorMessage(errorCode);
} catch (const std::bad_alloc& e) {
ErrorObject::throwBuiltinError(state, ErrorObject::TypeError, "got too complicated RegExp pattern to process");
Expand Down Expand Up @@ -478,6 +484,41 @@ ArrayObject* RegExpObject::createRegExpMatchedArray(ExecutionState& state, const
arr->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().groups), ObjectPropertyDescriptor(Value(groups), ObjectPropertyDescriptor::AllPresent));
}

if (option() & HasIndices) {
ArrayObject* indices = new ArrayObject(state, len);
arr->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().indices), ObjectPropertyDescriptor(Value(indices), ObjectPropertyDescriptor::AllPresent));

size_t idx = 0;
for (unsigned i = 0; i < result.m_matchResults.size(); i++) {
for (unsigned j = 0; j < result.m_matchResults[i].size(); j++) {
if (result.m_matchResults[i][j].m_start == std::numeric_limits<unsigned>::max()) {
indices->defineOwnIndexedPropertyWithoutExpanding(state, idx++, Value());
} else {
ArrayObject* pair = new ArrayObject(state, 2);
pair->defineOwnIndexedPropertyWithoutExpanding(state, 0, Value(result.m_matchResults[i][j].m_start));
pair->defineOwnIndexedPropertyWithoutExpanding(state, 1, Value(result.m_matchResults[i][j].m_end));

indices->defineOwnIndexedPropertyWithoutExpanding(state, idx++, Value(pair));
}
}
}

if (m_yarrPattern->m_namedGroupToParenIndex.empty()) {
indices->defineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().groups), ObjectPropertyDescriptor(Value(), ObjectPropertyDescriptor::AllPresent));
} else {
Object* groups = new Object(state);
groups->setPrototype(state, Value(Value::Null));
for (auto it = m_yarrPattern->m_captureGroupNames.begin(); it != m_yarrPattern->m_captureGroupNames.end(); ++it) {
auto foundMapElement = m_yarrPattern->m_namedGroupToParenIndex.find(*it);
if (foundMapElement != m_yarrPattern->m_namedGroupToParenIndex.end()) {
groups->directDefineOwnProperty(state, ObjectPropertyName(state, it->impl()),
ObjectPropertyDescriptor(indices->getOwnProperty(state, ObjectPropertyName(state, foundMapElement->second)).value(state, this), ObjectPropertyDescriptor::AllPresent));
}
}
indices->directDefineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().groups), ObjectPropertyDescriptor(Value(groups), ObjectPropertyDescriptor::AllPresent));
}
}

// FIXME RegExp should have own Realm internal slot when allocated
if (state.context() == this->getFunctionRealm(state)) {
if (!this->legacyFeaturesEnabled()) {
Expand Down Expand Up @@ -534,7 +575,7 @@ Value RegExpObject::regexpFlagsValue(ExecutionState& state, Object* obj)

String* RegExpObject::computeRegExpOptionString(ExecutionState& state, Object* obj)
{
char flags[7] = { 0 };
char flags[8] = { 0 };
size_t flagsIdx = 0;
size_t cacheIndex = 0;

Expand All @@ -545,59 +586,69 @@ String* RegExpObject::computeRegExpOptionString(ExecutionState& state, Object* o
cacheIndex |= 1 << 0;
}

if (opt & RegExpObject::Option::HasIndices) {
flags[flagsIdx++] = 'd';
cacheIndex |= 1 << 1;
}

if (opt & RegExpObject::Option::IgnoreCase) {
flags[flagsIdx++] = 'i';
cacheIndex |= 1 << 1;
cacheIndex |= 1 << 2;
}

if (opt & RegExpObject::Option::MultiLine) {
flags[flagsIdx++] = 'm';
cacheIndex |= 1 << 2;
cacheIndex |= 1 << 3;
}

if (opt & RegExpObject::Option::DotAll) {
flags[flagsIdx++] = 's';
cacheIndex |= 1 << 3;
cacheIndex |= 1 << 4;
}

if (opt & RegExpObject::Option::Unicode) {
flags[flagsIdx++] = 'u';
cacheIndex |= 1 << 4;
cacheIndex |= 1 << 5;
}

if (opt & RegExpObject::Option::Sticky) {
flags[flagsIdx++] = 'y';
cacheIndex |= 1 << 5;
cacheIndex |= 1 << 6;
}
} else {
if (obj->get(state, ObjectPropertyName(state, state.context()->staticStrings().global)).value(state, obj).toBoolean(state)) {
flags[flagsIdx++] = 'g';
cacheIndex |= 1 << 0;
}

if (obj->get(state, ObjectPropertyName(state, state.context()->staticStrings().hasIndices)).value(state, obj).toBoolean(state)) {
flags[flagsIdx++] = 'd';
cacheIndex |= 1 << 1;
}

if (obj->get(state, ObjectPropertyName(state, state.context()->staticStrings().ignoreCase)).value(state, obj).toBoolean(state)) {
flags[flagsIdx++] = 'i';
cacheIndex |= 1 << 1;
cacheIndex |= 1 << 2;
}

if (obj->get(state, ObjectPropertyName(state, state.context()->staticStrings().multiline)).value(state, obj).toBoolean(state)) {
flags[flagsIdx++] = 'm';
cacheIndex |= 1 << 2;
cacheIndex |= 1 << 3;
}

if (obj->get(state, ObjectPropertyName(state, state.context()->staticStrings().dotAll)).value(state, obj).toBoolean(state)) {
flags[flagsIdx++] = 's';
cacheIndex |= 1 << 3;
cacheIndex |= 1 << 4;
}

if (obj->get(state, ObjectPropertyName(state, state.context()->staticStrings().unicode)).value(state, obj).toBoolean(state)) {
flags[flagsIdx++] = 'u';
cacheIndex |= 1 << 4;
cacheIndex |= 1 << 5;
}

if (obj->get(state, ObjectPropertyName(state, state.context()->staticStrings().sticky)).value(state, obj).toBoolean(state)) {
flags[flagsIdx++] = 'y';
cacheIndex |= 1 << 5;
cacheIndex |= 1 << 6;
}
}

Expand Down
2 changes: 2 additions & 0 deletions src/runtime/RegExpObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ class RegExpObject : public DerivedObject {
Sticky = 1 << 3,
Unicode = 1 << 4,
DotAll = 1 << 5,
// HasIndices is not a Yarr property
HasIndices = 1 << 6,
};

struct RegExpCacheKey {
Expand Down
1 change: 1 addition & 0 deletions src/runtime/StaticStrings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ void StaticStrings::initStaticStrings()
INIT_STATIC_STRING(getFlags, "get flags");
INIT_STATIC_STRING(getFormat, "get format");
INIT_STATIC_STRING(getGlobal, "get global");
INIT_STATIC_STRING(getHasIndices, "get hasIndices");
INIT_STATIC_STRING(getHourCycle, "get hourCycle");
INIT_STATIC_STRING(getHourCycles, "get hourCycles");
INIT_STATIC_STRING(getIgnoreCase, "get ignoreCase");
Expand Down
3 changes: 3 additions & 0 deletions src/runtime/StaticStrings.h
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@ namespace Escargot {
F(grow) \
F(growable) \
F(has) \
F(hasIndices) \
F(hasInstance) \
F(hasOwn) \
F(hasOwnProperty) \
Expand All @@ -287,6 +288,7 @@ namespace Escargot {
F(includes) \
F(index) \
F(indexOf) \
F(indices) \
F(input) \
F(instanceof) \
F(interface) \
Expand Down Expand Up @@ -976,6 +978,7 @@ class StaticStrings {
AtomicString getFlags;
AtomicString getFormat;
AtomicString getGlobal;
AtomicString getHasIndices;
AtomicString getHourCycle;
AtomicString getHourCycles;
AtomicString getIgnoreCase;
Expand Down
4 changes: 2 additions & 2 deletions src/runtime/VMInstance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -386,8 +386,8 @@ VMInstance::VMInstance(const char* locale, const char* timezone, const char* bas
m_staticStrings.initStaticStrings();

m_regexpCache = new (GC) RegExpCacheMap();
m_regexpOptionStringCache = (ASCIIString**)GC_MALLOC(64 * sizeof(ASCIIString*));
memset(m_regexpOptionStringCache, 0, 64 * sizeof(ASCIIString*));
m_regexpOptionStringCache = (ASCIIString**)GC_MALLOC(128 * sizeof(ASCIIString*));
memset(m_regexpOptionStringCache, 0, 128 * sizeof(ASCIIString*));

#if defined(ENABLE_ICU)
#if !defined(OS_WINDOWS_UWP)
Expand Down
27 changes: 0 additions & 27 deletions tools/test/test262/excludelist.orig.xml
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,6 @@
<test id="built-ins/JSON/stringify/value-string-escape-unicode"><reason>TODO</reason></test>
<test id="built-ins/Object/freeze/proxy-with-defineProperty-handler"><reason>TODO</reason></test>
<test id="built-ins/Object/seal/proxy-with-defineProperty-handler"><reason>TODO</reason></test>
<test id="built-ins/RegExp/duplicate-flags"><reason>TODO</reason></test>
<test id="built-ins/RegExp/lookBehind/alternations"><reason>TODO</reason></test>
<test id="built-ins/RegExp/lookBehind/back-references"><reason>TODO</reason></test>
<test id="built-ins/RegExp/lookBehind/back-references-to-captures"><reason>TODO</reason></test>
Expand All @@ -193,19 +192,6 @@
<test id="built-ins/RegExp/lookBehind/sticky"><reason>TODO</reason></test>
<test id="built-ins/RegExp/lookBehind/variable-length"><reason>TODO</reason></test>
<test id="built-ins/RegExp/lookBehind/word-boundary"><reason>TODO</reason></test>
<test id="built-ins/RegExp/match-indices/indices-array"><reason>TODO</reason></test>
<test id="built-ins/RegExp/match-indices/indices-array-element"><reason>TODO</reason></test>
<test id="built-ins/RegExp/match-indices/indices-array-matched"><reason>TODO</reason></test>
<test id="built-ins/RegExp/match-indices/indices-array-non-unicode-match"><reason>TODO</reason></test>
<test id="built-ins/RegExp/match-indices/indices-array-properties"><reason>TODO</reason></test>
<test id="built-ins/RegExp/match-indices/indices-array-unicode-match"><reason>TODO</reason></test>
<test id="built-ins/RegExp/match-indices/indices-array-unicode-property-names"><reason>TODO</reason></test>
<test id="built-ins/RegExp/match-indices/indices-array-unmatched"><reason>TODO</reason></test>
<test id="built-ins/RegExp/match-indices/indices-groups-object"><reason>TODO</reason></test>
<test id="built-ins/RegExp/match-indices/indices-groups-object-undefined"><reason>TODO</reason></test>
<test id="built-ins/RegExp/match-indices/indices-groups-object-unmatched"><reason>TODO</reason></test>
<test id="built-ins/RegExp/match-indices/indices-groups-properties"><reason>TODO</reason></test>
<test id="built-ins/RegExp/match-indices/indices-property"><reason>TODO</reason></test>
<test id="built-ins/RegExp/named-groups/lookbehind"><reason>TODO</reason></test>
<test id="built-ins/RegExp/named-groups/non-unicode-property-names-valid"><reason>TODO</reason></test>
<test id="built-ins/RegExp/named-groups/unicode-property-names-valid"><reason>TODO</reason></test>
Expand Down Expand Up @@ -461,19 +447,6 @@
<test id="built-ins/RegExp/prototype/Symbol.search/u-lastindex-advance"><reason>TODO</reason></test>
<test id="built-ins/RegExp/prototype/Symbol.split/u-lastindex-adv-thru-match"><reason>TODO</reason></test>
<test id="built-ins/RegExp/prototype/exec/u-lastindex-adv"><reason>TODO</reason></test>
<test id="built-ins/RegExp/prototype/flags/coercion-hasIndices"><reason>TODO</reason></test>
<test id="built-ins/RegExp/prototype/flags/get-order"><reason>TODO</reason></test>
<test id="built-ins/RegExp/prototype/flags/rethrow"><reason>TODO</reason></test>
<test id="built-ins/RegExp/prototype/flags/return-order"><reason>TODO</reason></test>
<test id="built-ins/RegExp/prototype/flags/this-val-regexp"><reason>TODO</reason></test>
<test id="built-ins/RegExp/prototype/hasIndices/cross-realm"><reason>TODO</reason></test>
<test id="built-ins/RegExp/prototype/hasIndices/length"><reason>TODO</reason></test>
<test id="built-ins/RegExp/prototype/hasIndices/name"><reason>TODO</reason></test>
<test id="built-ins/RegExp/prototype/hasIndices/prop-desc"><reason>TODO</reason></test>
<test id="built-ins/RegExp/prototype/hasIndices/this-val-invalid-obj"><reason>TODO</reason></test>
<test id="built-ins/RegExp/prototype/hasIndices/this-val-non-obj"><reason>TODO</reason></test>
<test id="built-ins/RegExp/prototype/hasIndices/this-val-regexp"><reason>TODO</reason></test>
<test id="built-ins/RegExp/prototype/hasIndices/this-val-regexp-prototype"><reason>TODO</reason></test>
<test id="built-ins/RegExp/prototype/source/value-line-terminator"><reason>TODO</reason></test>
<test id="built-ins/RegExp/quantifier-integer-limit"><reason>TODO</reason></test>
<test id="built-ins/RegExp/unicode_character_class_backspace_escape"><reason>TODO</reason></test>
Expand Down

0 comments on commit 48100fa

Please sign in to comment.