diff --git a/src/Aspect/Compiler.php b/src/Aspect/Compiler.php index d4f0439..5bbefc0 100644 --- a/src/Aspect/Compiler.php +++ b/src/Aspect/Compiler.php @@ -89,7 +89,7 @@ class Compiler { * @static * @param Tokenizer $tokens * @param Scope $scope - * @throws UnexpectedException + * @throws UnexpectedTokenException * @throws ImproperUseException * @return string */ @@ -106,7 +106,7 @@ class Compiler { $prepend = $uid.' = '.$from.';'; $from = $uid; } else { - throw new UnexpectedException($tokens, null, "tag {foreach}"); + throw new UnexpectedTokenException($tokens, null, "tag {foreach}"); } $tokens->get(T_AS); $tokens->next(); @@ -704,8 +704,9 @@ class Compiler { * * @param Tokenizer $tokens * @param Template $tpl - * @return string + * @throws UnexpectedTokenException * @throws ImproperUseException + * @return string */ public static function tagImport(Tokenizer $tokens, Template $tpl) { $import = array(); @@ -718,10 +719,14 @@ class Compiler { } elseif($tokens->is(']')) { $tokens->next(); break; + } elseif($tokens->is(',')) { + $tokens->next(); + } else { + break; } } if($tokens->current() != "from") { - throw new UnexpectedException($tokens); + throw new UnexpectedTokenException($tokens); } $tokens->next(); } @@ -745,9 +750,13 @@ class Compiler { if($p = strpos($name, ".")) { $name = substr($name, $p); } + if($import && !isset($import[$name])) { + continue; + } if($alias) { $name = $alias.'.'.$name; } + $tpl->macros[$name] = $macro; } $tpl->addDepend($donor); diff --git a/src/Aspect/Template.php b/src/Aspect/Template.php index 0aeca0d..b49f226 100644 --- a/src/Aspect/Template.php +++ b/src/Aspect/Template.php @@ -330,7 +330,7 @@ class Template extends Render { /** * Internal tags router * @param Tokenizer $tokens - * @throws UnexpectedException + * @throws UnexpectedTokenException * @throws CompileException * @throws SecurityException * @return string executable PHP code @@ -449,7 +449,7 @@ class Template extends Render { * @param Tokenizer $tokens * @param bool $required * @throws \LogicException - * @throws UnexpectedException + * @throws UnexpectedTokenException * @throws TokenizeException * @return string */ @@ -511,7 +511,7 @@ class Template extends Render { $term = 0; } elseif($tokens->is(Tokenizer::MACRO_BINARY)) { if(!$term) { - throw new UnexpectedException($tokens); + throw new UnexpectedTokenException($tokens); } if($tokens->isLast()) { break; @@ -546,13 +546,13 @@ class Template extends Render { } if($term === 0) { - throw new UnexpectedException($tokens); + throw new UnexpectedTokenException($tokens); } if($brackets) { throw new TokenizeException("Brackets don't match"); } if($required && $_exp === "") { - throw new UnexpectedException($tokens); + throw new UnexpectedTokenException($tokens); } return $_exp; } @@ -568,7 +568,7 @@ class Template extends Render { * @param int $deny * @param bool $pure_var * @throws \LogicException - * @throws UnexpectedException + * @throws UnexpectedTokenException * @return string */ public function parseVar(Tokenizer $tokens, $deny = 0, &$pure_var = true) { @@ -647,7 +647,7 @@ class Template extends Render { } else { $expr1 = $this->parseExp($tokens, true); if(!$tokens->is(":")) { - throw new UnexpectedException($tokens, null, "ternary operator"); + throw new UnexpectedTokenException($tokens, null, "ternary operator"); } $expr2 = $this->parseExp($tokens, true); if($empty) { @@ -702,7 +702,7 @@ class Template extends Render { * Parse string with or without variable * * @param Tokenizer $tokens - * @throws UnexpectedException + * @throws UnexpectedTokenException * @return string */ public function parseSubstr(Tokenizer $tokens) { @@ -767,7 +767,7 @@ class Template extends Render { $tokens->append("}".$more, $p); goto ref; } - throw new UnexpectedException($tokens); + throw new UnexpectedTokenException($tokens); } elseif($tokens->is(T_CONSTANT_ENCAPSED_STRING)) { return $tokens->getAndNext(); } elseif($tokens->is(T_ENCAPSED_AND_WHITESPACE)) { @@ -776,7 +776,7 @@ class Template extends Render { $tokens->append("}".$more, $p); goto ref; } - throw new UnexpectedException($tokens); + throw new UnexpectedTokenException($tokens); } else { return ""; } @@ -850,7 +850,7 @@ class Template extends Render { * [1, 2.3, 5+7/$var, 'string', "str {$var+3} ing", $var2, []] * * @param Tokenizer $tokens - * @throws UnexpectedException + * @throws UnexpectedTokenException * @return string */ public function parseArray(Tokenizer $tokens) { @@ -887,7 +887,7 @@ class Template extends Render { } } } - throw new UnexpectedException($tokens); + throw new UnexpectedTokenException($tokens); } /** @@ -942,7 +942,6 @@ class Template extends Render { $args = $args ? '$tpl = '.Compiler::toArray($args).';' : ''; return '$_tpl = $tpl; '.$args.' ?>'.$macro["body"].'macros); throw new ImproperUseException("Undefined macro '$name'"); } } diff --git a/src/Aspect/Tokenizer.php b/src/Aspect/Tokenizer.php index 46c1857..e21ca81 100644 --- a/src/Aspect/Tokenizer.php +++ b/src/Aspect/Tokenizer.php @@ -288,7 +288,7 @@ class Tokenizer { /** * Return token and move pointer * @return mixed - * @throws UnexpectedException + * @throws UnexpectedTokenException */ public function getAndNext() { if($this->curr) { @@ -296,7 +296,7 @@ class Tokenizer { $this->next(); return $cur; } else { - throw new UnexpectedException($this, func_get_args()); + throw new UnexpectedTokenException($this, func_get_args()); } } @@ -331,14 +331,14 @@ class Tokenizer { * Get specified token * * @param string|int $token1 - * @throws UnexpectedException + * @throws UnexpectedTokenException * @return mixed */ public function get($token1 /*, $token2 ...*/) { if($this->curr && $this->_valid(func_get_args(), $this->curr[0])) { return $this->curr[1]; } else { - throw new UnexpectedException($this, func_get_args()); + throw new UnexpectedTokenException($this, func_get_args()); } } @@ -416,7 +416,7 @@ class Tokenizer { /** * Skip specific token or throw an exception * - * @throws UnexpectedException + * @throws UnexpectedTokenException * @return Tokenizer */ public function skip(/*$token1, $token2, ...*/) { @@ -425,7 +425,7 @@ class Tokenizer { $this->next(); return $this; } else { - throw new UnexpectedException($this, func_get_args()); + throw new UnexpectedTokenException($this, func_get_args()); } } else { $this->next(); @@ -451,13 +451,13 @@ class Tokenizer { * * @param int|string $token1 * @return Tokenizer - * @throws UnexpectedException + * @throws UnexpectedTokenException */ public function need($token1/*, $token2, ...*/) { if($this->_valid(func_get_args(), $this->curr[0])) { return $this; } else { - throw new UnexpectedException($this, func_get_args()); + throw new UnexpectedTokenException($this, func_get_args()); } } @@ -581,7 +581,7 @@ class TokenizeException extends \RuntimeException {} /** * Unexpected token */ -class UnexpectedException extends TokenizeException { +class UnexpectedTokenException extends TokenizeException { public function __construct(Tokenizer $tokens, $expect = null, $where = null) { if($expect && count($expect) == 1 && is_string($expect[0])) { $expect = ", expect '".$expect[0]."'"; diff --git a/tests/cases/Aspect/MacrosTest.php b/tests/cases/Aspect/MacrosTest.php index 527000b..a1b93f9 100644 --- a/tests/cases/Aspect/MacrosTest.php +++ b/tests/cases/Aspect/MacrosTest.php @@ -14,6 +14,10 @@ class MacrosTest extends TestCase { x - y - z = {$x - $y - $z} {/macro} + {macro multi(x, y)} + x * y = {$x * $y} + {/macro} + Math: {macro.plus x=2 y=3}, {macro.minus x=10 y=4} '); @@ -23,6 +27,21 @@ class MacrosTest extends TestCase { Imp: {macro.plus x=1 y=2}, {math.minus x=6 y=2 z=1} '); + + $this->tpl("import_custom.tpl", ' + {macro minus(x, y)} + new minus macros + {/macro} + {import [plus, minus] from "math.tpl" as math} + + a: {math.plus x=1 y=2}, {math.minus x=6 y=2 z=1}, {macro.minus x=5 y=3}. + '); + + $this->tpl("import_miss.tpl", ' + {import [minus] from "math.tpl" as math} + + a: {macro.plus x=5 y=3}. + '); } public function testMacros() { @@ -37,4 +56,20 @@ class MacrosTest extends TestCase { $this->assertSame('Imp: x + y = 3 , x - y - z = 3', Modifier::strip($tpl->fetch(array()), true)); } + + public function testImportCustom() { + $tpl = $this->aspect->compile('import_custom.tpl'); + + $this->assertSame('a: x + y = 3 , x - y - z = 3 , new minus macros .', Modifier::strip($tpl->fetch(array()), true)); + } + + /** + * @expectedExceptionMessage Undefined macro 'plus' + * @expectedException \Aspect\CompileException + */ + public function testImportMiss() { + $tpl = $this->aspect->compile('import_miss.tpl'); + + $this->assertSame('a: x + y = 3 , x - y - z = 3 , new minus macros .', Modifier::strip($tpl->fetch(array()), true)); + } } diff --git a/tests/cases/Aspect/TokenizerTest.php b/tests/cases/Aspect/TokenizerTest.php index aa0473d..2277901 100644 --- a/tests/cases/Aspect/TokenizerTest.php +++ b/tests/cases/Aspect/TokenizerTest.php @@ -54,7 +54,7 @@ class TokenizerTest extends \PHPUnit_Framework_TestCase { try { $tokens->skip(T_STRING)->skip('(')->skip(':'); } catch(\Exception $e) { - $this->assertInstanceOf('Aspect\UnexpectedException', $e); + $this->assertInstanceOf('Aspect\UnexpectedTokenException', $e); $this->assertStringStartsWith("Unexpected token '3' in expression, expect ':'", $e->getMessage()); } $this->assertTrue($tokens->valid());