Flutter Engine
The Flutter Engine
Public Types | Public Member Functions | Static Public Member Functions | List of all members
dart::RegExpQuantifier Class Reference

#include <regexp_ast.h>

Inheritance diagram for dart::RegExpQuantifier:
dart::RegExpTree dart::ZoneAllocated

Public Types

enum  QuantifierType { GREEDY , NON_GREEDY , POSSESSIVE }
 

Public Member Functions

 RegExpQuantifier (intptr_t min, intptr_t max, QuantifierType type, RegExpTree *body)
 
virtual void * Accept (RegExpVisitor *visitor, void *data)
 
virtual RegExpNodeToNode (RegExpCompiler *compiler, RegExpNode *on_success)
 
virtual RegExpQuantifierAsQuantifier ()
 
virtual Interval CaptureRegisters () const
 
virtual bool IsQuantifier () const
 
virtual intptr_t min_match () const
 
virtual intptr_t max_match () const
 
intptr_t min () const
 
intptr_t max () const
 
bool is_possessive () const
 
bool is_non_greedy () const
 
bool is_greedy () const
 
RegExpTreebody () const
 
- Public Member Functions inherited from dart::RegExpTree
virtual ~RegExpTree ()
 
virtual void * Accept (RegExpVisitor *visitor, void *data)=0
 
virtual RegExpNodeToNode (RegExpCompiler *compiler, RegExpNode *on_success)=0
 
virtual bool IsTextElement () const
 
virtual bool IsAnchoredAtStart () const
 
virtual bool IsAnchoredAtEnd () const
 
virtual intptr_t min_match () const =0
 
virtual intptr_t max_match () const =0
 
virtual Interval CaptureRegisters () const
 
virtual void AppendToText (RegExpText *text)
 
void Print ()
 
- Public Member Functions inherited from dart::ZoneAllocated
 ZoneAllocated ()
 
void * operator new (size_t size)
 
void * operator new (size_t size, Zone *zone)
 
void operator delete (void *pointer)
 

Static Public Member Functions

static RegExpNodeToNode (intptr_t min, intptr_t max, bool is_greedy, RegExpTree *body, RegExpCompiler *compiler, RegExpNode *on_success, bool not_at_start=false)
 

Additional Inherited Members

- Static Public Attributes inherited from dart::RegExpTree
static constexpr intptr_t kInfinity = kMaxInt32
 

Detailed Description

Definition at line 263 of file regexp_ast.h.

Member Enumeration Documentation

◆ QuantifierType

Enumerator
GREEDY 
NON_GREEDY 
POSSESSIVE 

Definition at line 265 of file regexp_ast.h.

Constructor & Destructor Documentation

◆ RegExpQuantifier()

dart::RegExpQuantifier::RegExpQuantifier ( intptr_t  min,
intptr_t  max,
QuantifierType  type,
RegExpTree body 
)
inline

Definition at line 266 of file regexp_ast.h.

270 : body_(body),
271 min_(min),
272 max_(max),
273 min_match_(min * body->min_match()),
274 quantifier_type_(type) {
275 if (max > 0 && body->max_match() > kInfinity / max) {
276 max_match_ = kInfinity;
277 } else {
278 max_match_ = max * body->max_match();
279 }
280 }
GLenum type
intptr_t max() const
Definition: regexp_ast.h:296
intptr_t min() const
Definition: regexp_ast.h:295
RegExpTree * body() const
Definition: regexp_ast.h:300
virtual intptr_t min_match() const =0
virtual intptr_t max_match() const =0
static constexpr intptr_t kInfinity
Definition: regexp_ast.h:39

Member Function Documentation

◆ Accept()

virtual void * dart::RegExpQuantifier::Accept ( RegExpVisitor visitor,
void *  data 
)
virtual

Implements dart::RegExpTree.

◆ AsQuantifier()

virtual RegExpQuantifier * dart::RegExpQuantifier::AsQuantifier ( )
virtual

◆ body()

RegExpTree * dart::RegExpQuantifier::body ( ) const
inline

Definition at line 300 of file regexp_ast.h.

300{ return body_; }

◆ CaptureRegisters()

Interval dart::RegExpQuantifier::CaptureRegisters ( ) const
virtual

Reimplemented from dart::RegExpTree.

Definition at line 63 of file regexp_ast.cc.

63 {
64 return body()->CaptureRegisters();
65}
virtual Interval CaptureRegisters() const
Definition: regexp_ast.h:51

◆ is_greedy()

bool dart::RegExpQuantifier::is_greedy ( ) const
inline

Definition at line 299 of file regexp_ast.h.

299{ return quantifier_type_ == GREEDY; }

◆ is_non_greedy()

bool dart::RegExpQuantifier::is_non_greedy ( ) const
inline

Definition at line 298 of file regexp_ast.h.

298{ return quantifier_type_ == NON_GREEDY; }

◆ is_possessive()

bool dart::RegExpQuantifier::is_possessive ( ) const
inline

Definition at line 297 of file regexp_ast.h.

297{ return quantifier_type_ == POSSESSIVE; }

◆ IsQuantifier()

virtual bool dart::RegExpQuantifier::IsQuantifier ( ) const
virtual

◆ max()

intptr_t dart::RegExpQuantifier::max ( ) const
inline

Definition at line 296 of file regexp_ast.h.

296{ return max_; }

◆ max_match()

virtual intptr_t dart::RegExpQuantifier::max_match ( ) const
inlinevirtual

Implements dart::RegExpTree.

Definition at line 294 of file regexp_ast.h.

294{ return max_match_; }

◆ min()

intptr_t dart::RegExpQuantifier::min ( ) const
inline

Definition at line 295 of file regexp_ast.h.

295{ return min_; }

◆ min_match()

virtual intptr_t dart::RegExpQuantifier::min_match ( ) const
inlinevirtual

Implements dart::RegExpTree.

Definition at line 293 of file regexp_ast.h.

293{ return min_match_; }

◆ ToNode() [1/2]

RegExpNode * dart::RegExpQuantifier::ToNode ( intptr_t  min,
intptr_t  max,
bool  is_greedy,
RegExpTree body,
RegExpCompiler compiler,
RegExpNode on_success,
bool  not_at_start = false 
)
static

Definition at line 4258 of file regexp.cc.

4264 {
4265 // x{f, t} becomes this:
4266 //
4267 // (r++)<-.
4268 // | `
4269 // | (x)
4270 // v ^
4271 // (r=0)-->(?)---/ [if r < t]
4272 // |
4273 // [if r >= f] \----> ...
4274 //
4275
4276 // 15.10.2.5 RepeatMatcher algorithm.
4277 // The parser has already eliminated the case where max is 0. In the case
4278 // where max_match is zero the parser has removed the quantifier if min was
4279 // > 0 and removed the atom if min was 0. See AddQuantifierToAtom.
4280
4281 // If we know that we cannot match zero length then things are a little
4282 // simpler since we don't need to make the special zero length match check
4283 // from step 2.1. If the min and max are small we can unroll a little in
4284 // this case.
4285 // Unroll (foo)+ and (foo){3,}
4286 const intptr_t kMaxUnrolledMinMatches = 3;
4287 // Unroll (foo)? and (foo){x,3}
4288 const intptr_t kMaxUnrolledMaxMatches = 3;
4289 if (max == 0) return on_success; // This can happen due to recursion.
4290 bool body_can_be_empty = (body->min_match() == 0);
4291 intptr_t body_start_reg = RegExpCompiler::kNoRegister;
4292 Interval capture_registers = body->CaptureRegisters();
4293 bool needs_capture_clearing = !capture_registers.is_empty();
4294 Zone* zone = compiler->zone();
4295
4296 if (body_can_be_empty) {
4297 body_start_reg = compiler->AllocateRegister();
4298 } else if (kRegexpOptimization && !needs_capture_clearing) {
4299 // Only unroll if there are no captures and the body can't be
4300 // empty.
4301 {
4302 RegExpExpansionLimiter limiter(compiler, min + ((max != min) ? 1 : 0));
4303 if (min > 0 && min <= kMaxUnrolledMinMatches && limiter.ok_to_expand()) {
4304 intptr_t new_max = (max == kInfinity) ? max : max - min;
4305 // Recurse once to get the loop or optional matches after the fixed
4306 // ones.
4307 RegExpNode* answer =
4308 ToNode(0, new_max, is_greedy, body, compiler, on_success, true);
4309 // Unroll the forced matches from 0 to min. This can cause chains of
4310 // TextNodes (which the parser does not generate). These should be
4311 // combined if it turns out they hinder good code generation.
4312 for (intptr_t i = 0; i < min; i++) {
4313 answer = body->ToNode(compiler, answer);
4314 }
4315 return answer;
4316 }
4317 }
4318 if (max <= kMaxUnrolledMaxMatches && min == 0) {
4319 ASSERT(max > 0); // Due to the 'if' above.
4320 RegExpExpansionLimiter limiter(compiler, max);
4321 if (limiter.ok_to_expand()) {
4322 // Unroll the optional matches up to max.
4323 RegExpNode* answer = on_success;
4324 for (intptr_t i = 0; i < max; i++) {
4325 ChoiceNode* alternation = new (zone) ChoiceNode(2, zone);
4326 if (is_greedy) {
4327 alternation->AddAlternative(
4328 GuardedAlternative(body->ToNode(compiler, answer)));
4329 alternation->AddAlternative(GuardedAlternative(on_success));
4330 } else {
4331 alternation->AddAlternative(GuardedAlternative(on_success));
4332 alternation->AddAlternative(
4333 GuardedAlternative(body->ToNode(compiler, answer)));
4334 }
4335 answer = alternation;
4336 if (not_at_start && !compiler->read_backward()) {
4337 alternation->set_not_at_start();
4338 }
4339 }
4340 return answer;
4341 }
4342 }
4343 }
4344 bool has_min = min > 0;
4345 bool has_max = max < RegExpTree::kInfinity;
4346 bool needs_counter = has_min || has_max;
4347 intptr_t reg_ctr = needs_counter ? compiler->AllocateRegister()
4349 LoopChoiceNode* center = new (zone)
4350 LoopChoiceNode(body->min_match() == 0, compiler->read_backward(), zone);
4351 if (not_at_start && !compiler->read_backward()) center->set_not_at_start();
4352 RegExpNode* loop_return =
4353 needs_counter ? static_cast<RegExpNode*>(
4354 ActionNode::IncrementRegister(reg_ctr, center))
4355 : static_cast<RegExpNode*>(center);
4356 if (body_can_be_empty) {
4357 // If the body can be empty we need to check if it was and then
4358 // backtrack.
4359 loop_return =
4360 ActionNode::EmptyMatchCheck(body_start_reg, reg_ctr, min, loop_return);
4361 }
4362 RegExpNode* body_node = body->ToNode(compiler, loop_return);
4363 if (body_can_be_empty) {
4364 // If the body can be empty we need to store the start position
4365 // so we can bail out if it was empty.
4366 body_node = ActionNode::StorePosition(body_start_reg, false, body_node);
4367 }
4368 if (needs_capture_clearing) {
4369 // Before entering the body of this loop we need to clear captures.
4370 body_node = ActionNode::ClearCaptures(capture_registers, body_node);
4371 }
4372 GuardedAlternative body_alt(body_node);
4373 if (has_max) {
4374 Guard* body_guard = new (zone) Guard(reg_ctr, Guard::LT, max);
4375 body_alt.AddGuard(body_guard, zone);
4376 }
4377 GuardedAlternative rest_alt(on_success);
4378 if (has_min) {
4379 Guard* rest_guard = new (zone) Guard(reg_ctr, Guard::GEQ, min);
4380 rest_alt.AddGuard(rest_guard, zone);
4381 }
4382 if (is_greedy) {
4383 center->AddLoopAlternative(body_alt);
4384 center->AddContinueAlternative(rest_alt);
4385 } else {
4386 center->AddContinueAlternative(rest_alt);
4387 center->AddLoopAlternative(body_alt);
4388 }
4389 if (needs_counter) {
4390 return ActionNode::SetRegister(reg_ctr, 0, center);
4391 } else {
4392 return center;
4393 }
4394}
static ActionNode * EmptyMatchCheck(intptr_t start_register, intptr_t repetition_register, intptr_t repetition_limit, RegExpNode *on_success)
Definition: regexp.cc:816
static ActionNode * SetRegister(intptr_t reg, intptr_t val, RegExpNode *on_success)
Definition: regexp.cc:756
static ActionNode * IncrementRegister(intptr_t reg, RegExpNode *on_success)
Definition: regexp.cc:766
static ActionNode * ClearCaptures(Interval range, RegExpNode *on_success)
Definition: regexp.cc:784
static ActionNode * StorePosition(intptr_t reg, bool is_capture, RegExpNode *on_success)
Definition: regexp.cc:774
static constexpr intptr_t kNoRegister
Definition: regexp.cc:355
virtual RegExpNode * ToNode(RegExpCompiler *compiler, RegExpNode *on_success)
Definition: regexp.cc:4216
bool is_greedy() const
Definition: regexp_ast.h:299
virtual RegExpNode * ToNode(RegExpCompiler *compiler, RegExpNode *on_success)=0
#define ASSERT(E)
static constexpr bool kRegexpOptimization
Definition: regexp.cc:31

◆ ToNode() [2/2]

RegExpNode * dart::RegExpQuantifier::ToNode ( RegExpCompiler compiler,
RegExpNode on_success 
)
virtual

Implements dart::RegExpTree.

Definition at line 4216 of file regexp.cc.

4217 {
4218 return ToNode(min(), max(), is_greedy(), body(), compiler, on_success);
4219}

The documentation for this class was generated from the following files: