You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
202 lines
4.9 KiB
202 lines
4.9 KiB
<?php
|
|
|
|
|
|
class Less_Tree_Mixin_Call extends Less_Tree{
|
|
|
|
public $selector;
|
|
public $arguments;
|
|
public $index;
|
|
public $currentFileInfo;
|
|
|
|
public $important;
|
|
public $type = 'MixinCall';
|
|
|
|
/**
|
|
* less.js: tree.mixin.Call
|
|
*
|
|
*/
|
|
public function __construct($elements, $args, $index, $currentFileInfo, $important = false){
|
|
$this->selector = new Less_Tree_Selector($elements);
|
|
$this->arguments = $args;
|
|
$this->index = $index;
|
|
$this->currentFileInfo = $currentFileInfo;
|
|
$this->important = $important;
|
|
}
|
|
|
|
//function accept($visitor){
|
|
// $this->selector = $visitor->visit($this->selector);
|
|
// $this->arguments = $visitor->visit($this->arguments);
|
|
//}
|
|
|
|
|
|
public function compile($env){
|
|
|
|
$rules = array();
|
|
$match = false;
|
|
$isOneFound = false;
|
|
$candidates = array();
|
|
$defaultUsed = false;
|
|
$conditionResult = array();
|
|
|
|
$args = array();
|
|
foreach($this->arguments as $a){
|
|
$args[] = array('name'=> $a['name'], 'value' => $a['value']->compile($env) );
|
|
}
|
|
|
|
foreach($env->frames as $frame){
|
|
|
|
$mixins = $frame->find($this->selector);
|
|
|
|
if( !$mixins ){
|
|
continue;
|
|
}
|
|
|
|
$isOneFound = true;
|
|
$defNone = 0;
|
|
$defTrue = 1;
|
|
$defFalse = 2;
|
|
|
|
// To make `default()` function independent of definition order we have two "subpasses" here.
|
|
// At first we evaluate each guard *twice* (with `default() == true` and `default() == false`),
|
|
// and build candidate list with corresponding flags. Then, when we know all possible matches,
|
|
// we make a final decision.
|
|
|
|
$mixins_len = count($mixins);
|
|
for( $m = 0; $m < $mixins_len; $m++ ){
|
|
$mixin = $mixins[$m];
|
|
|
|
if( $this->IsRecursive( $env, $mixin ) ){
|
|
continue;
|
|
}
|
|
|
|
if( $mixin->matchArgs($args, $env) ){
|
|
|
|
$candidate = array('mixin' => $mixin, 'group' => $defNone);
|
|
|
|
if( $mixin instanceof Less_Tree_Ruleset ){
|
|
|
|
for( $f = 0; $f < 2; $f++ ){
|
|
Less_Tree_DefaultFunc::value($f);
|
|
$conditionResult[$f] = $mixin->matchCondition( $args, $env);
|
|
}
|
|
if( $conditionResult[0] || $conditionResult[1] ){
|
|
if( $conditionResult[0] != $conditionResult[1] ){
|
|
$candidate['group'] = $conditionResult[1] ? $defTrue : $defFalse;
|
|
}
|
|
|
|
$candidates[] = $candidate;
|
|
}
|
|
}else{
|
|
$candidates[] = $candidate;
|
|
}
|
|
|
|
$match = true;
|
|
}
|
|
}
|
|
|
|
Less_Tree_DefaultFunc::reset();
|
|
|
|
|
|
$count = array(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 Exception( 'Ambiguous use of `default()` found when matching for `' . $this->format($args) . '`' );
|
|
}
|
|
}
|
|
|
|
|
|
$candidates_length = count($candidates);
|
|
$length_1 = ($candidates_length == 1);
|
|
|
|
for( $m = 0; $m < $candidates_length; $m++){
|
|
$candidate = $candidates[$m]['group'];
|
|
if( ($candidate === $defNone) || ($candidate === $defaultResult) ){
|
|
try{
|
|
$mixin = $candidates[$m]['mixin'];
|
|
if( !($mixin instanceof Less_Tree_Mixin_Definition) ){
|
|
$mixin = new Less_Tree_Mixin_Definition('', array(), $mixin->rules, null, false);
|
|
$mixin->originalRuleset = $mixins[$m]->originalRuleset;
|
|
}
|
|
$rules = array_merge($rules, $mixin->evalCall($env, $args, $this->important)->rules);
|
|
} catch (Exception $e) {
|
|
//throw new Less_Exception_Compiler($e->getMessage(), $e->index, null, $this->currentFileInfo['filename']);
|
|
throw new Less_Exception_Compiler($e->getMessage(), null, null, $this->currentFileInfo);
|
|
}
|
|
}
|
|
}
|
|
|
|
if( $match ){
|
|
if( !$this->currentFileInfo || !isset($this->currentFileInfo['reference']) || !$this->currentFileInfo['reference'] ){
|
|
Less_Tree::ReferencedArray($rules);
|
|
}
|
|
|
|
return $rules;
|
|
}
|
|
}
|
|
|
|
if( $isOneFound ){
|
|
throw new Less_Exception_Compiler('No matching definition was found for `'.$this->Format( $args ).'`', null, $this->index, $this->currentFileInfo);
|
|
|
|
}else{
|
|
throw new Less_Exception_Compiler(trim($this->selector->toCSS()) . " is undefined in ".$this->currentFileInfo['filename'], null, $this->index);
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Format the args for use in exception messages
|
|
*
|
|
*/
|
|
private function Format($args){
|
|
$message = array();
|
|
if( $args ){
|
|
foreach($args as $a){
|
|
$argValue = '';
|
|
if( $a['name'] ){
|
|
$argValue .= $a['name'] . ':';
|
|
}
|
|
if( is_object($a['value']) ){
|
|
$argValue .= $a['value']->toCSS();
|
|
}else{
|
|
$argValue .= '???';
|
|
}
|
|
$message[] = $argValue;
|
|
}
|
|
}
|
|
return implode(', ',$message);
|
|
}
|
|
|
|
|
|
/**
|
|
* Are we in a recursive mixin call?
|
|
*
|
|
* @return bool
|
|
*/
|
|
private function IsRecursive( $env, $mixin ){
|
|
|
|
foreach($env->frames as $recur_frame){
|
|
if( !($mixin instanceof Less_Tree_Mixin_Definition) ){
|
|
|
|
if( $mixin === $recur_frame ){
|
|
return true;
|
|
}
|
|
|
|
if( isset($recur_frame->originalRuleset) && $mixin->ruleset_id === $recur_frame->originalRuleset ){
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|