@@ -374,7 +374,7 @@ private function parseRule() {
374374 return $ oRule ;
375375 }
376376
377- private function parseValue ($ aListDelimiters, $ ruleValueListClass = ' \Sabberworm\CSS\Value\RuleValueList ' ) {
377+ private function parseValue ($ aListDelimiters ) {
378378 $ aStack = array ();
379379 $ this ->consumeWhiteSpace ();
380380 //Build a list of delimiters and parsed values
@@ -410,7 +410,7 @@ private function parseValue($aListDelimiters, $ruleValueListClass = '\Sabberworm
410410 break ;
411411 }
412412 }
413- $ oList = new $ ruleValueListClass ($ sDelimiter , $ this ->iLineNo );
413+ $ oList = new RuleValueList ($ sDelimiter , $ this ->iLineNo );
414414 for ($ i = $ iStartPosition - 1 ; $ i - $ iStartPosition + 1 < $ iLength * 2 ; $ i +=2 ) {
415415 $ oList ->addListComponent ($ aStack [$ i ]);
416416 }
@@ -525,10 +525,39 @@ private function parseURLValue() {
525525 }
526526
527527 private function parseCalcValue () {
528- $ func = trim ($ this ->consumeUntil ('( ' , false , true ));
529- $ aArguments = $ this ->parseValue (array ('+ ' , '- ' , '* ' , '/ ' , ' ' ), '\Sabberworm\CSS\Value\CalcRuleValueList ' );
530- $ this ->consumeUntil (') ' , false , true );
531- return new CalcFunction ($ func , $ aArguments , ', ' , $ this ->iLineNo );
528+ $ aOperators = array ('+ ' , '- ' , '* ' , '/ ' , '( ' , ') ' );
529+ $ sFunction = trim ($ this ->consumeUntil ('( ' , false , true ));
530+ $ oCalcList = new CalcRuleValueList ($ this ->iLineNo );
531+ $ oList = new RuleValueList (', ' , $ this ->iLineNo );
532+ $ iNestingLevel = 0 ;
533+ $ iLastComponentType = NULL ;
534+ while (!$ this ->comes (') ' ) || $ iNestingLevel > 0 ) {
535+ $ this ->consumeWhiteSpace ();
536+ if (in_array ($ this ->peek (), $ aOperators )) {
537+ if (($ this ->comes ('- ' ) || $ this ->comes ('+ ' ))) {
538+ if ($ this ->peek (1 , -1 ) != ' ' || !($ this ->comes ('- ' ) || $ this ->comes ('+ ' ))) {
539+ throw new UnexpectedTokenException (" {$ this ->peek ()} " , $ this ->peek (1 , -1 ) . $ this ->peek (2 ), 'literal ' , $ this ->iLineNo );
540+ }
541+ } else if ($ this ->comes ('( ' )) {
542+ $ iNestingLevel ++;
543+ } else if ($ this ->comes (') ' )) {
544+ $ iNestingLevel --;
545+ }
546+ $ oCalcList ->addListComponent ($ this ->consume (1 ));
547+ $ iLastComponentType = CalcFunction::T_OPERATOR ;
548+ } else {
549+ $ oVal = $ this ->parsePrimitiveValue ();
550+ if ($ iLastComponentType == CalcFunction::T_OPERAND ) {
551+ throw new UnexpectedTokenException (sprintf ('Next token was expected to be an operand of type %s. Instead "%s" was found. ' , implode (', ' , $ aOperators ), $ oVal ), '' , 'custom ' , $ this ->iLineNo );
552+ }
553+
554+ $ oCalcList ->addListComponent ($ oVal );
555+ $ iLastComponentType = CalcFunction::T_OPERAND ;
556+ }
557+ }
558+ $ oList ->addListComponent ($ oCalcList );
559+ $ this ->consume (') ' );
560+ return new CalcFunction ($ sFunction , $ oList , ', ' , $ this ->iLineNo );
532561 }
533562
534563 /**
0 commit comments