1// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#include "platform/assert.h"
6#include "vm/bootstrap_natives.h"
7#include "vm/canonical_tables.h"
8#include "vm/exceptions.h"
9#include "vm/native_entry.h"
10#include "vm/object.h"
11#include "vm/object_store.h"
12#include "vm/regexp_assembler_bytecode.h"
13#include "vm/regexp_parser.h"
14#include "vm/reusable_handles.h"
15#include "vm/symbols.h"
16#include "vm/thread.h"
17
18#if !defined(DART_PRECOMPILED_RUNTIME)
19#include "vm/regexp_assembler_ir.h"
20#endif // !defined(DART_PRECOMPILED_RUNTIME)
21
22namespace dart {
23
24DEFINE_NATIVE_ENTRY(RegExp_factory, 0, 6) {
25 ASSERT(
26 TypeArguments::CheckedHandle(zone, arguments->NativeArgAt(0)).IsNull());
27 GET_NON_NULL_NATIVE_ARGUMENT(String, pattern, arguments->NativeArgAt(1));
28
29 bool multi_line = arguments->NativeArgAt(index: 2) == Bool::True().ptr();
30 bool ignore_case = arguments->NativeArgAt(index: 3) != Bool::True().ptr();
31 bool unicode = arguments->NativeArgAt(index: 4) == Bool::True().ptr();
32 bool dot_all = arguments->NativeArgAt(index: 5) == Bool::True().ptr();
33
34 RegExpFlags flags;
35 flags.SetGlobal(); // All dart regexps are global.
36 if (ignore_case) flags.SetIgnoreCase();
37 if (multi_line) flags.SetMultiLine();
38 if (unicode) flags.SetUnicode();
39 if (dot_all) flags.SetDotAll();
40
41 RegExpKey lookup_key(pattern, flags);
42 RegExp& regexp = RegExp::Handle(zone: thread->zone());
43 {
44 REUSABLE_OBJECT_HANDLESCOPE(thread);
45 REUSABLE_SMI_HANDLESCOPE(thread);
46 REUSABLE_WEAK_ARRAY_HANDLESCOPE(thread);
47 Object& key = thread->ObjectHandle();
48 Smi& value = thread->SmiHandle();
49 WeakArray& data = thread->WeakArrayHandle();
50 data = thread->isolate_group()->object_store()->regexp_table();
51 CanonicalRegExpSet table(&key, &value, &data);
52 regexp ^= table.GetOrNull(key: lookup_key);
53 table.Release();
54 if (!regexp.IsNull()) {
55 return regexp.ptr();
56 }
57 }
58
59 // Parse the pattern once in order to throw any format exceptions within
60 // the factory constructor. It is parsed again upon compilation.
61 RegExpCompileData compileData;
62 // Throws an exception on parsing failure.
63 RegExpParser::ParseRegExp(input: pattern, regexp_flags: flags, result: &compileData);
64
65 {
66 RegExpKey lookup_symbol_key(String::Handle(ptr: Symbols::New(thread, str: pattern)),
67 flags);
68 SafepointMutexLocker ml(thread->isolate_group()->symbols_mutex());
69 CanonicalRegExpSet table(
70 thread->zone(),
71 thread->isolate_group()->object_store()->regexp_table());
72 regexp ^= table.InsertNewOrGet(key: lookup_symbol_key);
73 thread->isolate_group()->object_store()->set_regexp_table(table.Release());
74 }
75
76 ASSERT(regexp.flags() == flags);
77 return regexp.ptr();
78}
79
80DEFINE_NATIVE_ENTRY(RegExp_getPattern, 0, 1) {
81 const RegExp& regexp = RegExp::CheckedHandle(zone, ptr: arguments->NativeArgAt(index: 0));
82 ASSERT(!regexp.IsNull());
83 return regexp.pattern();
84}
85
86DEFINE_NATIVE_ENTRY(RegExp_getIsMultiLine, 0, 1) {
87 const RegExp& regexp = RegExp::CheckedHandle(zone, ptr: arguments->NativeArgAt(index: 0));
88 ASSERT(!regexp.IsNull());
89 return Bool::Get(value: regexp.flags().IsMultiLine()).ptr();
90}
91
92DEFINE_NATIVE_ENTRY(RegExp_getIsUnicode, 0, 1) {
93 const RegExp& regexp = RegExp::CheckedHandle(zone, ptr: arguments->NativeArgAt(index: 0));
94 ASSERT(!regexp.IsNull());
95 return Bool::Get(value: regexp.flags().IsUnicode()).ptr();
96}
97
98DEFINE_NATIVE_ENTRY(RegExp_getIsDotAll, 0, 1) {
99 const RegExp& regexp = RegExp::CheckedHandle(zone, ptr: arguments->NativeArgAt(index: 0));
100 ASSERT(!regexp.IsNull());
101 return Bool::Get(value: regexp.flags().IsDotAll()).ptr();
102}
103
104DEFINE_NATIVE_ENTRY(RegExp_getIsCaseSensitive, 0, 1) {
105 const RegExp& regexp = RegExp::CheckedHandle(zone, ptr: arguments->NativeArgAt(index: 0));
106 ASSERT(!regexp.IsNull());
107 return Bool::Get(value: !regexp.flags().IgnoreCase()).ptr();
108}
109
110DEFINE_NATIVE_ENTRY(RegExp_getGroupCount, 0, 1) {
111 const RegExp& regexp = RegExp::CheckedHandle(zone, ptr: arguments->NativeArgAt(index: 0));
112 ASSERT(!regexp.IsNull());
113 if (regexp.is_initialized()) {
114 return Smi::New(value: regexp.num_bracket_expressions());
115 }
116 const String& pattern = String::Handle(ptr: regexp.pattern());
117 const String& errmsg =
118 String::Handle(ptr: String::New(cstr: "Regular expression is not initialized yet."));
119 const String& message = String::Handle(ptr: String::Concat(str1: errmsg, str2: pattern));
120 const Array& args = Array::Handle(ptr: Array::New(len: 1));
121 args.SetAt(index: 0, value: message);
122 Exceptions::ThrowByType(type: Exceptions::kFormat, arguments: args);
123 return Object::null();
124}
125
126DEFINE_NATIVE_ENTRY(RegExp_getGroupNameMap, 0, 1) {
127 const RegExp& regexp = RegExp::CheckedHandle(zone, ptr: arguments->NativeArgAt(index: 0));
128 ASSERT(!regexp.IsNull());
129 if (regexp.is_initialized()) {
130 return regexp.capture_name_map();
131 }
132 const String& pattern = String::Handle(ptr: regexp.pattern());
133 const String& errmsg = String::Handle(
134 ptr: String::New(cstr: "Regular expression is not initialized yet. "));
135 const String& message = String::Handle(ptr: String::Concat(str1: errmsg, str2: pattern));
136 const Array& args = Array::Handle(ptr: Array::New(len: 1));
137 args.SetAt(index: 0, value: message);
138 Exceptions::ThrowByType(type: Exceptions::kFormat, arguments: args);
139 return Object::null();
140}
141
142static ObjectPtr ExecuteMatch(Zone* zone,
143 NativeArguments* arguments,
144 bool sticky) {
145 const RegExp& regexp = RegExp::CheckedHandle(zone, ptr: arguments->NativeArgAt(index: 0));
146 ASSERT(!regexp.IsNull());
147 GET_NON_NULL_NATIVE_ARGUMENT(String, subject, arguments->NativeArgAt(1));
148 GET_NON_NULL_NATIVE_ARGUMENT(Smi, start_index, arguments->NativeArgAt(2));
149
150#if !defined(DART_PRECOMPILED_RUNTIME)
151 if (!FLAG_interpret_irregexp) {
152 return IRRegExpMacroAssembler::Execute(regexp, input: subject, start_offset: start_index,
153 /*sticky=*/sticky, zone);
154 }
155#endif
156 return BytecodeRegExpMacroAssembler::Interpret(regexp, str: subject, start_index,
157 /*sticky=*/is_sticky: sticky, zone);
158}
159
160DEFINE_NATIVE_ENTRY(RegExp_ExecuteMatch, 0, 3) {
161 // This function is intrinsified. See Intrinsifier::RegExp_ExecuteMatch.
162 return ExecuteMatch(zone, arguments, /*sticky=*/false);
163}
164
165DEFINE_NATIVE_ENTRY(RegExp_ExecuteMatchSticky, 0, 3) {
166 // This function is intrinsified. See Intrinsifier::RegExp_ExecuteMatchSticky.
167 return ExecuteMatch(zone, arguments, /*sticky=*/true);
168}
169
170} // namespace dart
171

source code of flutter_engine/third_party/dart/runtime/lib/regexp.cc