Files
sdk/runtime/lib/regexp.cc
T
Stevie Strickland af5fc2d4d2 [VM] Partial support for named regexp captures.
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>
2019-03-19 10:40:15 +00:00

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