af5fc2d4d2
See https://github.com/tc39/proposal-regexp-named-groups for a high-level description of the feature and examples. This is one of the features requested in https://github.com/dart-lang/sdk/issues/34935. This is a partial implementation because while there is a way to retrieve groups via Dart by name, it requires casting the returned Match to the new RegExpMatch interface to avoid changing the RegExp interface. Changing the RegExp interface will happen in a future update, since there are other planned changes to the RegExp interface coming soon and that way we only change it once. See https://github.com/dart-lang/sdk/issues/36171 for more details on the planned changes. Also, since only BMP regular expressions are supported, not full Unicode ones (i.e., those with the /u flag in ECMAscript), \k<NAME> will only be parsed as a named back reference if there are named captures in the string. Otherwise, the \k will be parsed as the identity escape for backwards compatibility. The new tests illustrate this difference. Change-Id: Ieeb0374813db78924c9aa8ac3e652dfb6d4a5934 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/95461 Commit-Queue: Stevie Strickland <sstrickl@google.com> Reviewed-by: Lasse R.H. Nielsen <lrn@google.com> Reviewed-by: Martin Kustermann <kustermann@google.com> Reviewed-by: Jenny Messerly <jmesserly@google.com> Reviewed-by: Johnni Winther <johnniwinther@google.com>
117 lines
4.5 KiB
C++
117 lines
4.5 KiB
C++
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
#include "platform/assert.h"
|
|
#include "vm/bootstrap_natives.h"
|
|
#include "vm/exceptions.h"
|
|
#include "vm/native_entry.h"
|
|
#include "vm/object.h"
|
|
#include "vm/regexp_assembler_bytecode.h"
|
|
#include "vm/regexp_assembler_ir.h"
|
|
#include "vm/regexp_parser.h"
|
|
#include "vm/thread.h"
|
|
|
|
namespace dart {
|
|
|
|
DEFINE_NATIVE_ENTRY(RegExp_factory, 0, 4) {
|
|
ASSERT(
|
|
TypeArguments::CheckedHandle(zone, arguments->NativeArgAt(0)).IsNull());
|
|
GET_NON_NULL_NATIVE_ARGUMENT(String, pattern, arguments->NativeArgAt(1));
|
|
GET_NON_NULL_NATIVE_ARGUMENT(Instance, handle_multi_line,
|
|
arguments->NativeArgAt(2));
|
|
GET_NON_NULL_NATIVE_ARGUMENT(Instance, handle_case_sensitive,
|
|
arguments->NativeArgAt(3));
|
|
bool ignore_case = handle_case_sensitive.raw() != Bool::True().raw();
|
|
bool multi_line = handle_multi_line.raw() == Bool::True().raw();
|
|
|
|
// Parse the pattern once in order to throw any format exceptions within
|
|
// the factory constructor. It is parsed again upon compilation.
|
|
RegExpCompileData compileData;
|
|
// Throws an exception on parsing failure.
|
|
RegExpParser::ParseRegExp(pattern, multi_line, &compileData);
|
|
|
|
// Create a RegExp object containing only the initial parameters.
|
|
return RegExpEngine::CreateRegExp(thread, pattern, multi_line, ignore_case);
|
|
}
|
|
|
|
DEFINE_NATIVE_ENTRY(RegExp_getPattern, 0, 1) {
|
|
const RegExp& regexp = RegExp::CheckedHandle(zone, arguments->NativeArgAt(0));
|
|
ASSERT(!regexp.IsNull());
|
|
return regexp.pattern();
|
|
}
|
|
|
|
DEFINE_NATIVE_ENTRY(RegExp_getIsMultiLine, 0, 1) {
|
|
const RegExp& regexp = RegExp::CheckedHandle(zone, arguments->NativeArgAt(0));
|
|
ASSERT(!regexp.IsNull());
|
|
return Bool::Get(regexp.is_multi_line()).raw();
|
|
}
|
|
|
|
DEFINE_NATIVE_ENTRY(RegExp_getIsCaseSensitive, 0, 1) {
|
|
const RegExp& regexp = RegExp::CheckedHandle(zone, arguments->NativeArgAt(0));
|
|
ASSERT(!regexp.IsNull());
|
|
return Bool::Get(!regexp.is_ignore_case()).raw();
|
|
}
|
|
|
|
DEFINE_NATIVE_ENTRY(RegExp_getGroupCount, 0, 1) {
|
|
const RegExp& regexp = RegExp::CheckedHandle(zone, arguments->NativeArgAt(0));
|
|
ASSERT(!regexp.IsNull());
|
|
if (regexp.is_initialized()) {
|
|
return regexp.num_bracket_expressions();
|
|
}
|
|
const String& pattern = String::Handle(regexp.pattern());
|
|
const String& errmsg =
|
|
String::Handle(String::New("Regular expression is not initialized yet."));
|
|
const String& message = String::Handle(String::Concat(errmsg, pattern));
|
|
const Array& args = Array::Handle(Array::New(1));
|
|
args.SetAt(0, message);
|
|
Exceptions::ThrowByType(Exceptions::kFormat, args);
|
|
return Object::null();
|
|
}
|
|
|
|
DEFINE_NATIVE_ENTRY(RegExp_getGroupNameMap, 0, 1) {
|
|
const RegExp& regexp = RegExp::CheckedHandle(zone, arguments->NativeArgAt(0));
|
|
ASSERT(!regexp.IsNull());
|
|
if (regexp.is_initialized()) {
|
|
return regexp.capture_name_map();
|
|
}
|
|
const String& pattern = String::Handle(regexp.pattern());
|
|
const String& errmsg = String::Handle(
|
|
String::New("Regular expression is not initialized yet. "));
|
|
const String& message = String::Handle(String::Concat(errmsg, pattern));
|
|
const Array& args = Array::Handle(Array::New(1));
|
|
args.SetAt(0, message);
|
|
Exceptions::ThrowByType(Exceptions::kFormat, args);
|
|
return Object::null();
|
|
}
|
|
|
|
static RawObject* ExecuteMatch(Zone* zone,
|
|
NativeArguments* arguments,
|
|
bool sticky) {
|
|
const RegExp& regexp = RegExp::CheckedHandle(zone, arguments->NativeArgAt(0));
|
|
ASSERT(!regexp.IsNull());
|
|
GET_NON_NULL_NATIVE_ARGUMENT(String, subject, arguments->NativeArgAt(1));
|
|
GET_NON_NULL_NATIVE_ARGUMENT(Smi, start_index, arguments->NativeArgAt(2));
|
|
|
|
#if !defined(DART_PRECOMPILED_RUNTIME)
|
|
if (!FLAG_interpret_irregexp) {
|
|
return IRRegExpMacroAssembler::Execute(regexp, subject, start_index,
|
|
/*sticky=*/sticky, zone);
|
|
}
|
|
#endif
|
|
return BytecodeRegExpMacroAssembler::Interpret(regexp, subject, start_index,
|
|
/*sticky=*/sticky, zone);
|
|
}
|
|
|
|
DEFINE_NATIVE_ENTRY(RegExp_ExecuteMatch, 0, 3) {
|
|
// This function is intrinsified. See Intrinsifier::RegExp_ExecuteMatch.
|
|
return ExecuteMatch(zone, arguments, /*sticky=*/false);
|
|
}
|
|
|
|
DEFINE_NATIVE_ENTRY(RegExp_ExecuteMatchSticky, 0, 3) {
|
|
// This function is intrinsified. See Intrinsifier::RegExp_ExecuteMatchSticky.
|
|
return ExecuteMatch(zone, arguments, /*sticky=*/true);
|
|
}
|
|
|
|
} // namespace dart
|