summaryrefslogtreecommitdiffstats
path: root/vendor/wikimedia/less.php/lib/Less/Tree/Mixin
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/wikimedia/less.php/lib/Less/Tree/Mixin')
-rw-r--r--vendor/wikimedia/less.php/lib/Less/Tree/Mixin/Call.php197
-rw-r--r--vendor/wikimedia/less.php/lib/Less/Tree/Mixin/Definition.php236
2 files changed, 433 insertions, 0 deletions
diff --git a/vendor/wikimedia/less.php/lib/Less/Tree/Mixin/Call.php b/vendor/wikimedia/less.php/lib/Less/Tree/Mixin/Call.php
new file mode 100644
index 0000000..61e10fe
--- /dev/null
+++ b/vendor/wikimedia/less.php/lib/Less/Tree/Mixin/Call.php
@@ -0,0 +1,197 @@
+<?php
+/**
+ * @private
+ */
+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 = [];
+ $match = false;
+ $isOneFound = false;
+ $candidates = [];
+ $defaultUsed = false;
+ $conditionResult = [];
+
+ $args = [];
+ foreach ( $this->arguments as $a ) {
+ $args[] = [ '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 = [ '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 );
+ }
+
+ // PhanTypeInvalidDimOffset -- False positive
+ '@phan-var array{0:bool,1:bool} $conditionResult';
+
+ 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 = [ 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( '', [], $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 = [];
+ 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;
+ }
+
+}
diff --git a/vendor/wikimedia/less.php/lib/Less/Tree/Mixin/Definition.php b/vendor/wikimedia/less.php/lib/Less/Tree/Mixin/Definition.php
new file mode 100644
index 0000000..08bcd7a
--- /dev/null
+++ b/vendor/wikimedia/less.php/lib/Less/Tree/Mixin/Definition.php
@@ -0,0 +1,236 @@
+<?php
+/**
+ * @private
+ */
+class Less_Tree_Mixin_Definition extends Less_Tree_Ruleset {
+ public $name;
+ public $selectors;
+ public $params;
+ public $arity = 0;
+ public $rules;
+ public $lookups = [];
+ public $required = 0;
+ public $frames = [];
+ public $condition;
+ public $variadic;
+ public $type = 'MixinDefinition';
+
+ // less.js : /lib/less/tree/mixin.js : tree.mixin.Definition
+ public function __construct( $name, $params, $rules, $condition, $variadic = false, $frames = [] ) {
+ $this->name = $name;
+ $this->selectors = [ new Less_Tree_Selector( [ new Less_Tree_Element( null, $name ) ] ) ];
+
+ $this->params = $params;
+ $this->condition = $condition;
+ $this->variadic = $variadic;
+ $this->rules = $rules;
+
+ if ( $params ) {
+ $this->arity = count( $params );
+ foreach ( $params as $p ) {
+ if ( !isset( $p['name'] ) || ( $p['name'] && !isset( $p['value'] ) ) ) {
+ $this->required++;
+ }
+ }
+ }
+
+ $this->frames = $frames;
+ $this->SetRulesetIndex();
+ }
+
+ // function accept( $visitor ){
+ // $this->params = $visitor->visit($this->params);
+ // $this->rules = $visitor->visit($this->rules);
+ // $this->condition = $visitor->visit($this->condition);
+ //}
+
+ public function toCSS() {
+ return '';
+ }
+
+ // less.js : /lib/less/tree/mixin.js : tree.mixin.Definition.evalParams
+ public function compileParams( $env, $mixinFrames, $args = [], &$evaldArguments = [] ) {
+ $frame = new Less_Tree_Ruleset( null, [] );
+ $params = $this->params;
+ $mixinEnv = null;
+ $argsLength = 0;
+
+ if ( $args ) {
+ $argsLength = count( $args );
+ for ( $i = 0; $i < $argsLength; $i++ ) {
+ $arg = $args[$i];
+
+ if ( $arg && $arg['name'] ) {
+ $isNamedFound = false;
+
+ foreach ( $params as $j => $param ) {
+ if ( !isset( $evaldArguments[$j] ) && $arg['name'] === $params[$j]['name'] ) {
+ $evaldArguments[$j] = $arg['value']->compile( $env );
+ array_unshift( $frame->rules, new Less_Tree_Rule( $arg['name'], $arg['value']->compile( $env ) ) );
+ $isNamedFound = true;
+ break;
+ }
+ }
+ if ( $isNamedFound ) {
+ array_splice( $args, $i, 1 );
+ $i--;
+ $argsLength--;
+ continue;
+ } else {
+ throw new Less_Exception_Compiler( "Named argument for " . $this->name . ' ' . $args[$i]['name'] . ' not found' );
+ }
+ }
+ }
+ }
+
+ $argIndex = 0;
+ foreach ( $params as $i => $param ) {
+
+ if ( isset( $evaldArguments[$i] ) ) { continue;
+ }
+
+ $arg = null;
+ if ( isset( $args[$argIndex] ) ) {
+ $arg = $args[$argIndex];
+ }
+
+ if ( isset( $param['name'] ) && $param['name'] ) {
+
+ if ( isset( $param['variadic'] ) ) {
+ $varargs = [];
+ for ( $j = $argIndex; $j < $argsLength; $j++ ) {
+ $varargs[] = $args[$j]['value']->compile( $env );
+ }
+ $expression = new Less_Tree_Expression( $varargs );
+ array_unshift( $frame->rules, new Less_Tree_Rule( $param['name'], $expression->compile( $env ) ) );
+ } else {
+ $val = ( $arg && $arg['value'] ) ? $arg['value'] : false;
+
+ if ( $val ) {
+ $val = $val->compile( $env );
+ } elseif ( isset( $param['value'] ) ) {
+
+ if ( !$mixinEnv ) {
+ $mixinEnv = new Less_Environment();
+ $mixinEnv->frames = array_merge( [ $frame ], $mixinFrames );
+ }
+
+ $val = $param['value']->compile( $mixinEnv );
+ $frame->resetCache();
+ } else {
+ throw new Less_Exception_Compiler( "Wrong number of arguments for " . $this->name . " (" . $argsLength . ' for ' . $this->arity . ")" );
+ }
+
+ array_unshift( $frame->rules, new Less_Tree_Rule( $param['name'], $val ) );
+ $evaldArguments[$i] = $val;
+ }
+ }
+
+ if ( isset( $param['variadic'] ) && $args ) {
+ for ( $j = $argIndex; $j < $argsLength; $j++ ) {
+ $evaldArguments[$j] = $args[$j]['value']->compile( $env );
+ }
+ }
+ $argIndex++;
+ }
+
+ ksort( $evaldArguments );
+ $evaldArguments = array_values( $evaldArguments );
+
+ return $frame;
+ }
+
+ public function compile( $env ) {
+ if ( $this->frames ) {
+ return new Less_Tree_Mixin_Definition( $this->name, $this->params, $this->rules, $this->condition, $this->variadic, $this->frames );
+ }
+ return new Less_Tree_Mixin_Definition( $this->name, $this->params, $this->rules, $this->condition, $this->variadic, $env->frames );
+ }
+
+ public function evalCall( $env, $args = null, $important = null ) {
+ Less_Environment::$mixin_stack++;
+
+ $_arguments = [];
+
+ if ( $this->frames ) {
+ $mixinFrames = array_merge( $this->frames, $env->frames );
+ } else {
+ $mixinFrames = $env->frames;
+ }
+
+ $frame = $this->compileParams( $env, $mixinFrames, $args, $_arguments );
+
+ $ex = new Less_Tree_Expression( $_arguments );
+ array_unshift( $frame->rules, new Less_Tree_Rule( '@arguments', $ex->compile( $env ) ) );
+
+ $ruleset = new Less_Tree_Ruleset( null, $this->rules );
+ $ruleset->originalRuleset = $this->ruleset_id;
+
+ $ruleSetEnv = new Less_Environment();
+ $ruleSetEnv->frames = array_merge( [ $this, $frame ], $mixinFrames );
+ $ruleset = $ruleset->compile( $ruleSetEnv );
+
+ if ( $important ) {
+ $ruleset = $ruleset->makeImportant();
+ }
+
+ Less_Environment::$mixin_stack--;
+
+ return $ruleset;
+ }
+
+ /** @return bool */
+ public function matchCondition( $args, $env ) {
+ if ( !$this->condition ) {
+ return true;
+ }
+
+ // set array to prevent error on array_merge
+ if ( !is_array( $this->frames ) ) {
+ $this->frames = [];
+ }
+
+ $frame = $this->compileParams( $env, array_merge( $this->frames, $env->frames ), $args );
+
+ $compile_env = new Less_Environment();
+ $compile_env->frames = array_merge(
+ [ $frame ], // the parameter variables
+ $this->frames, // the parent namespace/mixin frames
+ $env->frames // the current environment frames
+ );
+
+ $compile_env->functions = $env->functions;
+
+ return (bool)$this->condition->compile( $compile_env );
+ }
+
+ public function matchArgs( $args, $env = null ) {
+ $argsLength = count( $args );
+
+ if ( !$this->variadic ) {
+ if ( $argsLength < $this->required ) {
+ return false;
+ }
+ if ( $argsLength > count( $this->params ) ) {
+ return false;
+ }
+ } else {
+ if ( $argsLength < ( $this->required - 1 ) ) {
+ return false;
+ }
+ }
+
+ $len = min( $argsLength, $this->arity );
+
+ for ( $i = 0; $i < $len; $i++ ) {
+ if ( !isset( $this->params[$i]['name'] ) && !isset( $this->params[$i]['variadic'] ) ) {
+ if ( $args[$i]['value']->compile( $env )->toCSS() != $this->params[$i]['value']->compile( $env )->toCSS() ) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+}