Example #1
0
 /**
  * @covers getType
  */
 public function testGetType()
 {
     $md = new MixinDefinitionNode('foobar');
     $this->assertEquals('MixinDefinition', $md->getType());
 }
Example #2
0
 /**
  * Compiles the node.
  *
  * @param Context $context The context
  * @param array|null $arguments Array of arguments
  * @param bool|null $important Important flag
  *
  * @return Node
  *
  * @throws
  */
 public function compile(Context $context, $arguments = null, $important = null)
 {
     $rules = [];
     $match = false;
     $isOneFound = false;
     $candidates = [];
     $conditionResult = [];
     $args = [];
     foreach ($this->arguments as $a) {
         $aValue = $a['value']->compile($context);
         if ($a['expand'] && is_array($aValue->value)) {
             $aValue = $aValue->value;
             for ($m = 0; $m < count($aValue); ++$m) {
                 $args[] = ['value' => $aValue[$m]];
             }
         } else {
             $args[] = ['name' => $a['name'], 'value' => $aValue];
         }
     }
     /*
      * @param $rule
      * @return bool
      */
     $noArgumentsFilter = function ($rule) use($context) {
         /* @var $rule RulesetNode */
         return $rule->matchArgs([], $context);
     };
     // return values for the function
     $defFalseEitherCase = -1;
     $defNone = 0;
     $defTrue = 1;
     $defFalse = 2;
     /*
      * Calculate
      * @param $mixin
      * @param $mixinPath
      * @return int
      */
     $calcDefGroup = function ($mixin, $mixinPath) use($context, $args, $defTrue, $defFalse, $defNone, $defFalseEitherCase, &$conditionResult) {
         $namespace = null;
         for ($f = 0; $f < 2; ++$f) {
             $conditionResult[$f] = true;
             DefaultFunc::value($f);
             for ($p = 0; $p < count($mixinPath) && $conditionResult[$f]; ++$p) {
                 $namespace = $mixinPath[$p];
                 if ($namespace instanceof ConditionMatchableInterface) {
                     $conditionResult[$f] = $conditionResult[$f] && $namespace->matchCondition([], $context);
                 }
             }
             if ($mixin instanceof ConditionMatchableInterface) {
                 $conditionResult[$f] = $conditionResult[$f] && $mixin->matchCondition($args, $context);
             }
         }
         if ($conditionResult[0] || $conditionResult[1]) {
             if ($conditionResult[0] != $conditionResult[1]) {
                 return $conditionResult[1] ? $defTrue : $defFalse;
             }
             return $defNone;
         }
         return $defFalseEitherCase;
     };
     foreach ($context->frames as $frame) {
         /* @var $frame RulesetNode */
         $mixins = $frame->find($this->selector, $context, null, $noArgumentsFilter);
         if ($mixins) {
             $isOneFound = true;
             for ($m = 0; $m < count($mixins); ++$m) {
                 $mixin = $mixins[$m]['rule'];
                 $mixinPath = $mixins[$m]['path'];
                 $isRecursive = false;
                 foreach ($context->frames as $recurFrame) {
                     if (!$mixin instanceof MixinDefinitionNode && ($mixin === $recurFrame->originalRuleset || $mixin === $recurFrame)) {
                         $isRecursive = true;
                         break;
                     }
                 }
                 if ($isRecursive) {
                     continue;
                 }
                 if ($mixin->matchArgs($args, $context)) {
                     $candidate = ['mixin' => $mixin, 'group' => $calcDefGroup($mixin, $mixinPath)];
                     if ($candidate['group'] !== $defFalseEitherCase) {
                         $candidates[] = $candidate;
                     }
                     $match = true;
                 }
             }
             DefaultFunc::reset();
             $count = [0, 0, 0];
             for ($m = 0; $m < count($candidates); ++$m) {
                 ++$count[$candidates[$m]['group']];
             }
             if ($count[$defNone] > 0) {
                 $defaultResult = $defFalse;
             } else {
                 $defaultResult = $defTrue;
                 if ($count[$defTrue] + $count[$defFalse] > 1) {
                     throw new ParserException(sprintf('Ambiguous use of `default()` found when matching for `%s`', $this->formatArgs($args)), $this->index, $this->currentFileInfo);
                 }
             }
             for ($m = 0; $m < count($candidates); ++$m) {
                 $candidate = $candidates[$m]['group'];
                 if ($candidate === $defNone || $candidate === $defaultResult) {
                     try {
                         $mixin = $candidates[$m]['mixin'];
                         if (!$mixin instanceof MixinDefinitionNode) {
                             $originalRuleset = $mixin->originalRuleset ? $mixin->originalRuleset : $mixin;
                             $mixin = new MixinDefinitionNode('', [], $mixin->rules, null, false);
                             $mixin->originalRuleset = $originalRuleset;
                         }
                         $compiled = $mixin->compileCall($context, $args, $this->important);
                         $rules = array_merge($rules, $compiled->rules);
                     } catch (Exception $e) {
                         throw new CompilerException($e->getMessage(), $this->index, $this->currentFileInfo, $e);
                     }
                 }
             }
             if ($match) {
                 if (!$this->currentFileInfo || !$this->currentFileInfo->reference) {
                     foreach ($rules as $rule) {
                         if ($rule instanceof MarkableAsReferencedInterface) {
                             $rule->markReferenced();
                         }
                     }
                 }
                 return $rules;
             }
         }
     }
     if ($isOneFound) {
         throw new CompilerException(sprintf('No matching definition was found for `%s`', $this->formatArgs($args)), $this->index, $this->currentFileInfo);
     } else {
         throw new CompilerException(sprintf('%s is undefined', trim($this->selector->toCSS($context))), $this->index, $this->currentFileInfo);
     }
 }