@@ -442,12 +442,12 @@ discard block |
||
442 | 442 | if (!is_array($p)) continue; |
443 | 443 | |
444 | 444 | switch ($p[0]) { |
445 | - case "interpolate": |
|
446 | - $p = $this->compileValue($p); |
|
447 | - break; |
|
448 | - case "string": |
|
449 | - $p = $this->compileValue($p); |
|
450 | - break; |
|
445 | + case "interpolate": |
|
446 | + $p = $this->compileValue($p); |
|
447 | + break; |
|
448 | + case "string": |
|
449 | + $p = $this->compileValue($p); |
|
450 | + break; |
|
451 | 451 | } |
452 | 452 | } |
453 | 453 | |
@@ -468,12 +468,12 @@ discard block |
||
468 | 468 | if (!is_array($p)) continue; |
469 | 469 | |
470 | 470 | switch ($p[0]) { |
471 | - case "self": |
|
472 | - $p = "&"; |
|
473 | - break; |
|
474 | - default: |
|
475 | - $p = $this->compileValue($p); |
|
476 | - break; |
|
471 | + case "self": |
|
472 | + $p = "&"; |
|
473 | + break; |
|
474 | + default: |
|
475 | + $p = $this->compileValue($p); |
|
476 | + break; |
|
477 | 477 | } |
478 | 478 | } |
479 | 479 | |
@@ -622,204 +622,204 @@ discard block |
||
622 | 622 | $this->sourceParser = isset($child[-2]) ? $child[-2] : $this->parser; |
623 | 623 | |
624 | 624 | switch ($child[0]) { |
625 | - case "import": |
|
626 | - list(,$rawPath) = $child; |
|
627 | - $rawPath = $this->reduce($rawPath); |
|
628 | - if (!$this->compileImport($rawPath, $out)) { |
|
629 | - $out->lines[] = "@import " . $this->compileValue($rawPath) . ";"; |
|
630 | - } |
|
631 | - break; |
|
632 | - case "directive": |
|
633 | - list(, $directive) = $child; |
|
634 | - $s = "@" . $directive->name; |
|
635 | - if (!empty($directive->value)) { |
|
636 | - $s .= " " . $this->compileValue($directive->value); |
|
637 | - } |
|
638 | - $this->compileNestedBlock($directive, array($s)); |
|
639 | - break; |
|
640 | - case "media": |
|
641 | - $this->compileMedia($child[1]); |
|
642 | - break; |
|
643 | - case "block": |
|
644 | - $this->compileBlock($child[1]); |
|
645 | - break; |
|
646 | - case "charset": |
|
647 | - $out->lines[] = "@charset ".$this->compileValue($child[1]).";"; |
|
648 | - break; |
|
649 | - case "assign": |
|
650 | - list(,$name, $value) = $child; |
|
651 | - if ($name[0] == "var") { |
|
652 | - $isDefault = !empty($child[3]); |
|
653 | - |
|
654 | - if ($isDefault) { |
|
655 | - $existingValue = $this->get($name[1], true); |
|
656 | - $shouldSet = $existingValue === true || $existingValue == self::$null; |
|
657 | - } |
|
658 | - |
|
659 | - if (!$isDefault || $shouldSet) { |
|
660 | - $this->set($name[1], $this->reduce($value)); |
|
661 | - } |
|
662 | - break; |
|
663 | - } |
|
664 | - |
|
665 | - // if the value reduces to null from something else then |
|
666 | - // the property should be discarded |
|
667 | - if ($value[0] != "null") { |
|
668 | - $value = $this->reduce($value); |
|
669 | - if ($value[0] == "null") { |
|
670 | - break; |
|
671 | - } |
|
672 | - } |
|
673 | - |
|
674 | - $compiledValue = $this->compileValue($value); |
|
675 | - $out->lines[] = $this->formatter->property( |
|
676 | - $this->compileValue($name), |
|
677 | - $compiledValue); |
|
678 | - break; |
|
679 | - case "comment": |
|
680 | - $out->lines[] = $child[1]; |
|
681 | - break; |
|
682 | - case "mixin": |
|
683 | - case "function": |
|
684 | - list(,$block) = $child; |
|
685 | - $this->set(self::$namespaces[$block->type] . $block->name, $block); |
|
686 | - break; |
|
687 | - case "extend": |
|
688 | - list(, $selectors) = $child; |
|
689 | - foreach ($selectors as $sel) { |
|
690 | - // only use the first one |
|
691 | - $sel = current($this->evalSelector($sel)); |
|
692 | - $this->pushExtends($sel, $out->selectors); |
|
693 | - } |
|
694 | - break; |
|
695 | - case "if": |
|
696 | - list(, $if) = $child; |
|
697 | - if ($this->isTruthy($this->reduce($if->cond, true))) { |
|
698 | - return $this->compileChildren($if->children, $out); |
|
699 | - } else { |
|
700 | - foreach ($if->cases as $case) { |
|
701 | - if ($case->type == "else" || |
|
702 | - $case->type == "elseif" && $this->isTruthy($this->reduce($case->cond))) |
|
703 | - { |
|
704 | - return $this->compileChildren($case->children, $out); |
|
705 | - } |
|
706 | - } |
|
707 | - } |
|
708 | - break; |
|
709 | - case "return": |
|
710 | - return $this->reduce($child[1], true); |
|
711 | - case "each": |
|
712 | - list(,$each) = $child; |
|
713 | - $list = $this->coerceList($this->reduce($each->list)); |
|
714 | - foreach ($list[2] as $item) { |
|
715 | - $this->pushEnv(); |
|
716 | - $this->set($each->var, $item); |
|
717 | - // TODO: allow return from here |
|
718 | - $this->compileChildren($each->children, $out); |
|
719 | - $this->popEnv(); |
|
720 | - } |
|
721 | - break; |
|
722 | - case "while": |
|
723 | - list(,$while) = $child; |
|
724 | - while ($this->isTruthy($this->reduce($while->cond, true))) { |
|
725 | - $ret = $this->compileChildren($while->children, $out); |
|
726 | - if ($ret) return $ret; |
|
727 | - } |
|
728 | - break; |
|
729 | - case "for": |
|
730 | - list(,$for) = $child; |
|
731 | - $start = $this->reduce($for->start, true); |
|
732 | - $start = $start[1]; |
|
733 | - $end = $this->reduce($for->end, true); |
|
734 | - $end = $end[1]; |
|
735 | - $d = $start < $end ? 1 : -1; |
|
736 | - |
|
737 | - while (true) { |
|
738 | - if ((!$for->until && $start - $d == $end) || |
|
739 | - ($for->until && $start == $end)) |
|
740 | - { |
|
741 | - break; |
|
742 | - } |
|
743 | - |
|
744 | - $this->set($for->var, array("number", $start, "")); |
|
745 | - $start += $d; |
|
746 | - |
|
747 | - $ret = $this->compileChildren($for->children, $out); |
|
748 | - if ($ret) return $ret; |
|
749 | - } |
|
750 | - |
|
751 | - break; |
|
752 | - case "nestedprop": |
|
753 | - list(,$prop) = $child; |
|
754 | - $prefixed = array(); |
|
755 | - $prefix = $this->compileValue($prop->prefix) . "-"; |
|
756 | - foreach ($prop->children as $child) { |
|
757 | - if ($child[0] == "assign") { |
|
758 | - array_unshift($child[1][2], $prefix); |
|
759 | - } |
|
760 | - if ($child[0] == "nestedprop") { |
|
761 | - array_unshift($child[1]->prefix[2], $prefix); |
|
762 | - } |
|
763 | - $prefixed[] = $child; |
|
764 | - } |
|
765 | - $this->compileChildren($prefixed, $out); |
|
766 | - break; |
|
767 | - case "include": // including a mixin |
|
768 | - list(,$name, $argValues, $content) = $child; |
|
769 | - $mixin = $this->get(self::$namespaces["mixin"] . $name, false); |
|
770 | - if (!$mixin) { |
|
771 | - $this->throwError("Undefined mixin $name"); |
|
772 | - } |
|
773 | - |
|
774 | - $callingScope = $this->env; |
|
775 | - |
|
776 | - // push scope, apply args |
|
777 | - $this->pushEnv(); |
|
778 | - if ($this->env->depth > 0) { |
|
779 | - $this->env->depth--; |
|
780 | - } |
|
781 | - |
|
782 | - if (isset($content)) { |
|
783 | - $content->scope = $callingScope; |
|
784 | - $this->setRaw(self::$namespaces["special"] . "content", $content); |
|
785 | - } |
|
786 | - |
|
787 | - if (isset($mixin->args)) { |
|
788 | - $this->applyArguments($mixin->args, $argValues); |
|
789 | - } |
|
790 | - |
|
791 | - foreach ($mixin->children as $child) { |
|
792 | - $this->compileChild($child, $out); |
|
793 | - } |
|
794 | - |
|
795 | - $this->popEnv(); |
|
796 | - |
|
797 | - break; |
|
798 | - case "mixin_content": |
|
799 | - $content = $this->get(self::$namespaces["special"] . "content"); |
|
800 | - if (!isset($content)) { |
|
801 | - $this->throwError("Expected @content inside of mixin"); |
|
802 | - } |
|
803 | - |
|
804 | - $strongTypes = array('include', 'block', 'for', 'while'); |
|
805 | - foreach ($content->children as $child) { |
|
806 | - $this->storeEnv = (in_array($child[0], $strongTypes)) |
|
807 | - ? null |
|
808 | - : $content->scope; |
|
809 | - |
|
810 | - $this->compileChild($child, $out); |
|
811 | - } |
|
812 | - |
|
813 | - unset($this->storeEnv); |
|
814 | - break; |
|
815 | - case "debug": |
|
816 | - list(,$value, $pos) = $child; |
|
817 | - $line = $this->parser->getLineNo($pos); |
|
818 | - $value = $this->compileValue($this->reduce($value, true)); |
|
819 | - fwrite(STDERR, "Line $line DEBUG: $value\n"); |
|
820 | - break; |
|
821 | - default: |
|
822 | - $this->throwError("unknown child type: $child[0]"); |
|
625 | + case "import": |
|
626 | + list(,$rawPath) = $child; |
|
627 | + $rawPath = $this->reduce($rawPath); |
|
628 | + if (!$this->compileImport($rawPath, $out)) { |
|
629 | + $out->lines[] = "@import " . $this->compileValue($rawPath) . ";"; |
|
630 | + } |
|
631 | + break; |
|
632 | + case "directive": |
|
633 | + list(, $directive) = $child; |
|
634 | + $s = "@" . $directive->name; |
|
635 | + if (!empty($directive->value)) { |
|
636 | + $s .= " " . $this->compileValue($directive->value); |
|
637 | + } |
|
638 | + $this->compileNestedBlock($directive, array($s)); |
|
639 | + break; |
|
640 | + case "media": |
|
641 | + $this->compileMedia($child[1]); |
|
642 | + break; |
|
643 | + case "block": |
|
644 | + $this->compileBlock($child[1]); |
|
645 | + break; |
|
646 | + case "charset": |
|
647 | + $out->lines[] = "@charset ".$this->compileValue($child[1]).";"; |
|
648 | + break; |
|
649 | + case "assign": |
|
650 | + list(,$name, $value) = $child; |
|
651 | + if ($name[0] == "var") { |
|
652 | + $isDefault = !empty($child[3]); |
|
653 | + |
|
654 | + if ($isDefault) { |
|
655 | + $existingValue = $this->get($name[1], true); |
|
656 | + $shouldSet = $existingValue === true || $existingValue == self::$null; |
|
657 | + } |
|
658 | + |
|
659 | + if (!$isDefault || $shouldSet) { |
|
660 | + $this->set($name[1], $this->reduce($value)); |
|
661 | + } |
|
662 | + break; |
|
663 | + } |
|
664 | + |
|
665 | + // if the value reduces to null from something else then |
|
666 | + // the property should be discarded |
|
667 | + if ($value[0] != "null") { |
|
668 | + $value = $this->reduce($value); |
|
669 | + if ($value[0] == "null") { |
|
670 | + break; |
|
671 | + } |
|
672 | + } |
|
673 | + |
|
674 | + $compiledValue = $this->compileValue($value); |
|
675 | + $out->lines[] = $this->formatter->property( |
|
676 | + $this->compileValue($name), |
|
677 | + $compiledValue); |
|
678 | + break; |
|
679 | + case "comment": |
|
680 | + $out->lines[] = $child[1]; |
|
681 | + break; |
|
682 | + case "mixin": |
|
683 | + case "function": |
|
684 | + list(,$block) = $child; |
|
685 | + $this->set(self::$namespaces[$block->type] . $block->name, $block); |
|
686 | + break; |
|
687 | + case "extend": |
|
688 | + list(, $selectors) = $child; |
|
689 | + foreach ($selectors as $sel) { |
|
690 | + // only use the first one |
|
691 | + $sel = current($this->evalSelector($sel)); |
|
692 | + $this->pushExtends($sel, $out->selectors); |
|
693 | + } |
|
694 | + break; |
|
695 | + case "if": |
|
696 | + list(, $if) = $child; |
|
697 | + if ($this->isTruthy($this->reduce($if->cond, true))) { |
|
698 | + return $this->compileChildren($if->children, $out); |
|
699 | + } else { |
|
700 | + foreach ($if->cases as $case) { |
|
701 | + if ($case->type == "else" || |
|
702 | + $case->type == "elseif" && $this->isTruthy($this->reduce($case->cond))) |
|
703 | + { |
|
704 | + return $this->compileChildren($case->children, $out); |
|
705 | + } |
|
706 | + } |
|
707 | + } |
|
708 | + break; |
|
709 | + case "return": |
|
710 | + return $this->reduce($child[1], true); |
|
711 | + case "each": |
|
712 | + list(,$each) = $child; |
|
713 | + $list = $this->coerceList($this->reduce($each->list)); |
|
714 | + foreach ($list[2] as $item) { |
|
715 | + $this->pushEnv(); |
|
716 | + $this->set($each->var, $item); |
|
717 | + // TODO: allow return from here |
|
718 | + $this->compileChildren($each->children, $out); |
|
719 | + $this->popEnv(); |
|
720 | + } |
|
721 | + break; |
|
722 | + case "while": |
|
723 | + list(,$while) = $child; |
|
724 | + while ($this->isTruthy($this->reduce($while->cond, true))) { |
|
725 | + $ret = $this->compileChildren($while->children, $out); |
|
726 | + if ($ret) return $ret; |
|
727 | + } |
|
728 | + break; |
|
729 | + case "for": |
|
730 | + list(,$for) = $child; |
|
731 | + $start = $this->reduce($for->start, true); |
|
732 | + $start = $start[1]; |
|
733 | + $end = $this->reduce($for->end, true); |
|
734 | + $end = $end[1]; |
|
735 | + $d = $start < $end ? 1 : -1; |
|
736 | + |
|
737 | + while (true) { |
|
738 | + if ((!$for->until && $start - $d == $end) || |
|
739 | + ($for->until && $start == $end)) |
|
740 | + { |
|
741 | + break; |
|
742 | + } |
|
743 | + |
|
744 | + $this->set($for->var, array("number", $start, "")); |
|
745 | + $start += $d; |
|
746 | + |
|
747 | + $ret = $this->compileChildren($for->children, $out); |
|
748 | + if ($ret) return $ret; |
|
749 | + } |
|
750 | + |
|
751 | + break; |
|
752 | + case "nestedprop": |
|
753 | + list(,$prop) = $child; |
|
754 | + $prefixed = array(); |
|
755 | + $prefix = $this->compileValue($prop->prefix) . "-"; |
|
756 | + foreach ($prop->children as $child) { |
|
757 | + if ($child[0] == "assign") { |
|
758 | + array_unshift($child[1][2], $prefix); |
|
759 | + } |
|
760 | + if ($child[0] == "nestedprop") { |
|
761 | + array_unshift($child[1]->prefix[2], $prefix); |
|
762 | + } |
|
763 | + $prefixed[] = $child; |
|
764 | + } |
|
765 | + $this->compileChildren($prefixed, $out); |
|
766 | + break; |
|
767 | + case "include": // including a mixin |
|
768 | + list(,$name, $argValues, $content) = $child; |
|
769 | + $mixin = $this->get(self::$namespaces["mixin"] . $name, false); |
|
770 | + if (!$mixin) { |
|
771 | + $this->throwError("Undefined mixin $name"); |
|
772 | + } |
|
773 | + |
|
774 | + $callingScope = $this->env; |
|
775 | + |
|
776 | + // push scope, apply args |
|
777 | + $this->pushEnv(); |
|
778 | + if ($this->env->depth > 0) { |
|
779 | + $this->env->depth--; |
|
780 | + } |
|
781 | + |
|
782 | + if (isset($content)) { |
|
783 | + $content->scope = $callingScope; |
|
784 | + $this->setRaw(self::$namespaces["special"] . "content", $content); |
|
785 | + } |
|
786 | + |
|
787 | + if (isset($mixin->args)) { |
|
788 | + $this->applyArguments($mixin->args, $argValues); |
|
789 | + } |
|
790 | + |
|
791 | + foreach ($mixin->children as $child) { |
|
792 | + $this->compileChild($child, $out); |
|
793 | + } |
|
794 | + |
|
795 | + $this->popEnv(); |
|
796 | + |
|
797 | + break; |
|
798 | + case "mixin_content": |
|
799 | + $content = $this->get(self::$namespaces["special"] . "content"); |
|
800 | + if (!isset($content)) { |
|
801 | + $this->throwError("Expected @content inside of mixin"); |
|
802 | + } |
|
803 | + |
|
804 | + $strongTypes = array('include', 'block', 'for', 'while'); |
|
805 | + foreach ($content->children as $child) { |
|
806 | + $this->storeEnv = (in_array($child[0], $strongTypes)) |
|
807 | + ? null |
|
808 | + : $content->scope; |
|
809 | + |
|
810 | + $this->compileChild($child, $out); |
|
811 | + } |
|
812 | + |
|
813 | + unset($this->storeEnv); |
|
814 | + break; |
|
815 | + case "debug": |
|
816 | + list(,$value, $pos) = $child; |
|
817 | + $line = $this->parser->getLineNo($pos); |
|
818 | + $value = $this->compileValue($this->reduce($value, true)); |
|
819 | + fwrite(STDERR, "Line $line DEBUG: $value\n"); |
|
820 | + break; |
|
821 | + default: |
|
822 | + $this->throwError("unknown child type: $child[0]"); |
|
823 | 823 | } |
824 | 824 | } |
825 | 825 | |
@@ -840,13 +840,13 @@ discard block |
||
840 | 840 | // should $value cause its operand to eval |
841 | 841 | protected function shouldEval($value) { |
842 | 842 | switch ($value[0]) { |
843 | - case "exp": |
|
844 | - if ($value[1] == "/") { |
|
845 | - return $this->shouldEval($value[2], $value[3]); |
|
846 | - } |
|
847 | - case "var": |
|
848 | - case "fncall": |
|
849 | - return true; |
|
843 | + case "exp": |
|
844 | + if ($value[1] == "/") { |
|
845 | + return $this->shouldEval($value[2], $value[3]); |
|
846 | + } |
|
847 | + case "var": |
|
848 | + case "fncall": |
|
849 | + return true; |
|
850 | 850 | } |
851 | 851 | return false; |
852 | 852 | } |
@@ -947,11 +947,11 @@ discard block |
||
947 | 947 | $exp = $this->reduce($exp); |
948 | 948 | if ($exp[0] == "number") { |
949 | 949 | switch ($op) { |
950 | - case "+": |
|
951 | - return $exp; |
|
952 | - case "-": |
|
953 | - $exp[1] *= -1; |
|
954 | - return $exp; |
|
950 | + case "+": |
|
951 | + return $exp; |
|
952 | + case "-": |
|
953 | + $exp[1] *= -1; |
|
954 | + return $exp; |
|
955 | 955 | } |
956 | 956 | } |
957 | 957 | |
@@ -1033,19 +1033,19 @@ discard block |
||
1033 | 1033 | list($type) = $value; |
1034 | 1034 | |
1035 | 1035 | switch ($type) { |
1036 | - case "list": |
|
1037 | - $value = $this->extractInterpolation($value); |
|
1038 | - if ($value[0] != "list") { |
|
1039 | - return array("keyword", $this->compileValue($value)); |
|
1040 | - } |
|
1041 | - foreach ($value[2] as $key => $item) { |
|
1042 | - $value[2][$key] = $this->normalizeValue($item); |
|
1043 | - } |
|
1044 | - return $value; |
|
1045 | - case "number": |
|
1046 | - return $this->normalizeNumber($value); |
|
1047 | - default: |
|
1048 | - return $value; |
|
1036 | + case "list": |
|
1037 | + $value = $this->extractInterpolation($value); |
|
1038 | + if ($value[0] != "list") { |
|
1039 | + return array("keyword", $this->compileValue($value)); |
|
1040 | + } |
|
1041 | + foreach ($value[2] as $key => $item) { |
|
1042 | + $value[2][$key] = $this->normalizeValue($item); |
|
1043 | + } |
|
1044 | + return $value; |
|
1045 | + case "number": |
|
1046 | + return $this->normalizeNumber($value); |
|
1047 | + default: |
|
1048 | + return $value; |
|
1049 | 1049 | } |
1050 | 1050 | } |
1051 | 1051 | |
@@ -1126,30 +1126,30 @@ discard block |
||
1126 | 1126 | $lval = isset($left[$i]) ? $left[$i] : 0; |
1127 | 1127 | $rval = isset($right[$i]) ? $right[$i] : 0; |
1128 | 1128 | switch ($op) { |
1129 | - case '+': |
|
1130 | - $out[] = $lval + $rval; |
|
1131 | - break; |
|
1132 | - case '-': |
|
1133 | - $out[] = $lval - $rval; |
|
1134 | - break; |
|
1135 | - case '*': |
|
1136 | - $out[] = $lval * $rval; |
|
1137 | - break; |
|
1138 | - case '%': |
|
1139 | - $out[] = $lval % $rval; |
|
1140 | - break; |
|
1141 | - case '/': |
|
1142 | - if ($rval == 0) { |
|
1143 | - $this->throwError("color: Can't divide by zero"); |
|
1144 | - } |
|
1145 | - $out[] = $lval / $rval; |
|
1146 | - break; |
|
1147 | - case "==": |
|
1148 | - return $this->op_eq($left, $right); |
|
1149 | - case "!=": |
|
1150 | - return $this->op_neq($left, $right); |
|
1151 | - default: |
|
1152 | - $this->throwError("color: unknown op $op"); |
|
1129 | + case '+': |
|
1130 | + $out[] = $lval + $rval; |
|
1131 | + break; |
|
1132 | + case '-': |
|
1133 | + $out[] = $lval - $rval; |
|
1134 | + break; |
|
1135 | + case '*': |
|
1136 | + $out[] = $lval * $rval; |
|
1137 | + break; |
|
1138 | + case '%': |
|
1139 | + $out[] = $lval % $rval; |
|
1140 | + break; |
|
1141 | + case '/': |
|
1142 | + if ($rval == 0) { |
|
1143 | + $this->throwError("color: Can't divide by zero"); |
|
1144 | + } |
|
1145 | + $out[] = $lval / $rval; |
|
1146 | + break; |
|
1147 | + case "==": |
|
1148 | + return $this->op_eq($left, $right); |
|
1149 | + case "!=": |
|
1150 | + return $this->op_neq($left, $right); |
|
1151 | + default: |
|
1152 | + $this->throwError("color: unknown op $op"); |
|
1153 | 1153 | } |
1154 | 1154 | } |
1155 | 1155 | |
@@ -1223,82 +1223,82 @@ discard block |
||
1223 | 1223 | |
1224 | 1224 | list($type) = $value; |
1225 | 1225 | switch ($type) { |
1226 | - case "keyword": |
|
1227 | - return $value[1]; |
|
1228 | - case "color": |
|
1229 | - // [1] - red component (either number for a %) |
|
1230 | - // [2] - green component |
|
1231 | - // [3] - blue component |
|
1232 | - // [4] - optional alpha component |
|
1233 | - list(, $r, $g, $b) = $value; |
|
1234 | - |
|
1235 | - $r = round((int)$r); |
|
1236 | - $g = round((int)$g); |
|
1237 | - $b = round((int)$b); |
|
1238 | - |
|
1239 | - if (count($value) == 5 && $value[4] != 1) { // rgba |
|
1240 | - return 'rgba('.$r.', '.$g.', '.$b.', '.$value[4].')'; |
|
1241 | - } |
|
1242 | - |
|
1243 | - $h = sprintf("#%02x%02x%02x", $r, $g, $b); |
|
1244 | - |
|
1245 | - // Converting hex color to short notation (e.g. #003399 to #039) |
|
1246 | - if ($h[1] === $h[2] && $h[3] === $h[4] && $h[5] === $h[6]) { |
|
1247 | - $h = '#' . $h[1] . $h[3] . $h[5]; |
|
1248 | - } |
|
1249 | - |
|
1250 | - return $h; |
|
1251 | - case "number": |
|
1252 | - return round($value[1], $this->numberPrecision) . $value[2]; |
|
1253 | - case "string": |
|
1254 | - return $value[1] . $this->compileStringContent($value) . $value[1]; |
|
1255 | - case "function": |
|
1256 | - $args = !empty($value[2]) ? $this->compileValue($value[2]) : ""; |
|
1257 | - return "$value[1]($args)"; |
|
1258 | - case "list": |
|
1259 | - $value = $this->extractInterpolation($value); |
|
1260 | - if ($value[0] != "list") return $this->compileValue($value); |
|
1261 | - |
|
1262 | - list(, $delim, $items) = $value; |
|
1263 | - |
|
1264 | - $filtered = array(); |
|
1265 | - foreach ($items as $item) { |
|
1266 | - if ($item[0] == "null") continue; |
|
1267 | - $filtered[] = $this->compileValue($item); |
|
1268 | - } |
|
1269 | - |
|
1270 | - return implode("$delim ", $filtered); |
|
1271 | - case "interpolated": # node created by extractInterpolation |
|
1272 | - list(, $interpolate, $left, $right) = $value; |
|
1273 | - list(,, $whiteLeft, $whiteRight) = $interpolate; |
|
1274 | - |
|
1275 | - $left = count($left[2]) > 0 ? |
|
1276 | - $this->compileValue($left).$whiteLeft : ""; |
|
1277 | - |
|
1278 | - $right = count($right[2]) > 0 ? |
|
1279 | - $whiteRight.$this->compileValue($right) : ""; |
|
1280 | - |
|
1281 | - return $left.$this->compileValue($interpolate).$right; |
|
1282 | - |
|
1283 | - case "interpolate": # raw parse node |
|
1284 | - list(, $exp) = $value; |
|
1285 | - |
|
1286 | - // strip quotes if it's a string |
|
1287 | - $reduced = $this->reduce($exp); |
|
1288 | - switch ($reduced[0]) { |
|
1226 | + case "keyword": |
|
1227 | + return $value[1]; |
|
1228 | + case "color": |
|
1229 | + // [1] - red component (either number for a %) |
|
1230 | + // [2] - green component |
|
1231 | + // [3] - blue component |
|
1232 | + // [4] - optional alpha component |
|
1233 | + list(, $r, $g, $b) = $value; |
|
1234 | + |
|
1235 | + $r = round((int)$r); |
|
1236 | + $g = round((int)$g); |
|
1237 | + $b = round((int)$b); |
|
1238 | + |
|
1239 | + if (count($value) == 5 && $value[4] != 1) { // rgba |
|
1240 | + return 'rgba('.$r.', '.$g.', '.$b.', '.$value[4].')'; |
|
1241 | + } |
|
1242 | + |
|
1243 | + $h = sprintf("#%02x%02x%02x", $r, $g, $b); |
|
1244 | + |
|
1245 | + // Converting hex color to short notation (e.g. #003399 to #039) |
|
1246 | + if ($h[1] === $h[2] && $h[3] === $h[4] && $h[5] === $h[6]) { |
|
1247 | + $h = '#' . $h[1] . $h[3] . $h[5]; |
|
1248 | + } |
|
1249 | + |
|
1250 | + return $h; |
|
1251 | + case "number": |
|
1252 | + return round($value[1], $this->numberPrecision) . $value[2]; |
|
1253 | + case "string": |
|
1254 | + return $value[1] . $this->compileStringContent($value) . $value[1]; |
|
1255 | + case "function": |
|
1256 | + $args = !empty($value[2]) ? $this->compileValue($value[2]) : ""; |
|
1257 | + return "$value[1]($args)"; |
|
1258 | + case "list": |
|
1259 | + $value = $this->extractInterpolation($value); |
|
1260 | + if ($value[0] != "list") return $this->compileValue($value); |
|
1261 | + |
|
1262 | + list(, $delim, $items) = $value; |
|
1263 | + |
|
1264 | + $filtered = array(); |
|
1265 | + foreach ($items as $item) { |
|
1266 | + if ($item[0] == "null") continue; |
|
1267 | + $filtered[] = $this->compileValue($item); |
|
1268 | + } |
|
1269 | + |
|
1270 | + return implode("$delim ", $filtered); |
|
1271 | + case "interpolated": # node created by extractInterpolation |
|
1272 | + list(, $interpolate, $left, $right) = $value; |
|
1273 | + list(,, $whiteLeft, $whiteRight) = $interpolate; |
|
1274 | + |
|
1275 | + $left = count($left[2]) > 0 ? |
|
1276 | + $this->compileValue($left).$whiteLeft : ""; |
|
1277 | + |
|
1278 | + $right = count($right[2]) > 0 ? |
|
1279 | + $whiteRight.$this->compileValue($right) : ""; |
|
1280 | + |
|
1281 | + return $left.$this->compileValue($interpolate).$right; |
|
1282 | + |
|
1283 | + case "interpolate": # raw parse node |
|
1284 | + list(, $exp) = $value; |
|
1285 | + |
|
1286 | + // strip quotes if it's a string |
|
1287 | + $reduced = $this->reduce($exp); |
|
1288 | + switch ($reduced[0]) { |
|
1289 | 1289 | case "string": |
1290 | 1290 | $reduced = array("keyword", |
1291 | 1291 | $this->compileStringContent($reduced)); |
1292 | 1292 | break; |
1293 | 1293 | case "null": |
1294 | 1294 | $reduced = array("keyword", ""); |
1295 | - } |
|
1295 | + } |
|
1296 | 1296 | |
1297 | 1297 | return $this->compileValue($reduced); |
1298 | - case "null": |
|
1299 | - return "null"; |
|
1300 | - default: |
|
1301 | - $this->throwError("unknown value type: $type"); |
|
1298 | + case "null": |
|
1299 | + return "null"; |
|
1300 | + default: |
|
1301 | + $this->throwError("unknown value type: $type"); |
|
1302 | 1302 | } |
1303 | 1303 | } |
1304 | 1304 | |
@@ -1741,16 +1741,16 @@ discard block |
||
1741 | 1741 | |
1742 | 1742 | protected function coerceColor($value) { |
1743 | 1743 | switch ($value[0]) { |
1744 | - case "color": return $value; |
|
1745 | - case "keyword": |
|
1746 | - $name = $value[1]; |
|
1747 | - if (isset(self::$cssColors[$name])) { |
|
1748 | - $rgba = explode(',', self::$cssColors[$name]); |
|
1749 | - return isset($rgba[3]) |
|
1750 | - ? array('color', (int) $rgba[0], (int) $rgba[1], (int) $rgba[2], (int) $rgba[3]) |
|
1751 | - : array('color', (int) $rgba[0], (int) $rgba[1], (int) $rgba[2]); |
|
1752 | - } |
|
1753 | - return null; |
|
1744 | + case "color": return $value; |
|
1745 | + case "keyword": |
|
1746 | + $name = $value[1]; |
|
1747 | + if (isset(self::$cssColors[$name])) { |
|
1748 | + $rgba = explode(',', self::$cssColors[$name]); |
|
1749 | + return isset($rgba[3]) |
|
1750 | + ? array('color', (int) $rgba[0], (int) $rgba[1], (int) $rgba[2], (int) $rgba[3]) |
|
1751 | + : array('color', (int) $rgba[0], (int) $rgba[1], (int) $rgba[2]); |
|
1752 | + } |
|
1753 | + return null; |
|
1754 | 1754 | } |
1755 | 1755 | |
1756 | 1756 | return null; |
@@ -1758,10 +1758,10 @@ discard block |
||
1758 | 1758 | |
1759 | 1759 | protected function coerceString($value) { |
1760 | 1760 | switch ($value[0]) { |
1761 | - case "string": |
|
1762 | - return $value; |
|
1763 | - case "keyword": |
|
1764 | - return array("string", "", array($value[1])); |
|
1761 | + case "string": |
|
1762 | + return $value; |
|
1763 | + case "keyword": |
|
1764 | + return array("string", "", array($value[1])); |
|
1765 | 1765 | } |
1766 | 1766 | return null; |
1767 | 1767 | } |
@@ -1974,16 +1974,16 @@ discard block |
||
1974 | 1974 | // 4, 5, 6 - hsl |
1975 | 1975 | // 7 - a |
1976 | 1976 | switch ($i) { |
1977 | - case 1: |
|
1978 | - case 2: |
|
1979 | - case 3: |
|
1980 | - $max = 255; break; |
|
1981 | - case 4: |
|
1982 | - $max = 360; break; |
|
1983 | - case 7: |
|
1984 | - $max = 1; break; |
|
1985 | - default: |
|
1986 | - $max = 100; |
|
1977 | + case 1: |
|
1978 | + case 2: |
|
1979 | + case 3: |
|
1980 | + $max = 255; break; |
|
1981 | + case 4: |
|
1982 | + $max = 360; break; |
|
1983 | + case 7: |
|
1984 | + $max = 1; break; |
|
1985 | + default: |
|
1986 | + $max = 100; |
|
1987 | 1987 | } |
1988 | 1988 | |
1989 | 1989 | $scale = $scale / 100; |
@@ -2324,12 +2324,12 @@ discard block |
||
2324 | 2324 | protected function listSeparatorForJoin($list1, $sep) { |
2325 | 2325 | if (!isset($sep)) return $list1[1]; |
2326 | 2326 | switch ($this->compileValue($sep)) { |
2327 | - case "comma": |
|
2328 | - return ","; |
|
2329 | - case "space": |
|
2330 | - return ""; |
|
2331 | - default: |
|
2332 | - return $list1[1]; |
|
2327 | + case "comma": |
|
2328 | + return ","; |
|
2329 | + case "space": |
|
2330 | + return ""; |
|
2331 | + default: |
|
2332 | + return $list1[1]; |
|
2333 | 2333 | } |
2334 | 2334 | } |
2335 | 2335 | |
@@ -2376,18 +2376,18 @@ discard block |
||
2376 | 2376 | protected function lib_type_of($args) { |
2377 | 2377 | $value = $args[0]; |
2378 | 2378 | switch ($value[0]) { |
2379 | - case "keyword": |
|
2380 | - if ($value == self::$true || $value == self::$false) { |
|
2381 | - return "bool"; |
|
2382 | - } |
|
2383 | - |
|
2384 | - if ($this->coerceColor($value)) { |
|
2385 | - return "color"; |
|
2386 | - } |
|
2387 | - |
|
2388 | - return "string"; |
|
2389 | - default: |
|
2390 | - return $value[0]; |
|
2379 | + case "keyword": |
|
2380 | + if ($value == self::$true || $value == self::$false) { |
|
2381 | + return "bool"; |
|
2382 | + } |
|
2383 | + |
|
2384 | + if ($this->coerceColor($value)) { |
|
2385 | + return "color"; |
|
2386 | + } |
|
2387 | + |
|
2388 | + return "string"; |
|
2389 | + default: |
|
2390 | + return $value[0]; |
|
2391 | 2391 | } |
2392 | 2392 | } |
2393 | 2393 |
@@ -353,12 +353,12 @@ discard block |
||
353 | 353 | foreach ($piece as &$p) { |
354 | 354 | if (!is_array($p)) continue; |
355 | 355 | switch ($p[0]) { |
356 | - case "interpolate": |
|
357 | - $p = $this->compileValue($p); |
|
358 | - break; |
|
359 | - case "string": |
|
360 | - $p = $this->compileValue($p); |
|
361 | - break; |
|
356 | + case "interpolate": |
|
357 | + $p = $this->compileValue($p); |
|
358 | + break; |
|
359 | + case "string": |
|
360 | + $p = $this->compileValue($p); |
|
361 | + break; |
|
362 | 362 | } |
363 | 363 | } |
364 | 364 | return $this->flattenSelectorSingle($piece); |
@@ -374,12 +374,12 @@ discard block |
||
374 | 374 | foreach ($piece as &$p) { |
375 | 375 | if (!is_array($p)) continue; |
376 | 376 | switch ($p[0]) { |
377 | - case "self": |
|
378 | - $p = "&"; |
|
379 | - break; |
|
380 | - default: |
|
381 | - $p = $this->compileValue($p); |
|
382 | - break; |
|
377 | + case "self": |
|
378 | + $p = "&"; |
|
379 | + break; |
|
380 | + default: |
|
381 | + $p = $this->compileValue($p); |
|
382 | + break; |
|
383 | 383 | } |
384 | 384 | } |
385 | 385 | return implode($piece); |
@@ -461,186 +461,186 @@ discard block |
||
461 | 461 | $this->sourcePos = isset($child[-1]) ? $child[-1] : -1; |
462 | 462 | $this->sourceParser = isset($child[-2]) ? $child[-2] : $this->parser; |
463 | 463 | switch ($child[0]) { |
464 | - case "import": |
|
465 | - list(,$rawPath) = $child; |
|
466 | - $rawPath = $this->reduce($rawPath); |
|
467 | - if (!$this->compileImport($rawPath, $out)) { |
|
468 | - $out->lines[] = "@import " . $this->compileValue($rawPath) . ";"; |
|
469 | - } |
|
470 | - break; |
|
471 | - case "directive": |
|
472 | - list(, $directive) = $child; |
|
473 | - $s = "@" . $directive->name; |
|
474 | - if (!empty($directive->value)) { |
|
475 | - $s .= " " . $this->compileValue($directive->value); |
|
476 | - } |
|
477 | - $this->compileNestedBlock($directive, array($s)); |
|
478 | - break; |
|
479 | - case "media": |
|
480 | - $this->compileMedia($child[1]); |
|
481 | - break; |
|
482 | - case "block": |
|
483 | - $this->compileBlock($child[1]); |
|
484 | - break; |
|
485 | - case "charset": |
|
486 | - $out->lines[] = "@charset ".$this->compileValue($child[1]).";"; |
|
487 | - break; |
|
488 | - case "assign": |
|
489 | - list(,$name, $value) = $child; |
|
490 | - if ($name[0] == "var") { |
|
491 | - $isDefault = !empty($child[3]); |
|
492 | - if ($isDefault) { |
|
493 | - $existingValue = $this->get($name[1], true); |
|
494 | - $shouldSet = $existingValue === true || $existingValue == self::$null; |
|
495 | - } |
|
496 | - if (!$isDefault || $shouldSet) { |
|
497 | - $this->set($name[1], $this->reduce($value)); |
|
498 | - } |
|
499 | - break; |
|
500 | - } |
|
501 | - // if the value reduces to null from something else then |
|
502 | - // the property should be discarded |
|
503 | - if ($value[0] != "null") { |
|
504 | - $value = $this->reduce($value); |
|
505 | - if ($value[0] == "null") { |
|
506 | - break; |
|
507 | - } |
|
508 | - } |
|
509 | - $compiledValue = $this->compileValue($value); |
|
510 | - $out->lines[] = $this->formatter->property( |
|
511 | - $this->compileValue($name), |
|
512 | - $compiledValue); |
|
513 | - break; |
|
514 | - case "comment": |
|
515 | - $out->lines[] = $child[1]; |
|
516 | - break; |
|
517 | - case "mixin": |
|
518 | - case "function": |
|
519 | - list(,$block) = $child; |
|
520 | - $this->set(self::$namespaces[$block->type] . $block->name, $block); |
|
521 | - break; |
|
522 | - case "extend": |
|
523 | - list(, $selectors) = $child; |
|
524 | - foreach ($selectors as $sel) { |
|
525 | - // only use the first one |
|
526 | - $sel = current($this->evalSelector($sel)); |
|
527 | - $this->pushExtends($sel, $out->selectors); |
|
528 | - } |
|
529 | - break; |
|
530 | - case "if": |
|
531 | - list(, $if) = $child; |
|
532 | - if ($this->isTruthy($this->reduce($if->cond, true))) { |
|
533 | - return $this->compileChildren($if->children, $out); |
|
534 | - } else { |
|
535 | - foreach ($if->cases as $case) { |
|
536 | - if ($case->type == "else" || |
|
537 | - $case->type == "elseif" && $this->isTruthy($this->reduce($case->cond))) |
|
538 | - { |
|
539 | - return $this->compileChildren($case->children, $out); |
|
540 | - } |
|
541 | - } |
|
542 | - } |
|
543 | - break; |
|
544 | - case "return": |
|
545 | - return $this->reduce($child[1], true); |
|
546 | - case "each": |
|
547 | - list(,$each) = $child; |
|
548 | - $list = $this->coerceList($this->reduce($each->list)); |
|
549 | - foreach ($list[2] as $item) { |
|
550 | - $this->pushEnv(); |
|
551 | - $this->set($each->var, $item); |
|
552 | - // TODO: allow return from here |
|
553 | - $this->compileChildren($each->children, $out); |
|
554 | - $this->popEnv(); |
|
555 | - } |
|
556 | - break; |
|
557 | - case "while": |
|
558 | - list(,$while) = $child; |
|
559 | - while ($this->isTruthy($this->reduce($while->cond, true))) { |
|
560 | - $ret = $this->compileChildren($while->children, $out); |
|
561 | - if ($ret) return $ret; |
|
562 | - } |
|
563 | - break; |
|
564 | - case "for": |
|
565 | - list(,$for) = $child; |
|
566 | - $start = $this->reduce($for->start, true); |
|
567 | - $start = $start[1]; |
|
568 | - $end = $this->reduce($for->end, true); |
|
569 | - $end = $end[1]; |
|
570 | - $d = $start < $end ? 1 : -1; |
|
571 | - while (true) { |
|
572 | - if ((!$for->until && $start - $d == $end) || |
|
573 | - ($for->until && $start == $end)) |
|
574 | - { |
|
575 | - break; |
|
576 | - } |
|
577 | - $this->set($for->var, array("number", $start, "")); |
|
578 | - $start += $d; |
|
579 | - $ret = $this->compileChildren($for->children, $out); |
|
580 | - if ($ret) return $ret; |
|
581 | - } |
|
582 | - break; |
|
583 | - case "nestedprop": |
|
584 | - list(,$prop) = $child; |
|
585 | - $prefixed = array(); |
|
586 | - $prefix = $this->compileValue($prop->prefix) . "-"; |
|
587 | - foreach ($prop->children as $child) { |
|
588 | - if ($child[0] == "assign") { |
|
589 | - array_unshift($child[1][2], $prefix); |
|
590 | - } |
|
591 | - if ($child[0] == "nestedprop") { |
|
592 | - array_unshift($child[1]->prefix[2], $prefix); |
|
593 | - } |
|
594 | - $prefixed[] = $child; |
|
595 | - } |
|
596 | - $this->compileChildren($prefixed, $out); |
|
597 | - break; |
|
598 | - case "include": // including a mixin |
|
599 | - list(,$name, $argValues, $content) = $child; |
|
600 | - $mixin = $this->get(self::$namespaces["mixin"] . $name, false); |
|
601 | - if (!$mixin) { |
|
602 | - $this->throwError("Undefined mixin $name"); |
|
603 | - } |
|
604 | - $callingScope = $this->env; |
|
605 | - // push scope, apply args |
|
606 | - $this->pushEnv(); |
|
607 | - if ($this->env->depth > 0) { |
|
608 | - $this->env->depth--; |
|
609 | - } |
|
610 | - if (!is_null($content)) { |
|
611 | - $content->scope = $callingScope; |
|
612 | - $this->setRaw(self::$namespaces["special"] . "content", $content); |
|
613 | - } |
|
614 | - if (!is_null($mixin->args)) { |
|
615 | - $this->applyArguments($mixin->args, $argValues); |
|
616 | - } |
|
617 | - foreach ($mixin->children as $child) { |
|
618 | - $this->compileChild($child, $out); |
|
619 | - } |
|
620 | - $this->popEnv(); |
|
621 | - break; |
|
622 | - case "mixin_content": |
|
623 | - $content = $this->get(self::$namespaces["special"] . "content"); |
|
624 | - if (is_null($content)) { |
|
625 | - $this->throwError("Expected @content inside of mixin"); |
|
626 | - } |
|
627 | - $strongTypes = array('include', 'block', 'for', 'while'); |
|
628 | - foreach ($content->children as $child) { |
|
629 | - $this->storeEnv = (in_array($child[0], $strongTypes)) |
|
630 | - ? null |
|
631 | - : $content->scope; |
|
632 | - $this->compileChild($child, $out); |
|
633 | - } |
|
634 | - unset($this->storeEnv); |
|
635 | - break; |
|
636 | - case "debug": |
|
637 | - list(,$value, $pos) = $child; |
|
638 | - $line = $this->parser->getLineNo($pos); |
|
639 | - $value = $this->compileValue($this->reduce($value, true)); |
|
640 | - fwrite(STDERR, "Line $line DEBUG: $value\n"); |
|
641 | - break; |
|
642 | - default: |
|
643 | - $this->throwError("unknown child type: $child[0]"); |
|
464 | + case "import": |
|
465 | + list(,$rawPath) = $child; |
|
466 | + $rawPath = $this->reduce($rawPath); |
|
467 | + if (!$this->compileImport($rawPath, $out)) { |
|
468 | + $out->lines[] = "@import " . $this->compileValue($rawPath) . ";"; |
|
469 | + } |
|
470 | + break; |
|
471 | + case "directive": |
|
472 | + list(, $directive) = $child; |
|
473 | + $s = "@" . $directive->name; |
|
474 | + if (!empty($directive->value)) { |
|
475 | + $s .= " " . $this->compileValue($directive->value); |
|
476 | + } |
|
477 | + $this->compileNestedBlock($directive, array($s)); |
|
478 | + break; |
|
479 | + case "media": |
|
480 | + $this->compileMedia($child[1]); |
|
481 | + break; |
|
482 | + case "block": |
|
483 | + $this->compileBlock($child[1]); |
|
484 | + break; |
|
485 | + case "charset": |
|
486 | + $out->lines[] = "@charset ".$this->compileValue($child[1]).";"; |
|
487 | + break; |
|
488 | + case "assign": |
|
489 | + list(,$name, $value) = $child; |
|
490 | + if ($name[0] == "var") { |
|
491 | + $isDefault = !empty($child[3]); |
|
492 | + if ($isDefault) { |
|
493 | + $existingValue = $this->get($name[1], true); |
|
494 | + $shouldSet = $existingValue === true || $existingValue == self::$null; |
|
495 | + } |
|
496 | + if (!$isDefault || $shouldSet) { |
|
497 | + $this->set($name[1], $this->reduce($value)); |
|
498 | + } |
|
499 | + break; |
|
500 | + } |
|
501 | + // if the value reduces to null from something else then |
|
502 | + // the property should be discarded |
|
503 | + if ($value[0] != "null") { |
|
504 | + $value = $this->reduce($value); |
|
505 | + if ($value[0] == "null") { |
|
506 | + break; |
|
507 | + } |
|
508 | + } |
|
509 | + $compiledValue = $this->compileValue($value); |
|
510 | + $out->lines[] = $this->formatter->property( |
|
511 | + $this->compileValue($name), |
|
512 | + $compiledValue); |
|
513 | + break; |
|
514 | + case "comment": |
|
515 | + $out->lines[] = $child[1]; |
|
516 | + break; |
|
517 | + case "mixin": |
|
518 | + case "function": |
|
519 | + list(,$block) = $child; |
|
520 | + $this->set(self::$namespaces[$block->type] . $block->name, $block); |
|
521 | + break; |
|
522 | + case "extend": |
|
523 | + list(, $selectors) = $child; |
|
524 | + foreach ($selectors as $sel) { |
|
525 | + // only use the first one |
|
526 | + $sel = current($this->evalSelector($sel)); |
|
527 | + $this->pushExtends($sel, $out->selectors); |
|
528 | + } |
|
529 | + break; |
|
530 | + case "if": |
|
531 | + list(, $if) = $child; |
|
532 | + if ($this->isTruthy($this->reduce($if->cond, true))) { |
|
533 | + return $this->compileChildren($if->children, $out); |
|
534 | + } else { |
|
535 | + foreach ($if->cases as $case) { |
|
536 | + if ($case->type == "else" || |
|
537 | + $case->type == "elseif" && $this->isTruthy($this->reduce($case->cond))) |
|
538 | + { |
|
539 | + return $this->compileChildren($case->children, $out); |
|
540 | + } |
|
541 | + } |
|
542 | + } |
|
543 | + break; |
|
544 | + case "return": |
|
545 | + return $this->reduce($child[1], true); |
|
546 | + case "each": |
|
547 | + list(,$each) = $child; |
|
548 | + $list = $this->coerceList($this->reduce($each->list)); |
|
549 | + foreach ($list[2] as $item) { |
|
550 | + $this->pushEnv(); |
|
551 | + $this->set($each->var, $item); |
|
552 | + // TODO: allow return from here |
|
553 | + $this->compileChildren($each->children, $out); |
|
554 | + $this->popEnv(); |
|
555 | + } |
|
556 | + break; |
|
557 | + case "while": |
|
558 | + list(,$while) = $child; |
|
559 | + while ($this->isTruthy($this->reduce($while->cond, true))) { |
|
560 | + $ret = $this->compileChildren($while->children, $out); |
|
561 | + if ($ret) return $ret; |
|
562 | + } |
|
563 | + break; |
|
564 | + case "for": |
|
565 | + list(,$for) = $child; |
|
566 | + $start = $this->reduce($for->start, true); |
|
567 | + $start = $start[1]; |
|
568 | + $end = $this->reduce($for->end, true); |
|
569 | + $end = $end[1]; |
|
570 | + $d = $start < $end ? 1 : -1; |
|
571 | + while (true) { |
|
572 | + if ((!$for->until && $start - $d == $end) || |
|
573 | + ($for->until && $start == $end)) |
|
574 | + { |
|
575 | + break; |
|
576 | + } |
|
577 | + $this->set($for->var, array("number", $start, "")); |
|
578 | + $start += $d; |
|
579 | + $ret = $this->compileChildren($for->children, $out); |
|
580 | + if ($ret) return $ret; |
|
581 | + } |
|
582 | + break; |
|
583 | + case "nestedprop": |
|
584 | + list(,$prop) = $child; |
|
585 | + $prefixed = array(); |
|
586 | + $prefix = $this->compileValue($prop->prefix) . "-"; |
|
587 | + foreach ($prop->children as $child) { |
|
588 | + if ($child[0] == "assign") { |
|
589 | + array_unshift($child[1][2], $prefix); |
|
590 | + } |
|
591 | + if ($child[0] == "nestedprop") { |
|
592 | + array_unshift($child[1]->prefix[2], $prefix); |
|
593 | + } |
|
594 | + $prefixed[] = $child; |
|
595 | + } |
|
596 | + $this->compileChildren($prefixed, $out); |
|
597 | + break; |
|
598 | + case "include": // including a mixin |
|
599 | + list(,$name, $argValues, $content) = $child; |
|
600 | + $mixin = $this->get(self::$namespaces["mixin"] . $name, false); |
|
601 | + if (!$mixin) { |
|
602 | + $this->throwError("Undefined mixin $name"); |
|
603 | + } |
|
604 | + $callingScope = $this->env; |
|
605 | + // push scope, apply args |
|
606 | + $this->pushEnv(); |
|
607 | + if ($this->env->depth > 0) { |
|
608 | + $this->env->depth--; |
|
609 | + } |
|
610 | + if (!is_null($content)) { |
|
611 | + $content->scope = $callingScope; |
|
612 | + $this->setRaw(self::$namespaces["special"] . "content", $content); |
|
613 | + } |
|
614 | + if (!is_null($mixin->args)) { |
|
615 | + $this->applyArguments($mixin->args, $argValues); |
|
616 | + } |
|
617 | + foreach ($mixin->children as $child) { |
|
618 | + $this->compileChild($child, $out); |
|
619 | + } |
|
620 | + $this->popEnv(); |
|
621 | + break; |
|
622 | + case "mixin_content": |
|
623 | + $content = $this->get(self::$namespaces["special"] . "content"); |
|
624 | + if (is_null($content)) { |
|
625 | + $this->throwError("Expected @content inside of mixin"); |
|
626 | + } |
|
627 | + $strongTypes = array('include', 'block', 'for', 'while'); |
|
628 | + foreach ($content->children as $child) { |
|
629 | + $this->storeEnv = (in_array($child[0], $strongTypes)) |
|
630 | + ? null |
|
631 | + : $content->scope; |
|
632 | + $this->compileChild($child, $out); |
|
633 | + } |
|
634 | + unset($this->storeEnv); |
|
635 | + break; |
|
636 | + case "debug": |
|
637 | + list(,$value, $pos) = $child; |
|
638 | + $line = $this->parser->getLineNo($pos); |
|
639 | + $value = $this->compileValue($this->reduce($value, true)); |
|
640 | + fwrite(STDERR, "Line $line DEBUG: $value\n"); |
|
641 | + break; |
|
642 | + default: |
|
643 | + $this->throwError("unknown child type: $child[0]"); |
|
644 | 644 | } |
645 | 645 | } |
646 | 646 | protected function expToString($exp) { |
@@ -658,13 +658,13 @@ discard block |
||
658 | 658 | // should $value cause its operand to eval |
659 | 659 | protected function shouldEval($value) { |
660 | 660 | switch ($value[0]) { |
661 | - case "exp": |
|
662 | - if ($value[1] == "/") { |
|
663 | - return $this->shouldEval($value[2], $value[3]); |
|
664 | - } |
|
665 | - case "var": |
|
666 | - case "fncall": |
|
667 | - return true; |
|
661 | + case "exp": |
|
662 | + if ($value[1] == "/") { |
|
663 | + return $this->shouldEval($value[2], $value[3]); |
|
664 | + } |
|
665 | + case "var": |
|
666 | + case "fncall": |
|
667 | + return true; |
|
668 | 668 | } |
669 | 669 | return false; |
670 | 670 | } |
@@ -749,11 +749,11 @@ discard block |
||
749 | 749 | $exp = $this->reduce($exp); |
750 | 750 | if ($exp[0] == "number") { |
751 | 751 | switch ($op) { |
752 | - case "+": |
|
753 | - return $exp; |
|
754 | - case "-": |
|
755 | - $exp[1] *= -1; |
|
756 | - return $exp; |
|
752 | + case "+": |
|
753 | + return $exp; |
|
754 | + case "-": |
|
755 | + $exp[1] *= -1; |
|
756 | + return $exp; |
|
757 | 757 | } |
758 | 758 | } |
759 | 759 | if ($op == "not") { |
@@ -825,19 +825,19 @@ discard block |
||
825 | 825 | $value = $this->coerceForExpression($this->reduce($value)); |
826 | 826 | list($type) = $value; |
827 | 827 | switch ($type) { |
828 | - case "list": |
|
829 | - $value = $this->extractInterpolation($value); |
|
830 | - if ($value[0] != "list") { |
|
831 | - return array("keyword", $this->compileValue($value)); |
|
832 | - } |
|
833 | - foreach ($value[2] as $key => $item) { |
|
834 | - $value[2][$key] = $this->normalizeValue($item); |
|
835 | - } |
|
836 | - return $value; |
|
837 | - case "number": |
|
838 | - return $this->normalizeNumber($value); |
|
839 | - default: |
|
840 | - return $value; |
|
828 | + case "list": |
|
829 | + $value = $this->extractInterpolation($value); |
|
830 | + if ($value[0] != "list") { |
|
831 | + return array("keyword", $this->compileValue($value)); |
|
832 | + } |
|
833 | + foreach ($value[2] as $key => $item) { |
|
834 | + $value[2][$key] = $this->normalizeValue($item); |
|
835 | + } |
|
836 | + return $value; |
|
837 | + case "number": |
|
838 | + return $this->normalizeNumber($value); |
|
839 | + default: |
|
840 | + return $value; |
|
841 | 841 | } |
842 | 842 | } |
843 | 843 | // just does physical lengths for now |
@@ -905,30 +905,30 @@ discard block |
||
905 | 905 | $lval = isset($left[$i]) ? $left[$i] : 0; |
906 | 906 | $rval = isset($right[$i]) ? $right[$i] : 0; |
907 | 907 | switch ($op) { |
908 | - case '+': |
|
909 | - $out[] = $lval + $rval; |
|
910 | - break; |
|
911 | - case '-': |
|
912 | - $out[] = $lval - $rval; |
|
913 | - break; |
|
914 | - case '*': |
|
915 | - $out[] = $lval * $rval; |
|
916 | - break; |
|
917 | - case '%': |
|
918 | - $out[] = $lval % $rval; |
|
919 | - break; |
|
920 | - case '/': |
|
921 | - if ($rval == 0) { |
|
922 | - $this->throwError("color: Can't divide by zero"); |
|
923 | - } |
|
924 | - $out[] = $lval / $rval; |
|
925 | - break; |
|
926 | - case "==": |
|
927 | - return $this->op_eq($left, $right); |
|
928 | - case "!=": |
|
929 | - return $this->op_neq($left, $right); |
|
930 | - default: |
|
931 | - $this->throwError("color: unknown op $op"); |
|
908 | + case '+': |
|
909 | + $out[] = $lval + $rval; |
|
910 | + break; |
|
911 | + case '-': |
|
912 | + $out[] = $lval - $rval; |
|
913 | + break; |
|
914 | + case '*': |
|
915 | + $out[] = $lval * $rval; |
|
916 | + break; |
|
917 | + case '%': |
|
918 | + $out[] = $lval % $rval; |
|
919 | + break; |
|
920 | + case '/': |
|
921 | + if ($rval == 0) { |
|
922 | + $this->throwError("color: Can't divide by zero"); |
|
923 | + } |
|
924 | + $out[] = $lval / $rval; |
|
925 | + break; |
|
926 | + case "==": |
|
927 | + return $this->op_eq($left, $right); |
|
928 | + case "!=": |
|
929 | + return $this->op_neq($left, $right); |
|
930 | + default: |
|
931 | + $this->throwError("color: unknown op $op"); |
|
932 | 932 | } |
933 | 933 | } |
934 | 934 | if (isset($left[4])) $out[4] = $left[4]; |
@@ -988,68 +988,68 @@ discard block |
||
988 | 988 | $value = $this->reduce($value); |
989 | 989 | list($type) = $value; |
990 | 990 | switch ($type) { |
991 | - case "keyword": |
|
992 | - return $value[1]; |
|
993 | - case "color": |
|
994 | - // [1] - red component (either number for a %) |
|
995 | - // [2] - green component |
|
996 | - // [3] - blue component |
|
997 | - // [4] - optional alpha component |
|
998 | - list(, $r, $g, $b) = $value; |
|
999 | - $r = round($r); |
|
1000 | - $g = round($g); |
|
1001 | - $b = round($b); |
|
1002 | - if (count($value) == 5 && $value[4] != 1) { // rgba |
|
1003 | - return 'rgba('.$r.', '.$g.', '.$b.', '.$value[4].')'; |
|
1004 | - } |
|
1005 | - $h = sprintf("#%02x%02x%02x", $r, $g, $b); |
|
1006 | - // Converting hex color to short notation (e.g. #003399 to #039) |
|
1007 | - if ($h[1] === $h[2] && $h[3] === $h[4] && $h[5] === $h[6]) { |
|
1008 | - $h = '#' . $h[1] . $h[3] . $h[5]; |
|
1009 | - } |
|
1010 | - return $h; |
|
1011 | - case "number": |
|
1012 | - return round($value[1], $this->numberPrecision) . $value[2]; |
|
1013 | - case "string": |
|
1014 | - return $value[1] . $this->compileStringContent($value) . $value[1]; |
|
1015 | - case "function": |
|
1016 | - $args = !empty($value[2]) ? $this->compileValue($value[2]) : ""; |
|
1017 | - return "$value[1]($args)"; |
|
1018 | - case "list": |
|
1019 | - $value = $this->extractInterpolation($value); |
|
1020 | - if ($value[0] != "list") return $this->compileValue($value); |
|
1021 | - list(, $delim, $items) = $value; |
|
1022 | - $filtered = array(); |
|
1023 | - foreach ($items as $item) { |
|
1024 | - if ($item[0] == "null") continue; |
|
1025 | - $filtered[] = $this->compileValue($item); |
|
1026 | - } |
|
1027 | - return implode("$delim ", $filtered); |
|
1028 | - case "interpolated": # node created by extractInterpolation |
|
1029 | - list(, $interpolate, $left, $right) = $value; |
|
1030 | - list(,, $whiteLeft, $whiteRight) = $interpolate; |
|
1031 | - $left = count($left[2]) > 0 ? |
|
1032 | - $this->compileValue($left).$whiteLeft : ""; |
|
1033 | - $right = count($right[2]) > 0 ? |
|
1034 | - $whiteRight.$this->compileValue($right) : ""; |
|
1035 | - return $left.$this->compileValue($interpolate).$right; |
|
1036 | - case "interpolate": # raw parse node |
|
1037 | - list(, $exp) = $value; |
|
1038 | - // strip quotes if it's a string |
|
1039 | - $reduced = $this->reduce($exp); |
|
1040 | - switch ($reduced[0]) { |
|
991 | + case "keyword": |
|
992 | + return $value[1]; |
|
993 | + case "color": |
|
994 | + // [1] - red component (either number for a %) |
|
995 | + // [2] - green component |
|
996 | + // [3] - blue component |
|
997 | + // [4] - optional alpha component |
|
998 | + list(, $r, $g, $b) = $value; |
|
999 | + $r = round($r); |
|
1000 | + $g = round($g); |
|
1001 | + $b = round($b); |
|
1002 | + if (count($value) == 5 && $value[4] != 1) { // rgba |
|
1003 | + return 'rgba('.$r.', '.$g.', '.$b.', '.$value[4].')'; |
|
1004 | + } |
|
1005 | + $h = sprintf("#%02x%02x%02x", $r, $g, $b); |
|
1006 | + // Converting hex color to short notation (e.g. #003399 to #039) |
|
1007 | + if ($h[1] === $h[2] && $h[3] === $h[4] && $h[5] === $h[6]) { |
|
1008 | + $h = '#' . $h[1] . $h[3] . $h[5]; |
|
1009 | + } |
|
1010 | + return $h; |
|
1011 | + case "number": |
|
1012 | + return round($value[1], $this->numberPrecision) . $value[2]; |
|
1013 | + case "string": |
|
1014 | + return $value[1] . $this->compileStringContent($value) . $value[1]; |
|
1015 | + case "function": |
|
1016 | + $args = !empty($value[2]) ? $this->compileValue($value[2]) : ""; |
|
1017 | + return "$value[1]($args)"; |
|
1018 | + case "list": |
|
1019 | + $value = $this->extractInterpolation($value); |
|
1020 | + if ($value[0] != "list") return $this->compileValue($value); |
|
1021 | + list(, $delim, $items) = $value; |
|
1022 | + $filtered = array(); |
|
1023 | + foreach ($items as $item) { |
|
1024 | + if ($item[0] == "null") continue; |
|
1025 | + $filtered[] = $this->compileValue($item); |
|
1026 | + } |
|
1027 | + return implode("$delim ", $filtered); |
|
1028 | + case "interpolated": # node created by extractInterpolation |
|
1029 | + list(, $interpolate, $left, $right) = $value; |
|
1030 | + list(,, $whiteLeft, $whiteRight) = $interpolate; |
|
1031 | + $left = count($left[2]) > 0 ? |
|
1032 | + $this->compileValue($left).$whiteLeft : ""; |
|
1033 | + $right = count($right[2]) > 0 ? |
|
1034 | + $whiteRight.$this->compileValue($right) : ""; |
|
1035 | + return $left.$this->compileValue($interpolate).$right; |
|
1036 | + case "interpolate": # raw parse node |
|
1037 | + list(, $exp) = $value; |
|
1038 | + // strip quotes if it's a string |
|
1039 | + $reduced = $this->reduce($exp); |
|
1040 | + switch ($reduced[0]) { |
|
1041 | 1041 | case "string": |
1042 | 1042 | $reduced = array("keyword", |
1043 | 1043 | $this->compileStringContent($reduced)); |
1044 | 1044 | break; |
1045 | 1045 | case "null": |
1046 | 1046 | $reduced = array("keyword", ""); |
1047 | - } |
|
1047 | + } |
|
1048 | 1048 | return $this->compileValue($reduced); |
1049 | - case "null": |
|
1050 | - return "null"; |
|
1051 | - default: |
|
1052 | - $this->throwError("unknown value type: $type"); |
|
1049 | + case "null": |
|
1050 | + return "null"; |
|
1051 | + default: |
|
1052 | + $this->throwError("unknown value type: $type"); |
|
1053 | 1053 | } |
1054 | 1054 | } |
1055 | 1055 | protected function compileStringContent($string) { |
@@ -1419,25 +1419,25 @@ discard block |
||
1419 | 1419 | } |
1420 | 1420 | protected function coerceColor($value) { |
1421 | 1421 | switch ($value[0]) { |
1422 | - case "color": return $value; |
|
1423 | - case "keyword": |
|
1424 | - $name = $value[1]; |
|
1425 | - if (isset(self::$cssColors[$name])) { |
|
1426 | - @list($r, $g, $b, $a) = explode(',', self::$cssColors[$name]); |
|
1427 | - return isset($a) |
|
1428 | - ? array('color', (int) $r, (int) $g, (int) $b, (int) $a) |
|
1429 | - : array('color', (int) $r, (int) $g, (int) $b); |
|
1430 | - } |
|
1431 | - return null; |
|
1422 | + case "color": return $value; |
|
1423 | + case "keyword": |
|
1424 | + $name = $value[1]; |
|
1425 | + if (isset(self::$cssColors[$name])) { |
|
1426 | + @list($r, $g, $b, $a) = explode(',', self::$cssColors[$name]); |
|
1427 | + return isset($a) |
|
1428 | + ? array('color', (int) $r, (int) $g, (int) $b, (int) $a) |
|
1429 | + : array('color', (int) $r, (int) $g, (int) $b); |
|
1430 | + } |
|
1431 | + return null; |
|
1432 | 1432 | } |
1433 | 1433 | return null; |
1434 | 1434 | } |
1435 | 1435 | protected function coerceString($value) { |
1436 | 1436 | switch ($value[0]) { |
1437 | - case "string": |
|
1438 | - return $value; |
|
1439 | - case "keyword": |
|
1440 | - return array("string", "", array($value[1])); |
|
1437 | + case "string": |
|
1438 | + return $value; |
|
1439 | + case "keyword": |
|
1440 | + return array("string", "", array($value[1])); |
|
1441 | 1441 | } |
1442 | 1442 | return null; |
1443 | 1443 | } |
@@ -1615,16 +1615,16 @@ discard block |
||
1615 | 1615 | // 4, 5, 6 - hsl |
1616 | 1616 | // 7 - a |
1617 | 1617 | switch ($i) { |
1618 | - case 1: |
|
1619 | - case 2: |
|
1620 | - case 3: |
|
1621 | - $max = 255; break; |
|
1622 | - case 4: |
|
1623 | - $max = 360; break; |
|
1624 | - case 7: |
|
1625 | - $max = 1; break; |
|
1626 | - default: |
|
1627 | - $max = 100; |
|
1618 | + case 1: |
|
1619 | + case 2: |
|
1620 | + case 3: |
|
1621 | + $max = 255; break; |
|
1622 | + case 4: |
|
1623 | + $max = 360; break; |
|
1624 | + case 7: |
|
1625 | + $max = 1; break; |
|
1626 | + default: |
|
1627 | + $max = 100; |
|
1628 | 1628 | } |
1629 | 1629 | $scale = $scale / 100; |
1630 | 1630 | if ($scale < 0) { |
@@ -1910,12 +1910,12 @@ discard block |
||
1910 | 1910 | protected function listSeparatorForJoin($list1, $sep) { |
1911 | 1911 | if (is_null($sep)) return $list1[1]; |
1912 | 1912 | switch ($this->compileValue($sep)) { |
1913 | - case "comma": |
|
1914 | - return ","; |
|
1915 | - case "space": |
|
1916 | - return ""; |
|
1917 | - default: |
|
1918 | - return $list1[1]; |
|
1913 | + case "comma": |
|
1914 | + return ","; |
|
1915 | + case "space": |
|
1916 | + return ""; |
|
1917 | + default: |
|
1918 | + return $list1[1]; |
|
1919 | 1919 | } |
1920 | 1920 | } |
1921 | 1921 | protected static $lib_join = array("list1", "list2", "separator"); |
@@ -1956,16 +1956,16 @@ discard block |
||
1956 | 1956 | protected function lib_type_of($args) { |
1957 | 1957 | $value = $args[0]; |
1958 | 1958 | switch ($value[0]) { |
1959 | - case "keyword": |
|
1960 | - if ($value == self::$true || $value == self::$false) { |
|
1961 | - return "bool"; |
|
1962 | - } |
|
1963 | - if ($this->coerceColor($value)) { |
|
1964 | - return "color"; |
|
1965 | - } |
|
1966 | - return "string"; |
|
1967 | - default: |
|
1968 | - return $value[0]; |
|
1959 | + case "keyword": |
|
1960 | + if ($value == self::$true || $value == self::$false) { |
|
1961 | + return "bool"; |
|
1962 | + } |
|
1963 | + if ($this->coerceColor($value)) { |
|
1964 | + return "color"; |
|
1965 | + } |
|
1966 | + return "string"; |
|
1967 | + default: |
|
1968 | + return $value[0]; |
|
1969 | 1969 | } |
1970 | 1970 | } |
1971 | 1971 | protected static $lib_unit = array("number"); |