@@ -304,35 +304,25 @@ private function createGroupType(TreeNode $group, bool $maybeConstant, string $p
304304 return TypeCombinator::union (...$ types );
305305 }
306306
307- $ isNonEmpty = TrinaryLogic::createMaybe ();
308- $ isNonFalsy = TrinaryLogic::createMaybe ();
309- $ isNumeric = TrinaryLogic::createMaybe ();
310- $ inOptionalQuantification = false ;
311- $ onlyLiterals = [];
312-
313- $ this ->walkGroupAst (
307+ $ walkResult = $ this ->walkGroupAst (
314308 $ group ,
315309 false ,
316- $ isNonEmpty ,
317- $ isNonFalsy ,
318- $ isNumeric ,
319- $ inOptionalQuantification ,
320- $ onlyLiterals ,
321310 false ,
322311 $ patternModifiers ,
312+ RegexGroupWalkResult::createEmpty (),
323313 );
324314
325- if ($ maybeConstant && $ onlyLiterals !== null && $ onlyLiterals !== []) {
315+ if ($ maybeConstant && $ walkResult -> getOnlyLiterals () !== null && $ walkResult -> getOnlyLiterals () !== []) {
326316 $ result = [];
327- foreach ($ onlyLiterals as $ literal ) {
317+ foreach ($ walkResult -> getOnlyLiterals () as $ literal ) {
328318 $ result [] = new ConstantStringType ($ literal );
329319
330320 }
331321 return TypeCombinator::union (...$ result );
332322 }
333323
334- if ($ isNumeric ->yes ()) {
335- if ($ isNonFalsy ->yes ()) {
324+ if ($ walkResult -> isNumeric () ->yes ()) {
325+ if ($ walkResult -> isNonFalsy () ->yes ()) {
336326 return new IntersectionType ([
337327 new StringType (),
338328 new AccessoryNumericStringType (),
@@ -341,13 +331,13 @@ private function createGroupType(TreeNode $group, bool $maybeConstant, string $p
341331 }
342332
343333 $ result = new IntersectionType ([new StringType (), new AccessoryNumericStringType ()]);
344- if (!$ isNonEmpty ->yes ()) {
334+ if (!$ walkResult -> isNonEmpty () ->yes ()) {
345335 return TypeCombinator::union (new ConstantStringType ('' ), $ result );
346336 }
347337 return $ result ;
348- } elseif ($ isNonFalsy ->yes ()) {
338+ } elseif ($ walkResult -> isNonFalsy () ->yes ()) {
349339 return new IntersectionType ([new StringType (), new AccessoryNonFalsyStringType ()]);
350- } elseif ($ isNonEmpty ->yes ()) {
340+ } elseif ($ walkResult -> isNonEmpty () ->yes ()) {
351341 return new IntersectionType ([new StringType (), new AccessoryNonEmptyStringType ()]);
352342 }
353343
@@ -376,20 +366,13 @@ private function getRootAlternation(TreeNode $group): ?TreeNode
376366 return null ;
377367 }
378368
379- /**
380- * @param array<string>|null $onlyLiterals
381- */
382369 private function walkGroupAst (
383370 TreeNode $ ast ,
384371 bool $ inAlternation ,
385- TrinaryLogic &$ isNonEmpty ,
386- TrinaryLogic &$ isNonFalsy ,
387- TrinaryLogic &$ isNumeric ,
388- bool &$ inOptionalQuantification ,
389- ?array &$ onlyLiterals ,
390372 bool $ inClass ,
391373 string $ patternModifiers ,
392- ): void
374+ RegexGroupWalkResult $ walkResult ,
375+ ): RegexGroupWalkResult
393376 {
394377 $ children = $ ast ->getChildren ();
395378
@@ -411,61 +394,65 @@ private function walkGroupAst(
411394 }
412395
413396 // a single token non-falsy on its own
414- $ isNonFalsy = TrinaryLogic::createYes ();
397+ $ walkResult = $ walkResult -> nonFalsy ( TrinaryLogic::createYes () );
415398 break ;
416399 }
417400
418401 if ($ meaningfulTokens > 0 ) {
419- $ isNonEmpty = TrinaryLogic::createYes ();
402+ $ walkResult = $ walkResult -> nonEmpty ( TrinaryLogic::createYes () );
420403
421404 // two non-empty tokens concatenated results in a non-falsy string
422405 if ($ meaningfulTokens > 1 && !$ inAlternation ) {
423- $ isNonFalsy = TrinaryLogic::createYes ();
406+ $ walkResult = $ walkResult -> nonFalsy ( TrinaryLogic::createYes () );
424407 }
425408 }
426409 } elseif ($ ast ->getId () === '#quantification ' ) {
427410 [$ min ] = $ this ->getQuantificationRange ($ ast );
428411
429412 if ($ min === 0 ) {
430- $ inOptionalQuantification = true ;
413+ $ walkResult = $ walkResult -> inOptionalQuantification ( true ) ;
431414 }
432415 if ($ min >= 1 ) {
433- $ isNonEmpty = TrinaryLogic::createYes ();
434- $ inOptionalQuantification = false ;
416+ $ walkResult = $ walkResult
417+ ->nonEmpty (TrinaryLogic::createYes ())
418+ ->inOptionalQuantification (false );
435419 }
436420 if ($ min >= 2 && !$ inAlternation ) {
437- $ isNonFalsy = TrinaryLogic::createYes ();
421+ $ walkResult = $ walkResult -> nonFalsy ( TrinaryLogic::createYes () );
438422 }
439423
440- $ onlyLiterals = null ;
441- } elseif ($ ast ->getId () === '#class ' && $ onlyLiterals !== null ) {
424+ $ walkResult = $ walkResult -> onlyLiterals ( null ) ;
425+ } elseif ($ ast ->getId () === '#class ' && $ walkResult -> getOnlyLiterals () !== null ) {
442426 $ inClass = true ;
443427
444428 $ newLiterals = [];
445429 foreach ($ children as $ child ) {
446- $ oldLiterals = $ onlyLiterals ;
430+ $ oldLiterals = $ walkResult -> getOnlyLiterals () ;
447431
448432 $ this ->getLiteralValue ($ child , $ oldLiterals , true , $ patternModifiers , true );
449433 foreach ($ oldLiterals ?? [] as $ oldLiteral ) {
450434 $ newLiterals [] = $ oldLiteral ;
451435 }
452436 }
453- $ onlyLiterals = $ newLiterals ;
437+ $ walkResult = $ walkResult -> onlyLiterals ( $ newLiterals) ;
454438 } elseif ($ ast ->getId () === 'token ' ) {
439+ $ onlyLiterals = $ walkResult ->getOnlyLiterals ();
455440 $ literalValue = $ this ->getLiteralValue ($ ast , $ onlyLiterals , !$ inClass , $ patternModifiers , false );
441+ $ walkResult = $ walkResult ->onlyLiterals ($ onlyLiterals );
442+
456443 if ($ literalValue !== null ) {
457444 if (Strings::match ($ literalValue , '/^\d+$/ ' ) === null ) {
458- $ isNumeric = TrinaryLogic::createNo ();
459- } elseif ($ isNumeric ->maybe ()) {
460- $ isNumeric = TrinaryLogic::createYes ();
445+ $ walkResult = $ walkResult -> numeric ( TrinaryLogic::createNo () );
446+ } elseif ($ walkResult -> isNumeric () ->maybe ()) {
447+ $ walkResult = $ walkResult -> numeric ( TrinaryLogic::createYes () );
461448 }
462449
463- if (!$ inOptionalQuantification && $ literalValue !== '' ) {
464- $ isNonEmpty = TrinaryLogic::createYes ();
450+ if (!$ walkResult -> isInOptionalQuantification () && $ literalValue !== '' ) {
451+ $ walkResult = $ walkResult -> nonEmpty ( TrinaryLogic::createYes () );
465452 }
466453 }
467454 } elseif (!in_array ($ ast ->getId (), ['#capturing ' , '#namedcapturing ' , '#alternation ' ], true )) {
468- $ onlyLiterals = null ;
455+ $ walkResult = $ walkResult -> onlyLiterals ( null ) ;
469456 }
470457
471458 if ($ ast ->getId () === '#alternation ' ) {
@@ -476,22 +463,20 @@ private function walkGroupAst(
476463 // doable but really silly compared to just \d so we can safely assume the string is not numeric
477464 // for negative classes
478465 if ($ ast ->getId () === '#negativeclass ' ) {
479- $ isNumeric = TrinaryLogic::createNo ();
466+ $ walkResult = $ walkResult -> numeric ( TrinaryLogic::createNo () );
480467 }
481468
482469 foreach ($ children as $ child ) {
483- $ this ->walkGroupAst (
470+ $ walkResult = $ this ->walkGroupAst (
484471 $ child ,
485472 $ inAlternation ,
486- $ isNonEmpty ,
487- $ isNonFalsy ,
488- $ isNumeric ,
489- $ inOptionalQuantification ,
490- $ onlyLiterals ,
491473 $ inClass ,
492474 $ patternModifiers ,
475+ $ walkResult ,
493476 );
494477 }
478+
479+ return $ walkResult ;
495480 }
496481
497482 private function isMaybeEmptyNode (TreeNode $ node , string $ patternModifiers , bool &$ isNonFalsy ): bool
0 commit comments