diff --git a/src/Aspect/Template.php b/src/Aspect/Template.php
index baaf156..c455967 100644
--- a/src/Aspect/Template.php
+++ b/src/Aspect/Template.php
@@ -137,12 +137,12 @@ class Template extends Render {
// $frag = ltrim($frag);
//}
- $this->_body .= str_replace("", '', $frag);
+ $frag = str_replace("", ''."\n", $frag);
- $this->_body .= $this->_tag($tag, $this->_trim); // dispatching tags
+ $this->_body .= $this->_tag($tag, $frag); // dispatching tags
// duplicate new line http://docs.php.net/manual/en/language.basic-syntax.instruction-separation.php
- /*if(isset($this->_src[ $end+1 ])) {
+ if(substr($this->_body, -2) === "?>" && isset($this->_src[ $end+1 ])) {
$c = $this->_src[ $end+1 ];
if($c === "\n") {
$this->_body .= "\n";
@@ -153,7 +153,7 @@ class Template extends Render {
$this->_body .= "\r";
}
}
- }*/
+ }
//if($this->_trim) { // if current tag has trim flag
// $frag = rtrim($frag);
//}
@@ -262,20 +262,21 @@ class Template extends Render {
/**
* Internal tags router
* @param string $src
- * @param bool $trim
+ * @param string $frag
* @throws UnexpectedException
* @throws CompileException
* @throws SecurityException
* @return string
*/
- private function _tag($src, &$trim = false) {
+ private function _tag($src, &$frag) {
if($src[strlen($src) - 2] === "-") {
$token = substr($src, 1, -2);
- $trim = true;
+ //$frag = ltrim($frag);
} else {
$token = substr($src, 1, -1);
- $trim = false;
}
+
+ $this->_body .= $frag;
$token = trim($token);
if($this->_ignore) {
if($token === '/ignore') {
@@ -298,10 +299,14 @@ class Template extends Render {
$code = $this->_end($tokens);
break;
default:
- $code = $this->_parseAct($tokens);
- break;
+ if($tokens->current() === "ignore") {
+ $this->_ignore = true;
+ $tokens->next();
+ $code = '';
+ } else {
+ $code = $this->_parseAct($tokens);
+ }
}
-
if($tokens->key()) { // if tokenizer still have tokens
throw new UnexpectedException($tokens);
}
@@ -344,6 +349,7 @@ class Template extends Render {
*
* @static
* @param Tokenizer $tokens
+ * @throws \LogicException
* @throws TokenizeException
* @return string
*/
@@ -355,11 +361,6 @@ class Template extends Render {
return 'echo '.$this->parseExp($tokens).';';
}
- if($action === "ignore") {
- $this->_ignore = true;
- $tokens->next();
- return '';
- }
if($tokens->isNext("(")) {
return "echo ".$this->parseExp($tokens).";";
}
@@ -368,7 +369,7 @@ class Template extends Render {
$tokens->next();
switch($act["type"]) {
case Aspect::BLOCK_COMPILER:
- $scope = new Scope($action, $this, $this->_line, $act);
+ $scope = new Scope($action, $this, $this->_line, $act, count($this->_stack));
array_push($this->_stack, $scope);
return $scope->open($tokens);
case Aspect::INLINE_COMPILER:
@@ -376,10 +377,12 @@ class Template extends Render {
case Aspect::INLINE_FUNCTION:
return call_user_func($act["parser"], $act["function"], $tokens, $this);
case Aspect::BLOCK_FUNCTION:
- $scope = new Scope($action, $this, $this->_line, $act);
+ $scope = new Scope($action, $this, $this->_line, $act, count($this->_stack));
$scope->setFuncName($act["function"]);
array_push($this->_stack, $scope);
return $scope->open($tokens);
+ default:
+ throw new \LogicException("Unknown function type");
}
}
@@ -520,6 +523,7 @@ class Template extends Render {
* @param int $deny
* @param bool $pure_var
* @throws \LogicException
+ * @throws UnexpectedException
* @return string
*/
public function parseVar(Tokenizer $tokens, $deny = 0, &$pure_var = true) {
@@ -707,6 +711,10 @@ class Template extends Render {
}
}
+ /**
+ * @param string $after
+ * @return bool|string
+ */
private function _getMoreSubstr($after) {
$end = strpos($this->_src, $after, $this->_pos);
$end = strpos($this->_src, "}", $end);
@@ -874,13 +882,25 @@ class Template extends Render {
throw new TokenizeException("Unexpected token '".$tokens->current()."' in argument list");
}
+ /**
+ * Parse first unnamed argument
+ *
+ * @param Tokenizer $tokens
+ * @param string $static
+ * @return mixed|string
+ */
public function parseFirstArg(Tokenizer $tokens, &$static) {
if($tokens->is(T_CONSTANT_ENCAPSED_STRING)) {
- $str = $tokens->getAndNext();
- $static = stripslashes(substr($str, 1, -1));
- return $str;
+ if($tokens->isNext('|')) {
+ return $this->parseExp($tokens, true);
+ } else {
+ $str = $tokens->getAndNext();
+ $static = stripslashes(substr($str, 1, -1));
+ return $str;
+ }
} elseif($tokens->is(Tokenizer::MACRO_STRING)) {
- return $static = $tokens->getAndNext();
+ $static = $tokens->getAndNext();
+ return '"'.addslashes($static).'"';
} else {
return $this->parseExp($tokens, true);
}
@@ -925,8 +945,6 @@ class Template extends Render {
}
}
-
-
class CompileException extends \ErrorException {}
class SecurityException extends CompileException {}
class ImproperUseException extends \LogicException {}
\ No newline at end of file
diff --git a/src/Aspect/Tokenizer.php b/src/Aspect/Tokenizer.php
index da0f335..84c0620 100644
--- a/src/Aspect/Tokenizer.php
+++ b/src/Aspect/Tokenizer.php
@@ -48,7 +48,7 @@ class Tokenizer {
*/
const MACRO_INCDEC = 1005;
/**
- * Boolean operations: &&, ||, or, xor
+ * Boolean operations: &&, ||, or, xor, and
*/
const MACRO_BOOLEAN = 1006;
/**
@@ -98,7 +98,7 @@ class Tokenizer {
"+" => 1, "-" => 1, "*" => 1, "/" => 1, ">" => 1, "<" => 1, "^" => 1, "%" => 1, "&" => 1
),
self::MACRO_BOOLEAN => array(
- \T_LOGICAL_OR => 1, \T_LOGICAL_XOR => 1, \T_BOOLEAN_AND => 1, \T_BOOLEAN_OR => 1
+ \T_LOGICAL_OR => 1, \T_LOGICAL_XOR => 1, \T_BOOLEAN_AND => 1, \T_BOOLEAN_OR => 1, \T_LOGICAL_AND => 1
),
self::MACRO_MATH => array(
"+" => 1, "-" => 1, "*" => 1, "/" => 1, "^" => 1, "%" => 1, "&" => 1, "|" => 1
@@ -171,22 +171,6 @@ class Tokenizer {
$this->_last_no = $this->tokens[$this->_max][3];
}
- /**
- * Set the filter callback. Token may be changed by reference or skipped if callback return false.
- *
- * @param $callback
- */
- public function filter(\Closure $callback) {
- $tokens = array();
- foreach($this->tokens as $token) {
- if($callback($token) !== false) {
- $tokens[] = $token;
- }
- }
- $this->tokens = $tokens;
- $this->_max = count($this->tokens) - 1;
- }
-
/**
* Return the current element
*
@@ -270,20 +254,6 @@ class Tokenizer {
return $this->current();
}
- /**
- * Concatenate tokens from the current one to one of the specified and returns the string.
- * @param string|int $token
- * @param ...
- * @return string
- */
- public function getStringUntil($token/*, $token2 */) {
- $str = '';
- while($this->valid() && !$this->_valid(func_get_args(), $this->curr[0])) {
- $str .= $this->curr[1].$this->curr[2];
- $this->next();
- }
- return $str;
- }
/**
* Return substring. This method doesn't move pointer.
@@ -313,11 +283,10 @@ class Tokenizer {
if($this->curr) {
$cur = $this->curr[1];
$this->next();
+ return $cur;
} else {
throw new UnexpectedException($this, func_get_args());
}
-
- return $cur;
}
/**
@@ -396,7 +365,6 @@ class Tokenizer {
/**
* Return the key of the current element
- * @link http://php.net/manual/en/iterator.key.php
* @return mixed scalar on success, or null on failure.
*/
public function key() {
@@ -405,7 +373,6 @@ class Tokenizer {
/**
* Checks if current position is valid
- * @link http://php.net/manual/en/iterator.valid.php
* @return boolean The return value will be casted to boolean and then evaluated.
* Returns true on success or false on failure.
*/
@@ -413,13 +380,6 @@ class Tokenizer {
return (bool)$this->curr;
}
- /**
- * Rewind the Iterator to the first element. Disabled.
- * @link http://php.net/manual/en/iterator.rewind.php
- * @return void Any returned value is ignored.
- */
- public function rewind() {}
-
/**
* Get token name
* @static
@@ -438,18 +398,6 @@ class Tokenizer {
}
}
- /**
- * Return whitespace of current token
- * @return null
- */
- public function getWhiteSpace() {
- if($this->curr) {
- return $this->curr[2];
- } else {
- return null;
- }
- }
-
/**
* Skip specific token or throw an exception
*
@@ -470,19 +418,6 @@ class Tokenizer {
}
}
- /**
- * Skip specific token or do nothing
- *
- * @param int|string $token1
- * @return Tokenizer
- */
- public function skipIf($token1/*, $token2, ...*/) {
- if($this->_valid(func_get_args(), $this->curr[0])) {
- $this->next();
- }
- return $this;
- }
-
/**
* Check current token's type
*
@@ -498,16 +433,6 @@ class Tokenizer {
}
}
- /**
- * Count elements of an object
- * @link http://php.net/manual/en/countable.count.php
- * @return int The custom count as an integer.
- * The return value is cast to an integer.
- */
- public function count() {
- return $this->_max;
- }
-
/**
* Get tokens near current token
* @param int $before count tokens before current token
@@ -636,8 +561,6 @@ class UnexpectedException extends TokenizeException {
}
if(!$tokens->curr) {
$this->message = "Unexpected end of ".($where?:"expression")."$expect";
- } elseif($tokens->curr[1] === "\n") {
- $this->message = "Unexpected new line$expect";
} elseif($tokens->curr[0] === T_WHITESPACE) {
$this->message = "Unexpected whitespace$expect";
} else {
diff --git a/tests/TestCase.php b/tests/TestCase.php
index 3895cff..e496cb8 100644
--- a/tests/TestCase.php
+++ b/tests/TestCase.php
@@ -17,6 +17,18 @@ class TestCase extends \PHPUnit_Framework_TestCase {
$this->aspect = Aspect::factory(ASPECT_RESOURCES.'/template', ASPECT_RESOURCES.'/compile');
}
+ public static function setUpBeforeClass() {
+ if(!file_exists(ASPECT_RESOURCES.'/template')) {
+ mkdir(ASPECT_RESOURCES.'/template', 0777, true);
+ } else {
+ Misc::clean(ASPECT_RESOURCES.'/template/');
+ }
+ }
+
+ public function tpl($name, $code) {
+ file_put_contents(ASPECT_RESOURCES.'/template/'.$name, $code);
+ }
+
/**
* Compile and execute template
*
@@ -33,6 +45,15 @@ class TestCase extends \PHPUnit_Framework_TestCase {
$this->assertSame(Modifier::strip($result), Modifier::strip($tpl->fetch($vars), true), "Test $code");
}
+ public function execTpl($name, $code, $vars, $result, $dump = false) {
+ $this->tpl($name, $code);
+ $tpl = $this->aspect->getTemplate($name);
+ if($dump) {
+ echo "\n========= DUMP BEGIN ===========\n".$code."\n--- to ---\n".$tpl->getBody()."\n========= DUMP END =============\n";
+ }
+ $this->assertSame(Modifier::strip($result, true), Modifier::strip($tpl->fetch($vars), true), "Test tpl $name");
+ }
+
/**
* Try to compile the invalid template
* @param string $code source of the template
diff --git a/tests/cases/Aspect/TemplateTest.php b/tests/cases/Aspect/TemplateTest.php
index 3a97f65..2d9d43e 100644
--- a/tests/cases/Aspect/TemplateTest.php
+++ b/tests/cases/Aspect/TemplateTest.php
@@ -165,16 +165,16 @@ class TemplateTest extends TestCase {
array('Exp: {!$x} result', $b, 'Exp: result'),
array('Exp: {!5} result', $b, 'Exp: result'),
array('Exp: {-1} result', $b, 'Exp: -1 result'),
- array('Exp: {$z = 5} {$z} result', $b, 'Exp: 5 5 result'),
- array('Exp: {$k.i = "str"} {$k.i} result', $b, 'Exp: str str result'),
+ array('Exp: {$z = 5} {$z} result', $b, 'Exp: 5 5 result'),
+ array('Exp: {$k.i = "str"} {$k.i} result', $b, 'Exp: str str result'),
array('Exp: {($y*$x - (($x+$y) + $y/$x) ^ $y)/4} result',
- $b, 'Exp: 53.75 result'),
- array('Exp: {$x+max($x, $y)} result', $b, 'Exp: 36 result'),
+ $b, 'Exp: 53.75 result'),
+ array('Exp: {$x+max($x, $y)} result', $b, 'Exp: 36 result'),
array('Exp: {max(1,2)} result', $b, 'Exp: 2 result'),
- array('Exp: {round(sin(pi()), 8)} result', $b, 'Exp: 0 result'),
+ array('Exp: {round(sin(pi()), 8)} result', $b, 'Exp: 0 result'),
array('Exp: {max($x, $y) + round(sin(pi()), 8) - min($x, $y) +3} result',
- $b, 'Exp: 21 result'),
+ $b, 'Exp: 21 result'),
);
}
@@ -207,25 +207,26 @@ class TemplateTest extends TestCase {
$result3 = 'Include Welcome, Master (flame@dev.null) template';
$result4 = 'Include Welcome, Flame (flame@dev.null) template';
return array(
- array('Include {include file="welcome.tpl"} template', $a, $result),
- array('Include {include file=$tpl} template', $a, $result),
- array('Include {include file="$tpl"} template', $a, $result),
- array('Include {include file="{$tpl}"} template', $a, $result),
- array('Include {include file="$name.tpl"} template', $a, $result),
- array('Include {include file="{$name}.tpl"} template', $a, $result),
- array('Include {include file="{$pr_name|lower}.tpl"} template', $a, $result),
- array('Include {include file="wel{$fragment}.tpl"} template', $a, $result),
- array('Include {include file="wel{$pr_fragment|lower}.tpl"} template', $a, $result),
- array('Include {include file="welcome.tpl" username="Flame"} template', $a, $result2),
- array('Include {include file="welcome.tpl" email="flame@dev.null"} template', $a, $result3),
- array('Include {include file="welcome.tpl" username="Flame" email="flame@dev.null"} template',
+ array('Include {include "welcome.tpl"} template', $a, $result),
+ array('Include {include $tpl} template', $a, $result),
+ array('Include {include "$tpl"} template', $a, $result),
+ array('Include {include "{$tpl}"} template', $a, $result),
+ array('Include {include "$name.tpl"} template', $a, $result),
+ array('Include {include "{$name}.tpl"} template', $a, $result),
+ array('Include {include "{$pr_name|lower}.tpl"} template', $a, $result),
+ array('Include {include "wel{$fragment}.tpl"} template', $a, $result),
+ array('Include {include "wel{$pr_fragment|lower}.tpl"} template', $a, $result),
+ array('Include {include "welcome.tpl" username="Flame"} template', $a, $result2),
+ array('Include {include "welcome.tpl" email="flame@dev.null"} template', $a, $result3),
+ array('Include {include "welcome.tpl" username="Flame" email="flame@dev.null"} template',
$a, $result4),
);
}
public static function providerIncludeInvalid() {
return array(
- array('Include {include} template', 'Aspect\CompileException', "The tag {include} requires 'file' parameter"),
+ array('Include {include} template', 'Aspect\CompileException', "Unexpected end of expression"),
+ array('Include {include another="welcome.tpl"} template', 'Aspect\CompileException', "Unexpected token '=' in expression"),
);
}
@@ -721,26 +722,5 @@ class TemplateTest extends TestCase {
public function testLayersInvalid($code, $exception, $message, $options = 0) {
$this->execError($code, $exception, $message, $options);
}
-
- /**
- * @group extends
- */
- public function _testExtends() {
- echo(self::$aspect->getTemplate("parent.tpl")->getBody()); exit;
- }
-
- /**
- * @group extends
- */
- public function ___testExtends() {
- echo(self::$aspect->getTemplate("child1.tpl")->getBody()); exit;
- }
-
- /**
- * @group extends
- */
- public function __testExtends() {
- echo(self::$aspect->fetch("child1.tpl", array("a" => "value", "z" => ""))."\n"); exit;
- }
}
diff --git a/tests/cases/Aspect/TokenizerTest.php b/tests/cases/Aspect/TokenizerTest.php
index 9f2e3e8..aa0473d 100644
--- a/tests/cases/Aspect/TokenizerTest.php
+++ b/tests/cases/Aspect/TokenizerTest.php
@@ -60,7 +60,6 @@ class TokenizerTest extends \PHPUnit_Framework_TestCase {
$this->assertTrue($tokens->valid());
$this->assertSame("3", $tokens->current());
$this->assertSame(T_LNUMBER, $tokens->key());
- $this->assertSame(" ", $tokens->getWhiteSpace());
$tokens->next();
}
}