[limb-svn] r6212 - in 3.x/trunk/limb/macro: src tests/cases

svn at limb-project.com svn at limb-project.com
Fri Aug 3 23:42:40 MSD 2007


Author: pachanga
Date: 2007-08-03 23:42:40 +0400 (Fri, 03 Aug 2007)
New Revision: 6212
URL: http://fisheye.limb-project.com/changelog/limb/?cs=6212

Modified:
   3.x/trunk/limb/macro/src/lmbMacroCodeWriter.class.php
   3.x/trunk/limb/macro/src/lmbMacroCompiler.class.php
   3.x/trunk/limb/macro/src/lmbMacroException.class.php
   3.x/trunk/limb/macro/src/lmbMacroNode.class.php
   3.x/trunk/limb/macro/src/lmbMacroParser.class.php
   3.x/trunk/limb/macro/src/lmbMacroSourceLocation.class.php
   3.x/trunk/limb/macro/src/lmbMacroTag.class.php
   3.x/trunk/limb/macro/src/lmbMacroTagDictionary.class.php
   3.x/trunk/limb/macro/src/lmbMacroTagInfo.class.php
   3.x/trunk/limb/macro/src/lmbMacroTagParsingState.class.php
   3.x/trunk/limb/macro/src/lmbMacroTemplate.class.php
   3.x/trunk/limb/macro/src/lmbMacroTemplateLocator.class.php
   3.x/trunk/limb/macro/src/lmbMacroTextNode.class.php
   3.x/trunk/limb/macro/src/lmbMacroTokenizer.class.php
   3.x/trunk/limb/macro/src/lmbMacroTokenizerListener.interface.php
   3.x/trunk/limb/macro/src/lmbMacroTreeBuilder.class.php
   3.x/trunk/limb/macro/tests/cases/lmbMacroCodeWriterTest.class.php
   3.x/trunk/limb/macro/tests/cases/lmbMacroTagDictionaryTest.class.php
   3.x/trunk/limb/macro/tests/cases/lmbMacroTagTest.class.php
   3.x/trunk/limb/macro/tests/cases/lmbMacroTemplateTest.class.php
   3.x/trunk/limb/macro/tests/cases/lmbMacroTokenizerMalformedTest.class.php
   3.x/trunk/limb/macro/tests/cases/lmbMacroTokenizerTest.class.php
   3.x/trunk/limb/macro/tests/cases/lmbMacroTreeBuilderTest.class.php
Log:
-- minor code beautifying
-- adding more malformed tests


Modified: 3.x/trunk/limb/macro/src/lmbMacroCodeWriter.class.php
===================================================================
--- 3.x/trunk/limb/macro/src/lmbMacroCodeWriter.class.php	2007-08-03 10:25:31 UTC (rev 6211)
+++ 3.x/trunk/limb/macro/src/lmbMacroCodeWriter.class.php	2007-08-03 19:42:40 UTC (rev 6212)
@@ -1,4 +1,4 @@
-<?php
+<?php
 /*
  * Limb PHP Framework
  *
@@ -7,178 +7,178 @@
  * @license    LGPL http://www.gnu.org/copyleft/lesser.html 
  */
 
-/**
- * class lmbMacroCodeWriter.
- *
- * @package macro
- * @version $Id$
+/**
+ * class lmbMacroCodeWriter.
+ *
+ * @package macro
+ * @version $Id$
  */
-class lmbMacroCodeWriter
-{
-  const MODE_PHP = 1;
-  const MODE_HTML = 2;
-
-  protected $current_mode = self :: MODE_HTML;
-
-  protected $code = '';
-
-  protected $function_prefix = '';
-  protected $function_suffix = 1;
-
-  protected $include_list = array();
-
-  protected $tempVarName = 1;
-
-  function reset()
-  {
-    $this->code = '';
-    $this->current_mode = self :: MODE_HTML;
-    $this->include_list = array();
-  }
-
-  protected function switchToPHP()
-  {
-    if($this->current_mode == self :: MODE_HTML)
-    {
-      $this->current_mode = self :: MODE_PHP;
-      $this->code .= '<?php ';
-    }
-  }
-
-  protected function switchToHTML($context = null)
-  {
-    if($this->current_mode == self :: MODE_PHP)
-    {
-      $this->current_mode = self :: MODE_HTML;
-      if($context === "\n")
-        $this->code .= " ?>\n";
-      else
-        $this->code .= ' ?>';
-    }
-  }
-
-  function writePHP($text)
-  {
-    $this->switchToPHP();
-    $this->code .= $text;
-  }
-
-  function writePHPLiteral($text, $escape_text = true)
-  {
-    $this->switchToPHP();
-
-    if($escape_text)
-      $this->code .= "'" . $this->escapeLiteral($text) . "'";
-    else
-      $this->code .= "'" . $text . "'";
-  }
-
-  function escapeLiteral($text)
-  {
-    $text = str_replace('\'', "\\'", $text);
-    if(substr($text, -1) == '\\')
-      $text .= '\\';
-    return $text;
-  }
-
-  function writeHTML($text)
-  {
-    $this->switchToHTML(substr($text,0,1));
-    $this->code .= $text;
-  }
-  
-  function writeRaw($text)
-  {
-    $this->code .= $text;
-  }
-
-  function renderCode()
-  {
-    $this->switchToHTML();
-
-    $this->_prependIncludeListToCode();
-
-    return $this->code;
-  }
-
-  function getCode()
-  {
-    return $this->code;
-  }
-
-  function setCode($code)
-  {
-    $this->code = $code;
-  }
-
-  protected function _prependIncludeListToCode()
-  {
-    $include_code = '';
-    foreach($this->include_list as $include_file)
-      $include_code .= "require_once('$include_file');\n";
-
-    if(!empty($include_code))
-      $this->code = '<?php ' . $include_code . '?>' . $this->code;
-  }
-
-  function getMode()
-  {
-    return $this->current_mode;
-  }
-
-  function registerInclude($include_file)
-  {
-    if(!in_array($include_file, $this->include_list))
-      $this->include_list[] = $include_file;    
-  }
-
-  function getIncludeList()
-  {
-    return $this->include_list;
-  }
-
-  /**
-  * Begins writing a PHP function to the compiled template, using the
-  * function_prefix and the function_suffix, the latter being post incremented
-  * by one.
-  */
-  function beginFunction($param_list)
-  {
-      $func_name = 'tpl' . $this->function_prefix . $this->function_suffix++;
-      $this->writePHP('function ' . $func_name . $param_list ." {\n");
-      return $func_name;
-  }
-
-  function endFunction()
-  {
-    $this->writePHP(" }\n");
-  }
-
-  function setFunctionPrefix($prefix)
-  {
-    $this->function_prefix = $prefix;
-  }
-
-  /**
-  * Utility method, which generates a unique variable name
-  */
-  function getTempVariable()
-  {
-    $var = $this->tempVarName++;
-    if($var > 675)
-      return chr(65 + ($var/26)/26) . chr(65 + ($var/26)%26) . chr(65 + $var%26);
-    elseif($var > 26)
-      return chr(65 + ($var/26)%26) . chr(65 + $var%26);
-    else
-      return chr(64 + $var);
-  }
-
-  /**
-  * Utility method, which generates a unique variable name, prefixed with a $
-  */
-  function getTempVarRef()
-  {
-    return '$' . $this->getTempVariable();
-  }
-}
-?>
+class lmbMacroCodeWriter
+{
+  const MODE_PHP = 1;
+  const MODE_HTML = 2;
+
+  protected $current_mode = self :: MODE_HTML;
+
+  protected $code = '';
+
+  protected $function_prefix = '';
+  protected $function_suffix = 1;
+
+  protected $include_list = array();
+
+  protected $tempVarName = 1;
+
+  function reset()
+  {
+    $this->code = '';
+    $this->current_mode = self :: MODE_HTML;
+    $this->include_list = array();
+  }
+
+  protected function switchToPHP()
+  {
+    if($this->current_mode == self :: MODE_HTML)
+    {
+      $this->current_mode = self :: MODE_PHP;
+      $this->code .= '<?php ';
+    }
+  }
+
+  protected function switchToHTML($context = null)
+  {
+    if($this->current_mode == self :: MODE_PHP)
+    {
+      $this->current_mode = self :: MODE_HTML;
+      if($context === "\n")
+        $this->code .= " ?>\n";
+      else
+        $this->code .= ' ?>';
+    }
+  }
+
+  function writePHP($text)
+  {
+    $this->switchToPHP();
+    $this->code .= $text;
+  }
+
+  function writePHPLiteral($text, $escape_text = true)
+  {
+    $this->switchToPHP();
+
+    if($escape_text)
+      $this->code .= "'" . $this->escapeLiteral($text) . "'";
+    else
+      $this->code .= "'" . $text . "'";
+  }
+
+  function escapeLiteral($text)
+  {
+    $text = str_replace('\'', "\\'", $text);
+    if(substr($text, -1) == '\\')
+      $text .= '\\';
+    return $text;
+  }
+
+  function writeHTML($text)
+  {
+    $this->switchToHTML(substr($text,0,1));
+    $this->code .= $text;
+  }
+  
+  function writeRaw($text)
+  {
+    $this->code .= $text;
+  }
+
+  function renderCode()
+  {
+    $this->switchToHTML();
+
+    $this->_prependIncludeListToCode();
+
+    return $this->code;
+  }
+
+  function getCode()
+  {
+    return $this->code;
+  }
+
+  function setCode($code)
+  {
+    $this->code = $code;
+  }
+
+  protected function _prependIncludeListToCode()
+  {
+    $include_code = '';
+    foreach($this->include_list as $include_file)
+      $include_code .= "require_once('$include_file');\n";
+
+    if(!empty($include_code))
+      $this->code = '<?php ' . $include_code . '?>' . $this->code;
+  }
+
+  function getMode()
+  {
+    return $this->current_mode;
+  }
+
+  function registerInclude($include_file)
+  {
+    if(!in_array($include_file, $this->include_list))
+      $this->include_list[] = $include_file;    
+  }
+
+  function getIncludeList()
+  {
+    return $this->include_list;
+  }
+
+  /**
+  * Begins writing a PHP function to the compiled template, using the
+  * function_prefix and the function_suffix, the latter being post incremented
+  * by one.
+  */
+  function beginFunction($param_list)
+  {
+      $func_name = 'tpl' . $this->function_prefix . $this->function_suffix++;
+      $this->writePHP('function ' . $func_name . $param_list ." {\n");
+      return $func_name;
+  }
+
+  function endFunction()
+  {
+    $this->writePHP(" }\n");
+  }
+
+  function setFunctionPrefix($prefix)
+  {
+    $this->function_prefix = $prefix;
+  }
+
+  /**
+  * Utility method, which generates a unique variable name
+  */
+  function getTempVariable()
+  {
+    $var = $this->tempVarName++;
+    if($var > 675)
+      return chr(65 + ($var/26)/26) . chr(65 + ($var/26)%26) . chr(65 + $var%26);
+    elseif($var > 26)
+      return chr(65 + ($var/26)%26) . chr(65 + $var%26);
+    else
+      return chr(64 + $var);
+  }
+
+  /**
+  * Utility method, which generates a unique variable name, prefixed with a $
+  */
+  function getTempVarRef()
+  {
+    return '$' . $this->getTempVariable();
+  }
+}
+?>

Modified: 3.x/trunk/limb/macro/src/lmbMacroCompiler.class.php
===================================================================
--- 3.x/trunk/limb/macro/src/lmbMacroCompiler.class.php	2007-08-03 10:25:31 UTC (rev 6211)
+++ 3.x/trunk/limb/macro/src/lmbMacroCompiler.class.php	2007-08-03 19:42:40 UTC (rev 6212)
@@ -1,4 +1,4 @@
-<?php
+<?php
 /*
  * Limb PHP Framework
  *
@@ -7,130 +7,130 @@
  * @license    LGPL http://www.gnu.org/copyleft/lesser.html 
  */
 
-/**
- * class lmbMacroCompiler.
- *
- * @package macro
- * @version $Id$
+/**
+ * class lmbMacroCompiler.
+ *
+ * @package macro
+ * @version $Id$
  */
-class lmbMacroCompiler
-{
-  /**
-  * @var lmbMacroTreeBuilder
-  */
-  protected $tree_builder;
-
-  /**
-  * @var lmbMacroConfig
-  */
-  protected $config;
-
-  /**
-  * @var lmbMacroTemplateLocator
-  */
-  protected $template_locator;
-
-  /**
-  * @var lmbMacroSourceParser
-  */
-  protected $parser;
-
-  /**
-  * @var lmbMacroTagDictionary
-  */
-  protected $tag_dictionary;
-
-
-  function __construct($config, $tag_dictionary, $template_locator)
-  {
-    $this->config = $config;
-    $this->template_locator = $template_locator;
-
-    $this->tag_dictionary = $tag_dictionary;
-    $this->tree_builder = new lmbMacroTreeBuilder($this);
-  }
-
-  function compile($file_name)
-  {
-    if(!$source_file_path = $this->template_locator->locateSourceTemplate($file_name))    
-     throw new lmbMacroException('Template source file not found', array('file_name' => $file_name));
-
-    $root_node = new lmbMacroRootNode(new lmbMacroSourceLocation($source_file_path, ''));
-
-    $this->parseTemplate($file_name, $root_node);
-
-    $root_node->prepare();
-
-    $compiled_file_path = $this->template_locator->locateCompiledTemplate($file_name);
-    $generated_code = $this->_generateTemplateCode(md5($compiled_file_path), $root_node);
-    self :: writeFile($compiled_file_path, $generated_code);
-  }
-
-  function _generateTemplateCode($prefix, $root_node)
-  {
-    $code_writer = new lmbMacroCodeWriter();
-    $code_writer->setFunctionPrefix($prefix);
-
-    $constructor_func = $code_writer->beginFunction('($root, $components)');
-    $root_node->generateConstructor($code_writer);
-    $code_writer->endFunction();
-
-    $render_func = $code_writer->beginFunction('($root, $components)');
-    $code_writer->writePHP('$template = $root;' . "\n");
-    $root_node->generate($code_writer);
-    $code_writer->endFunction();
-
-    $code_writer->writePHP('$GLOBALS[\'TemplateRender\'][$compiled_template_path] = \'' . $render_func . '\';');
-    $code_writer->writePHP('$GLOBALS[\'TemplateConstruct\'][$compiled_template_path] = \'' . $constructor_func . '\';');
-
-    return $code_writer->renderCode();
-  }
-
-  function parseTemplate($source_file_path, $root_node)
-  {
-    $parser = new lmbMacroParser($this->tree_builder,                                           
-                                 $this->config,
-                                 $this->template_locator,
-                                 $this->tag_dictionary);
-
-    $parser->parse($source_file_path, $root_node);
-  }
-
-  /**
-  * @return lmbMacroConfig
-  **/
-  function getConfig()
-  {
-    return $this->config;
-  }
-
-  /**
-  * @return lmbMacroTemplateLocator
-  **/
-  function getTemplateLocator()
-  {
-    return $this->template_locator;
-  }
-
-  /**
-  * @return lmbMacroTreeBuilder
-  **/
-  function getTreeBuilder()
-  {
-    return $this->tree_builder;
-  }
-
-  function getTagDictionary()
-  {
-    return $this->tag_dictionary;
-  }
-
-  static function writeFile($file, $data)
-  {
-    $dirname = dirname($file);    
-    lmbFs :: mkdir($dirname);
-
-    file_put_contents($file, $data);
-  }
-}
-?>
+class lmbMacroCompiler
+{
+  /**
+  * @var lmbMacroTreeBuilder
+  */
+  protected $tree_builder;
+
+  /**
+  * @var lmbMacroConfig
+  */
+  protected $config;
+
+  /**
+  * @var lmbMacroTemplateLocator
+  */
+  protected $template_locator;
+
+  /**
+  * @var lmbMacroSourceParser
+  */
+  protected $parser;
+
+  /**
+  * @var lmbMacroTagDictionary
+  */
+  protected $tag_dictionary;
+
+
+  function __construct($config, $tag_dictionary, $template_locator)
+  {
+    $this->config = $config;
+    $this->template_locator = $template_locator;
+
+    $this->tag_dictionary = $tag_dictionary;
+    $this->tree_builder = new lmbMacroTreeBuilder($this);
+  }
+
+  function compile($file_name)
+  {
+    if(!$source_file_path = $this->template_locator->locateSourceTemplate($file_name))    
+     throw new lmbMacroException('Template source file not found', array('file_name' => $file_name));
+
+    $root_node = new lmbMacroRootNode(new lmbMacroSourceLocation($source_file_path, ''));
+
+    $this->parseTemplate($file_name, $root_node);
+
+    $root_node->prepare();
+
+    $compiled_file_path = $this->template_locator->locateCompiledTemplate($file_name);
+    $generated_code = $this->_generateTemplateCode(md5($compiled_file_path), $root_node);
+    self :: writeFile($compiled_file_path, $generated_code);
+  }
+
+  function _generateTemplateCode($prefix, $root_node)
+  {
+    $code_writer = new lmbMacroCodeWriter();
+    $code_writer->setFunctionPrefix($prefix);
+
+    $constructor_func = $code_writer->beginFunction('($root, $components)');
+    $root_node->generateConstructor($code_writer);
+    $code_writer->endFunction();
+
+    $render_func = $code_writer->beginFunction('($root, $components)');
+    $code_writer->writePHP('$template = $root;' . "\n");
+    $root_node->generate($code_writer);
+    $code_writer->endFunction();
+
+    $code_writer->writePHP('$GLOBALS[\'TemplateRender\'][$compiled_template_path] = \'' . $render_func . '\';');
+    $code_writer->writePHP('$GLOBALS[\'TemplateConstruct\'][$compiled_template_path] = \'' . $constructor_func . '\';');
+
+    return $code_writer->renderCode();
+  }
+
+  function parseTemplate($source_file_path, $root_node)
+  {
+    $parser = new lmbMacroParser($this->tree_builder,                                           
+                                 $this->config,
+                                 $this->template_locator,
+                                 $this->tag_dictionary);
+
+    $parser->parse($source_file_path, $root_node);
+  }
+
+  /**
+  * @return lmbMacroConfig
+  */
+  function getConfig()
+  {
+    return $this->config;
+  }
+
+  /**
+  * @return lmbMacroTemplateLocator
+  */
+  function getTemplateLocator()
+  {
+    return $this->template_locator;
+  }
+
+  /**
+  * @return lmbMacroTreeBuilder
+  */
+  function getTreeBuilder()
+  {
+    return $this->tree_builder;
+  }
+
+  function getTagDictionary()
+  {
+    return $this->tag_dictionary;
+  }
+
+  static function writeFile($file, $data)
+  {
+    $dirname = dirname($file);    
+    lmbFs :: mkdir($dirname);
+
+    file_put_contents($file, $data);
+  }
+}
+?>

Modified: 3.x/trunk/limb/macro/src/lmbMacroException.class.php
===================================================================
--- 3.x/trunk/limb/macro/src/lmbMacroException.class.php	2007-08-03 10:25:31 UTC (rev 6211)
+++ 3.x/trunk/limb/macro/src/lmbMacroException.class.php	2007-08-03 19:42:40 UTC (rev 6212)
@@ -1,4 +1,4 @@
-<?php
+<?php
 /*
  * Limb PHP Framework
  *
@@ -7,17 +7,17 @@
  * @license    LGPL http://www.gnu.org/copyleft/lesser.html 
  */
 
-/**
- * class lmbMacroException.
- *
- * @package macro
- * @version $Id$
+/**
+ * class lmbMacroException.
+ *
+ * @package macro
+ * @version $Id$
  */
-class lmbMacroException extends lmbException
-{
-  function __construct($message, $params = array())
-  {
-    parent :: __construct('MACRO exception: ' . $message, $params);
-  }
-}
-?>
\ No newline at end of file
+class lmbMacroException extends lmbException
+{
+  function __construct($message, $params = array())
+  {
+    parent :: __construct('MACRO exception: ' . $message, $params);
+  }
+}
+?>

Modified: 3.x/trunk/limb/macro/src/lmbMacroNode.class.php
===================================================================
--- 3.x/trunk/limb/macro/src/lmbMacroNode.class.php	2007-08-03 10:25:31 UTC (rev 6211)
+++ 3.x/trunk/limb/macro/src/lmbMacroNode.class.php	2007-08-03 19:42:40 UTC (rev 6212)
@@ -1,253 +1,253 @@
-<?php
+<?php
 /*
  * Limb PHP Framework
  *
  * @link http://limb-project.com 
  * @copyright  Copyright &copy; 2004-2007 BIT(http://bit-creative.com)
  * @license    LGPL http://www.gnu.org/copyleft/lesser.html 
- */
-lmb_require('limb/macro/src/lmbMacroException.class.php');
+ */
+lmb_require('limb/macro/src/lmbMacroException.class.php');
 lmb_require('limb/macro/src/lmbMacroSourceLocation.class.php');
 
-/**
- * class lmbMacroNode.
- *
- * @package macro
- * @version $Id$
+/**
+ * class lmbMacroNode.
+ *
+ * @package macro
+ * @version $Id$
  */
-class lmbMacroNode
-{
-  protected $id;  
-  protected $children = array();
-  protected $parent;  
-  /**
-  * @var lmbMacroSourceLocation
-  **/
-  protected $location;    
-
-  function __construct($location = null)
-  {
-    if($location)
-      $this->location = $location;
-    else
-      $this->location = new lmbMacroSourceLocation();
-  }
-  
-  function setParent($parent)
-  {
-    $this->parent = $parent;
-  }
-  
-  function getParent()
-  {
-    return $this->parent;
-  }
-  
-  function getLocationInTemplate()
-  {
-    return $this->location;
-  }
-
-  function getTemplateFile()
-  {
-    return $this->location->getFile();
-  }
-
-  function getTemplateLine()
-  {
-    return $this->location->getLine();
-  }
-
-  function getId()
-  {
-    if($this->id)
-      return $this->id;
-        
-    $this->id = self :: generateNewId();
-    return $this->id;
-  }
-
-  function setId($id)
-  {
-    $this->id = $id;
-  }  
-  
-  static function generateNewId()
-  {
-    static $counter = 1;
-    return 'id00' . $counter++;
-  }    
-  
-  function raise($error, $vars = array())
-  {    
-    $vars['file'] = $this->location->getFile();
-    $vars['line'] = $this->location->getLine();
-    throw new lmbMacroException($error, $vars);
-  }  
-  
-  function addChild($child)
-  {
-    $child->parent = $this;
-    $this->children[] = $child;
-  }
-
-  function removeChild($id)
-  {
-    foreach(array_keys($this->children) as $key)
-    {
-      $child = $this->children[$key];
-      if($child->getId() == $id)
-      {
-        unset($this->children[$key]);
-        return $child;
-      }
-    }
-  }
-
-  function getChildren()
-  {
-    return $this->children;
-  }
-
-  function removeChildren()
-  {
-    foreach (array_keys($this->children) as $key)
-    {
-      $this->children[$key]->removeChildren();
-      unset($this->children[$key]);
-    }
-  }
-
-  function getChild($id)
-  {
-    if($child = $this->findChild($id))
-      return $child;
-    else
-      $this->raise('Could not find component', array('id' => $id));
-  }
-
-  function findChild($id)
-  {
-    foreach(array_keys($this->children) as $key)
-    {
-      if($this->children[$key]->getId() == $id)
-        return $this->children[$key];
-      else
-        return $this->children[$key]->findChild($id);          
-    }
-  }
-
-  function findChildByClass($class)
-  {
-    foreach(array_keys($this->children) as $key)
-    {
-      if(is_a($this->children[$key], $class))
-        return $this->children[$key];
-      else
-      {
-        if($result = $this->children[$key]->findChildByClass($class))
-          return $result;
-      }
-    }
-  }
-
-  function findChildrenByClass($class)
-  {
-    $ret = array();
-    foreach(array_keys($this->children) as $key)
-    {
-      if(is_a($this->children[$key], $class))
-        $ret[] = $this->children[$key];
-      else
-      {
-        $more_children = $this->children[$key]->findChildrenByClass($class);
-        if(count($more_children))
-          $ret = array_merge($ret, $more_children);
-      }
-    }
-    return $ret;
-  }
-
-  function findImmediateChildByClass($class)
-  {
-    foreach(array_keys($this->children) as $key)
-    {
-      if(is_a($this->children[$key], $class))
-        return $this->children[$key];
-    }
-  }
-
-  function findImmediateChildrenByClass($class)
-  {
-    $result = array();
-    foreach(array_keys($this->children) as $key)
-    {
-      if(is_a($this->children[$key], $class))
-        $result[] = $this->children[$key];
-    }
-    return $result;
-  }  
-  
-  function findParentByClass($class)
-  {
-    $parent = $this->parent;
-
-    while($parent && !is_a($parent, $class))
-      $parent = $parent->parent;
-
-    return $parent;
-  }  
-  
-  function prepare()
-  {
-    foreach(array_keys($this->children) as $key)
-      $this->children[$key]->prepare();
-  }  
-
-  function preParse(){}
-  
-  function generateConstructor($code_writer)
-  {
-    foreach(array_keys($this->children) as $key)
-      $this->children[$key]->generateConstructor($code_writer);
-  }
-
-  function generateContents($code_writer)
-  {
-    foreach(array_keys($this->children) as $key)
-      $this->children[$key]->generate($code_writer);
-  }
-  
-  function generate($code_writer)
-  {   
-    $this->generateContents($code_writer);   
-  }  
-     
-  /**
-  * Checks that each immediate child of the current component has a unique ID
-  * amongst its siblings.
-  */
-  function checkChildrenIds()
-  {
-    $child_ids = array();
-    $checked_children = array();
-    foreach($this->getChildren() as $key => $child)
-    {
-      $id = $child->getId();
-      if (in_array($id, $child_ids))
-      {
-        $duplicate_child = $checked_children[$id];
-        $child->raise('Duplicate "id" attribute',
-                                   array('id' => $id,
-                                         'duplicate_node_file' => $duplicate_child->getTemplateFile(),
-                                         'duplicate_node_line' => $duplicate_child->getTemplateLine()));
-      }
-      else
-      {
-        $child_ids[] = $id;
-        $checked_children[$id] = $child;
-      }
-    }
-  }  
-}
-?>
\ No newline at end of file
+class lmbMacroNode
+{
+  protected $id;  
+  protected $children = array();
+  protected $parent;  
+  /**
+  * @var lmbMacroSourceLocation
+  */
+  protected $location;    
+
+  function __construct($location = null)
+  {
+    if($location)
+      $this->location = $location;
+    else
+      $this->location = new lmbMacroSourceLocation();
+  }
+  
+  function setParent($parent)
+  {
+    $this->parent = $parent;
+  }
+  
+  function getParent()
+  {
+    return $this->parent;
+  }
+  
+  function getLocationInTemplate()
+  {
+    return $this->location;
+  }
+
+  function getTemplateFile()
+  {
+    return $this->location->getFile();
+  }
+
+  function getTemplateLine()
+  {
+    return $this->location->getLine();
+  }
+
+  function getId()
+  {
+    if($this->id)
+      return $this->id;
+        
+    $this->id = self :: generateNewId();
+    return $this->id;
+  }
+
+  function setId($id)
+  {
+    $this->id = $id;
+  }  
+  
+  static function generateNewId()
+  {
+    static $counter = 1;
+    return 'id00' . $counter++;
+  }    
+  
+  function raise($error, $vars = array())
+  {    
+    $vars['file'] = $this->location->getFile();
+    $vars['line'] = $this->location->getLine();
+    throw new lmbMacroException($error, $vars);
+  }  
+  
+  function addChild($child)
+  {
+    $child->parent = $this;
+    $this->children[] = $child;
+  }
+
+  function removeChild($id)
+  {
+    foreach(array_keys($this->children) as $key)
+    {
+      $child = $this->children[$key];
+      if($child->getId() == $id)
+      {
+        unset($this->children[$key]);
+        return $child;
+      }
+    }
+  }
+
+  function getChildren()
+  {
+    return $this->children;
+  }
+
+  function removeChildren()
+  {
+    foreach (array_keys($this->children) as $key)
+    {
+      $this->children[$key]->removeChildren();
+      unset($this->children[$key]);
+    }
+  }
+
+  function getChild($id)
+  {
+    if($child = $this->findChild($id))
+      return $child;
+    else
+      $this->raise('Could not find component', array('id' => $id));
+  }
+
+  function findChild($id)
+  {
+    foreach(array_keys($this->children) as $key)
+    {
+      if($this->children[$key]->getId() == $id)
+        return $this->children[$key];
+      else
+        return $this->children[$key]->findChild($id);          
+    }
+  }
+
+  function findChildByClass($class)
+  {
+    foreach(array_keys($this->children) as $key)
+    {
+      if(is_a($this->children[$key], $class))
+        return $this->children[$key];
+      else
+      {
+        if($result = $this->children[$key]->findChildByClass($class))
+          return $result;
+      }
+    }
+  }
+
+  function findChildrenByClass($class)
+  {
+    $ret = array();
+    foreach(array_keys($this->children) as $key)
+    {
+      if(is_a($this->children[$key], $class))
+        $ret[] = $this->children[$key];
+      else
+      {
+        $more_children = $this->children[$key]->findChildrenByClass($class);
+        if(count($more_children))
+          $ret = array_merge($ret, $more_children);
+      }
+    }
+    return $ret;
+  }
+
+  function findImmediateChildByClass($class)
+  {
+    foreach(array_keys($this->children) as $key)
+    {
+      if(is_a($this->children[$key], $class))
+        return $this->children[$key];
+    }
+  }
+
+  function findImmediateChildrenByClass($class)
+  {
+    $result = array();
+    foreach(array_keys($this->children) as $key)
+    {
+      if(is_a($this->children[$key], $class))
+        $result[] = $this->children[$key];
+    }
+    return $result;
+  }  
+  
+  function findParentByClass($class)
+  {
+    $parent = $this->parent;
+
+    while($parent && !is_a($parent, $class))
+      $parent = $parent->parent;
+
+    return $parent;
+  }  
+  
+  function prepare()
+  {
+    foreach(array_keys($this->children) as $key)
+      $this->children[$key]->prepare();
+  }  
+
+  function preParse(){}
+  
+  function generateConstructor($code_writer)
+  {
+    foreach(array_keys($this->children) as $key)
+      $this->children[$key]->generateConstructor($code_writer);
+  }
+
+  function generateContents($code_writer)
+  {
+    foreach(array_keys($this->children) as $key)
+      $this->children[$key]->generate($code_writer);
+  }
+  
+  function generate($code_writer)
+  {   
+    $this->generateContents($code_writer);   
+  }  
+     
+  /**
+  * Checks that each immediate child of the current component has a unique ID
+  * amongst its siblings.
+  */
+  function checkChildrenIds()
+  {
+    $child_ids = array();
+    $checked_children = array();
+    foreach($this->getChildren() as $key => $child)
+    {
+      $id = $child->getId();
+      if (in_array($id, $child_ids))
+      {
+        $duplicate_child = $checked_children[$id];
+        $child->raise('Duplicate "id" attribute',
+                                   array('id' => $id,
+                                         'duplicate_node_file' => $duplicate_child->getTemplateFile(),
+                                         'duplicate_node_line' => $duplicate_child->getTemplateLine()));
+      }
+      else
+      {
+        $child_ids[] = $id;
+        $checked_children[$id] = $child;
+      }
+    }
+  }  
+}
+?>

Modified: 3.x/trunk/limb/macro/src/lmbMacroParser.class.php
===================================================================
--- 3.x/trunk/limb/macro/src/lmbMacroParser.class.php	2007-08-03 10:25:31 UTC (rev 6211)
+++ 3.x/trunk/limb/macro/src/lmbMacroParser.class.php	2007-08-03 19:42:40 UTC (rev 6212)
@@ -1,4 +1,4 @@
-<?php
+<?php
 /*
  * Limb PHP Framework
  *
@@ -7,150 +7,150 @@
  * @license    LGPL http://www.gnu.org/copyleft/lesser.html 
  */
 
-/**
- * class lmbMacroParser.
- *
- * @package macro
- * @version $Id$
+/**
+ * class lmbMacroParser.
+ *
+ * @package macro
+ * @version $Id$
  */
-class lmbMacroParser implements lmbMacroTokenizerListener
-{
-  protected $active_parsing_state;
-  protected $component_parsing_state;
-  protected $literal_parsing_state;
-
-  /**
-   * @var lmbMacroConfig
-   */
-  protected $config;
-
-  /**
-   * @var lmbMacrotree_builder
-   */
-  protected $tree_builder;
-
-  /**
-   * @var lmbMacroTemplateLocator
-   */
-  protected $template_locator;
-
-  function __construct($tree_builder, $config, $template_locator, $tag_dictionary)
-  {
-    $this->tree_builder = $tree_builder;
-
-    $this->config = $config;
-    $this->template_locator = $template_locator;
-
-    $this->component_parsing_state = $this->_createComponentParsingState($tag_dictionary);
-    $this->literal_parsing_state = $this->_createLiteralParsingState();
-
-    $this->changeToComponentParsingState();
-  }
-
-  // for testing purposes
-  protected function _createComponentParsingState($tag_dictionary)
-  {
-    return new lmbMacroTagParsingState($this, $this->tree_builder, $tag_dictionary);
-  }
-
-  // for testing purposes
-  protected function _createLiteralParsingState()
-  {
-    return new lmbMacroLiteralParsingState($this, $this->tree_builder);
-  }
-
-  /**
-  * Used to parse the source template.
-  * Initially invoked by the CompileTemplate function,
-  * the first component argument being a root node.
-  */
-  function parse($file_name, $root_node)
-  {
-    $source_file_path = $this->template_locator->locateSourceTemplate($file_name);
-
-    if(empty($source_file_path))
-        throw new lmbMacroException('Template source file not found', array('file_name' => $file_name));
-
-    $tags_before_parse = $this->tree_builder->getExpectedTagCount();
-
-    $this->tree_builder->setCursor($root_node);
-
-    $this->changeToComponentParsingState();
-
-    $tokenizer = new lmbMacroTokenizer($this);
-
-    $this->setTemplateLocator($parser);
-
-    $content = $this->template_locator->readTemplateFile($source_file_path);
-
-    $tokenizer->parse($content, $source_file_path);
-
-    if($tags_before_parse != $this->tree_builder->getExpectedTagCount())
-    {
-      $location = $this->tree_builder->getExpectedTagLocation();
-      throw new lmbMacroException('Missing close tag',
-                              array('tag' => $this->tree_builder->getExpectedTag(),
-                                    'file' => $location->getFile(),
-                                    'line' => $location->getLine()));
-    }
-  }
-
-  function getActiveParsingState()
-  {
-    return $this->active_parsing_state;
-  }
-  
-  function changeToComponentParsingState()
-  {
-    $this->active_parsing_state = $this->component_parsing_state;
-  }  
-
-  function changeToLiteralParsingState($tag)
-  {
-    $this->active_parsing_state = $this->literal_parsing_state;
-    $this->active_parsing_state->setLiteralTag($tag);
-  }
-  
-  function setTemplateLocator($template_locator)
-  {
-    $this->literal_parsing_state->setTemplateLocator($template_locator);
-    $this->component_parsing_state->setTemplateLocator($template_locator);
-  }  
-
-  function startElement($tag, $attrs)
-  {
-    $this->active_parsing_state->startElement($tag, $attrs);
-  }
-
-  function endElement($tag)
-  {
-    $this->active_parsing_state->endElement($tag);
-  }
-
-  function emptyElement($tag, $attrs)
-  {
-    $this->active_parsing_state->emptyElement($tag, $attrs);
-  }
-
-  function characters($text)
-  {
-    $this->active_parsing_state->characters($text);
-  }
-
-  function unexpectedEOF($text)
-  {
-    $this->active_parsing_state->unexpectedEOF($text);
-  }
-
-  function invalidEntitySyntax($text)
-  {
-    $this->active_parsing_state->invalidEntitySyntax($text);
-  }
-
-  function invalidAttributeSyntax()
-  {
-    $this->active_parsing_state->invalidAttributeSyntax();
-  }
-}
-
-?>
+class lmbMacroParser implements lmbMacroTokenizerListener
+{
+  protected $active_parsing_state;
+  protected $component_parsing_state;
+  protected $literal_parsing_state;
+
+  /**
+   * @var lmbMacroConfig
+   */
+  protected $config;
+
+  /**
+   * @var lmbMacrotree_builder
+   */
+  protected $tree_builder;
+
+  /**
+   * @var lmbMacroTemplateLocator
+   */
+  protected $template_locator;
+
+  function __construct($tree_builder, $config, $template_locator, $tag_dictionary)
+  {
+    $this->tree_builder = $tree_builder;
+
+    $this->config = $config;
+    $this->template_locator = $template_locator;
+
+    $this->component_parsing_state = $this->_createComponentParsingState($tag_dictionary);
+    $this->literal_parsing_state = $this->_createLiteralParsingState();
+
+    $this->changeToComponentParsingState();
+  }
+
+  // for testing purposes
+  protected function _createComponentParsingState($tag_dictionary)
+  {
+    return new lmbMacroTagParsingState($this, $this->tree_builder, $tag_dictionary);
+  }
+
+  // for testing purposes
+  protected function _createLiteralParsingState()
+  {
+    return new lmbMacroLiteralParsingState($this, $this->tree_builder);
+  }
+
+  /**
+  * Used to parse the source template.
+  * Initially invoked by the CompileTemplate function,
+  * the first component argument being a root node.
+  */
+  function parse($file_name, $root_node)
+  {
+    $source_file_path = $this->template_locator->locateSourceTemplate($file_name);
+
+    if(empty($source_file_path))
+        throw new lmbMacroException('Template source file not found', array('file_name' => $file_name));
+
+    $tags_before_parse = $this->tree_builder->getExpectedTagCount();
+
+    $this->tree_builder->setCursor($root_node);
+
+    $this->changeToComponentParsingState();
+
+    $tokenizer = new lmbMacroTokenizer($this);
+
+    $this->setTemplateLocator($parser);
+
+    $content = $this->template_locator->readTemplateFile($source_file_path);
+
+    $tokenizer->parse($content, $source_file_path);
+
+    if($tags_before_parse != $this->tree_builder->getExpectedTagCount())
+    {
+      $location = $this->tree_builder->getExpectedTagLocation();
+      throw new lmbMacroException('Missing close tag',
+                              array('tag' => $this->tree_builder->getExpectedTag(),
+                                    'file' => $location->getFile(),
+                                    'line' => $location->getLine()));
+    }
+  }
+
+  function getActiveParsingState()
+  {
+    return $this->active_parsing_state;
+  }
+  
+  function changeToComponentParsingState()
+  {
+    $this->active_parsing_state = $this->component_parsing_state;
+  }  
+
+  function changeToLiteralParsingState($tag)
+  {
+    $this->active_parsing_state = $this->literal_parsing_state;
+    $this->active_parsing_state->setLiteralTag($tag);
+  }
+  
+  function setTemplateLocator($template_locator)
+  {
+    $this->literal_parsing_state->setTemplateLocator($template_locator);
+    $this->component_parsing_state->setTemplateLocator($template_locator);
+  }  
+
+  function startElement($tag, $attrs)
+  {
+    $this->active_parsing_state->startElement($tag, $attrs);
+  }
+
+  function endElement($tag)
+  {
+    $this->active_parsing_state->endElement($tag);
+  }
+
+  function emptyElement($tag, $attrs)
+  {
+    $this->active_parsing_state->emptyElement($tag, $attrs);
+  }
+
+  function characters($text)
+  {
+    $this->active_parsing_state->characters($text);
+  }
+
+  function unexpectedEOF($text)
+  {
+    $this->active_parsing_state->unexpectedEOF($text);
+  }
+
+  function invalidEntitySyntax($text)
+  {
+    $this->active_parsing_state->invalidEntitySyntax($text);
+  }
+
+  function invalidAttributeSyntax()
+  {
+    $this->active_parsing_state->invalidAttributeSyntax();
+  }
+}
+
+?>

Modified: 3.x/trunk/limb/macro/src/lmbMacroSourceLocation.class.php
===================================================================
--- 3.x/trunk/limb/macro/src/lmbMacroSourceLocation.class.php	2007-08-03 10:25:31 UTC (rev 6211)
+++ 3.x/trunk/limb/macro/src/lmbMacroSourceLocation.class.php	2007-08-03 19:42:40 UTC (rev 6212)
@@ -1,4 +1,4 @@
-<?php
+<?php
 /*
  * Limb PHP Framework
  *
@@ -7,38 +7,38 @@
  * @license    LGPL http://www.gnu.org/copyleft/lesser.html 
  */
 
-/**
- * class lmbMacroSourceLocation.
- *
- * @package macro
- * @version $Id$
+/**
+ * class lmbMacroSourceLocation.
+ *
+ * @package macro
+ * @version $Id$
  */
-class lmbMacroSourceLocation
-{
-  public $file;
-  public $line;
-
-  function __construct($file = null, $line = null)
-  {
-    if($file)
-      $this->file = $file;
-    else
-      $this->file = 'unknown file';
-
-    if($line)
-      $this->line = $line;
-    else
-      $this->line = 'unknown line';
-  }
-
-  function getFile()
-  {
-    return $this->file;
-  }
-
-  function getLine()
-  {
-    return $this->line;
-  }
-}
-?>
\ No newline at end of file
+class lmbMacroSourceLocation
+{
+  public $file;
+  public $line;
+
+  function __construct($file = null, $line = null)
+  {
+    if($file)
+      $this->file = $file;
+    else
+      $this->file = 'unknown file';
+
+    if($line)
+      $this->line = $line;
+    else
+      $this->line = 'unknown line';
+  }
+
+  function getFile()
+  {
+    return $this->file;
+  }
+
+  function getLine()
+  {
+    return $this->line;
+  }
+}
+?>

Modified: 3.x/trunk/limb/macro/src/lmbMacroTag.class.php
===================================================================
--- 3.x/trunk/limb/macro/src/lmbMacroTag.class.php	2007-08-03 10:25:31 UTC (rev 6211)
+++ 3.x/trunk/limb/macro/src/lmbMacroTag.class.php	2007-08-03 19:42:40 UTC (rev 6212)
@@ -1,147 +1,147 @@
-<?php
+<?php
 /*
  * Limb PHP Framework
  *
  * @link http://limb-project.com 
  * @copyright  Copyright &copy; 2004-2007 BIT(http://bit-creative.com)
  * @license    LGPL http://www.gnu.org/copyleft/lesser.html 
- */
-
+ */
+
 lmb_require('limb/macro/src/lmbMacroNode.class.php');
 
-/**
- * class lmbMacroTag.
- *
- * @package macro
- * @version $Id$
+/**
+ * class lmbMacroTag.
+ *
+ * @package macro
+ * @version $Id$
  */
-class lmbMacroTag extends lmbMacroNode
-{
-  protected $tag;
-  protected $has_closing_tag = true;
-  protected $empty_closed_tag = false;  
-  protected $tag_info;
-  protected $attributes = array();
-  
-  function __construct($location, $tag, $tag_info)
-  {
-    $this->tag = $tag;
-    $this->tag_info = $tag_info;
-    
-    parent :: __construct($location);
-  }
-
-  function getTag()
-  {
-    return $this->tag;
-  }
-  
-  function getHasClosingTag()
-  {
-    return $this->has_closing_tag;
-  }
-  
-  function setHasClosingTag($flag)
-  {
-    return $this->has_closing_tag = $flag;
-  }  
-  
-  function getId()
-  {
-    if($this->id)
-      return $this->id;
-        
-    if($id = $this->get('id'))
-      $this->id = $id;
-    else
-      $this->id = self :: generateNewId();
-
-    return $this->id;
-  }  
-  
-  function get($name)
-  {
-    if(array_key_exists(strtolower($name), $this->attributes))
-      return $this->attributes[strtolower($name)];
-  }  
-  
-  function set($name, $value)
-  {
-    $this->attributes[strtolower($name)] = $value;
-  }
-
-  function has($name)
-  {
-    return array_key_exists(strtolower($name), $this->attributes);
-  }
-
-  /**
-  * Return the value of a boolean attribute as a boolean.
-  * ATTRIBUTE=ANYTHING  (true)
-  * ATTRIBUTE=(false|N|NA|NO|NONE|0) (false)
-  * ATTRIBUTE (true)
-  * (attribute unspecified) (default)
-  */
-  function getBool($attrib, $default = false)
-  {
-    if(!isset($this->attributes[strtolower($attrib)]))
-      return $default;
-
-    return self :: getBooleanValue($this->attributes[strtolower($attrib)]);
-  }
-
-  static function getBooleanValue($value)
-  {
-    switch(strtoupper($value))
-    {
-      case 'FALSE':
-      case 'N':
-      case 'NO':
-      case 'NONE':
-      case 'NA':
-      case '0':
-        return false;
-      default:
-        return true;
-    }
-  }
-
-  function remove($attrib)
-  {
-    unset($this->attributes[strtolower($attrib)]);
-  }  
-    
-  function raise($error, $vars = array())
-  {
-    $vars['tag'] = $this->tag;
-    parent :: raise($error, $vars);
-  }  
-
-  function raiseRequiredAttribute($attribute_name)
-  {
-    $this->raise('Missing required attribute', array('attribute' => $attribute_name));
-  }
-  
-  function preParse()
-  {
-    foreach($this->tag_info->getRequiredAttributes() as $attr_name)
-    {
-      if(!$this->has($attr_name))
-        $this->raiseRequiredAttribute($attr_name);
-    }
-
-    if($this->tag_info->isRestrictSelfNesting() && $parent = $this->findParentByClass(get_class($this)))
-      $this->raise('Tag cannot be nested within the same tag',
-                                array('same_tag_file' => $parent->getTemplateFile(),
-                                      'same_tag_line' => $parent->getTemplateLine()));
-
-    if(($parent_class = $this->tag_info->getParentClass()) &&
-       !$parent = $this->findParentByClass($parent_class))
-    {
-      $this->raise('Tag must be enclosed by a proper parent tag',
-                                array('required_parent_tag_class' => $parent_class));
-
-    }
-  }  
-}
-?>
\ No newline at end of file
+class lmbMacroTag extends lmbMacroNode
+{
+  protected $tag;
+  protected $has_closing_tag = true;
+  protected $empty_closed_tag = false;  
+  protected $tag_info;
+  protected $attributes = array();
+  
+  function __construct($location, $tag, $tag_info)
+  {
+    $this->tag = $tag;
+    $this->tag_info = $tag_info;
+    
+    parent :: __construct($location);
+  }
+
+  function getTag()
+  {
+    return $this->tag;
+  }
+  
+  function getHasClosingTag()
+  {
+    return $this->has_closing_tag;
+  }
+  
+  function setHasClosingTag($flag)
+  {
+    return $this->has_closing_tag = $flag;
+  }  
+  
+  function getId()
+  {
+    if($this->id)
+      return $this->id;
+        
+    if($id = $this->get('id'))
+      $this->id = $id;
+    else
+      $this->id = self :: generateNewId();
+
+    return $this->id;
+  }  
+  
+  function get($name)
+  {
+    if(array_key_exists(strtolower($name), $this->attributes))
+      return $this->attributes[strtolower($name)];
+  }  
+  
+  function set($name, $value)
+  {
+    $this->attributes[strtolower($name)] = $value;
+  }
+
+  function has($name)
+  {
+    return array_key_exists(strtolower($name), $this->attributes);
+  }
+
+  /**
+  * Return the value of a boolean attribute as a boolean.
+  * ATTRIBUTE=ANYTHING  (true)
+  * ATTRIBUTE=(false|N|NA|NO|NONE|0) (false)
+  * ATTRIBUTE (true)
+  * (attribute unspecified) (default)
+  */
+  function getBool($attrib, $default = false)
+  {
+    if(!isset($this->attributes[strtolower($attrib)]))
+      return $default;
+
+    return self :: getBooleanValue($this->attributes[strtolower($attrib)]);
+  }
+
+  static function getBooleanValue($value)
+  {
+    switch(strtoupper($value))
+    {
+      case 'FALSE':
+      case 'N':
+      case 'NO':
+      case 'NONE':
+      case 'NA':
+      case '0':
+        return false;
+      default:
+        return true;
+    }
+  }
+
+  function remove($attrib)
+  {
+    unset($this->attributes[strtolower($attrib)]);
+  }  
+    
+  function raise($error, $vars = array())
+  {
+    $vars['tag'] = $this->tag;
+    parent :: raise($error, $vars);
+  }  
+
+  function raiseRequiredAttribute($attribute_name)
+  {
+    $this->raise('Missing required attribute', array('attribute' => $attribute_name));
+  }
+  
+  function preParse()
+  {
+    foreach($this->tag_info->getRequiredAttributes() as $attr_name)
+    {
+      if(!$this->has($attr_name))
+        $this->raiseRequiredAttribute($attr_name);
+    }
+
+    if($this->tag_info->isRestrictSelfNesting() && $parent = $this->findParentByClass(get_class($this)))
+      $this->raise('Tag cannot be nested within the same tag',
+                                array('same_tag_file' => $parent->getTemplateFile(),
+                                      'same_tag_line' => $parent->getTemplateLine()));
+
+    if(($parent_class = $this->tag_info->getParentClass()) &&
+       !$parent = $this->findParentByClass($parent_class))
+    {
+      $this->raise('Tag must be enclosed by a proper parent tag',
+                                array('required_parent_tag_class' => $parent_class));
+
+    }
+  }  
+}
+?>

Modified: 3.x/trunk/limb/macro/src/lmbMacroTagDictionary.class.php
===================================================================
--- 3.x/trunk/limb/macro/src/lmbMacroTagDictionary.class.php	2007-08-03 10:25:31 UTC (rev 6211)
+++ 3.x/trunk/limb/macro/src/lmbMacroTagDictionary.class.php	2007-08-03 19:42:40 UTC (rev 6212)
@@ -1,40 +1,40 @@
-<?php
+<?php
 /*
  * Limb PHP Framework
  *
  * @link http://limb-project.com 
  * @copyright  Copyright &copy; 2004-2007 BIT(http://bit-creative.com)
  * @license    LGPL http://www.gnu.org/copyleft/lesser.html 
- */
-
+ */
+
 lmb_require('limb/macro/src/lmbMacroTagInfo.class.php');
 
-/**
- * class lmbMacroTagDictionary.
- *
- * @package macro
- * @version $Id$
+/**
+ * class lmbMacroTagDictionary.
+ *
+ * @package macro
+ * @version $Id$
  */
-class lmbMacroTagDictionary
-{
-  protected $info = array();
-
-  function register($taginfo, $file)
-  {
-    $tag_to_lower = strtolower($taginfo->getTag());
-
-    if(isset($this->info[$tag_to_lower]))
-      return;
-
-    $taginfo->setFile($file);
-    $this->info[$tag_to_lower] = $taginfo;
-  }
-
-  function findTagInfo($tag)
-  {
-    $tag = strtolower($tag);
-    if(isset($this->info[$tag]))
-      return $this->info[$tag];
-  }
-}
-?>
\ No newline at end of file
+class lmbMacroTagDictionary
+{
+  protected $info = array();
+
+  function register($taginfo, $file)
+  {
+    $tag_to_lower = strtolower($taginfo->getTag());
+
+    if(isset($this->info[$tag_to_lower]))
+      return;
+
+    $taginfo->setFile($file);
+    $this->info[$tag_to_lower] = $taginfo;
+  }
+
+  function findTagInfo($tag)
+  {
+    $tag = strtolower($tag);
+    if(isset($this->info[$tag]))
+      return $this->info[$tag];
+  }
+}
+?>

Modified: 3.x/trunk/limb/macro/src/lmbMacroTagInfo.class.php
===================================================================
--- 3.x/trunk/limb/macro/src/lmbMacroTagInfo.class.php	2007-08-03 10:25:31 UTC (rev 6211)
+++ 3.x/trunk/limb/macro/src/lmbMacroTagInfo.class.php	2007-08-03 19:42:40 UTC (rev 6212)
@@ -1,4 +1,4 @@
-<?php
+<?php
 /*
  * Limb PHP Framework
  *
@@ -7,93 +7,93 @@
  * @license    LGPL http://www.gnu.org/copyleft/lesser.html 
  */
 
-/**
- * class lmbMacroTagInfo.
- *
- * @package macro
- * @version $Id$
+/**
+ * class lmbMacroTagInfo.
+ *
+ * @package macro
+ * @version $Id$
  */
-class lmbMacroTagInfo
-{
-  protected $tag = '';
-  protected $class = '';
-  protected $file;
-  protected $req_attributes = array();
-  protected $parent_class;
-  protected $restrict_self_nesting = false;
-  protected $forbid_parsing = false;
-  protected $forbid_endtag = false;
-
-  function __construct($tag, $class)
-  {
-    $this->tag = $tag;
-    $this->class = $class;
-  }
-  
-  function getTag()
-  {
-    return $this->tag;
-  }
-  
-  function setFile($file)
-  {
-    $this->file = $file;
-  }
-
-  function setForbidEndtag($flag = true)
-  {
-    $this->forbid_endtag = $flag;
-  }
-
-  function isEndtagForbidden()
-  {
-    return $this->forbid_endtag;
-  }
-
-  function setRequiredAttributes($attributes)
-  {
-    $this->req_attributes = $attributes;
-  }
-
-  function getRequiredAttributes()
-  {
-    return $this->req_attributes;
-  }
-
-  function setParentClass($parent_tag_class)
-  {
-    $this->parent_class = $parent_tag_class;
-  }
-
-  function getParentClass()
-  {
-    return $this->parent_class;
-  }
-
-  function setRestrictSelfNesting($flag = true)
-  {
-    $this->restrict_self_nesting = $flag;
-  }
-
-  function isRestrictSelfNesting()
-  {
-    return $this->restrict_self_nesting;
-  }
-
-  function setForbidParsing($flag = true)
-  {
-    $this->forbid_parsing = $flag;
-  }
-
-  function isParsingForbidden()
-  {
-    return $this->forbid_parsing;
-  }
-
-  function load()
-  {
-    if(!class_exists($this->class) && isset($this->file))
-      require_once($this->file);
-  }
-}
-?>
\ No newline at end of file
+class lmbMacroTagInfo
+{
+  protected $tag = '';
+  protected $class = '';
+  protected $file;
+  protected $req_attributes = array();
+  protected $parent_class;
+  protected $restrict_self_nesting = false;
+  protected $forbid_parsing = false;
+  protected $forbid_endtag = false;
+
+  function __construct($tag, $class)
+  {
+    $this->tag = $tag;
+    $this->class = $class;
+  }
+  
+  function getTag()
+  {
+    return $this->tag;
+  }
+  
+  function setFile($file)
+  {
+    $this->file = $file;
+  }
+
+  function setForbidEndtag($flag = true)
+  {
+    $this->forbid_endtag = $flag;
+  }
+
+  function isEndtagForbidden()
+  {
+    return $this->forbid_endtag;
+  }
+
+  function setRequiredAttributes($attributes)
+  {
+    $this->req_attributes = $attributes;
+  }
+
+  function getRequiredAttributes()
+  {
+    return $this->req_attributes;
+  }
+
+  function setParentClass($parent_tag_class)
+  {
+    $this->parent_class = $parent_tag_class;
+  }
+
+  function getParentClass()
+  {
+    return $this->parent_class;
+  }
+
+  function setRestrictSelfNesting($flag = true)
+  {
+    $this->restrict_self_nesting = $flag;
+  }
+
+  function isRestrictSelfNesting()
+  {
+    return $this->restrict_self_nesting;
+  }
+
+  function setForbidParsing($flag = true)
+  {
+    $this->forbid_parsing = $flag;
+  }
+
+  function isParsingForbidden()
+  {
+    return $this->forbid_parsing;
+  }
+
+  function load()
+  {
+    if(!class_exists($this->class) && isset($this->file))
+      require_once($this->file);
+  }
+}
+?>

Modified: 3.x/trunk/limb/macro/src/lmbMacroTagParsingState.class.php
===================================================================
--- 3.x/trunk/limb/macro/src/lmbMacroTagParsingState.class.php	2007-08-03 10:25:31 UTC (rev 6211)
+++ 3.x/trunk/limb/macro/src/lmbMacroTagParsingState.class.php	2007-08-03 19:42:40 UTC (rev 6212)
@@ -1,143 +1,143 @@
-<?php
+<?php
 /*
  * Limb PHP Framework
  *
  * @link http://limb-project.com 
  * @copyright  Copyright &copy; 2004-2007 BIT(http://bit-creative.com)
  * @license    LGPL http://www.gnu.org/copyleft/lesser.html 
- */
-
-lmb_require('limb/macro/src/lmbMacroTokenizerListener.interface.php');
+ */
+
+lmb_require('limb/macro/src/lmbMacroTokenizerListener.interface.php');
 lmb_require('limb/macro/src/lmbMacroBaseParsingState.class.php');
 
-/**
- * class lmbMacroTagParsingState.
- *
- * @package macro
- * @version $Id$
+/**
+ * class lmbMacroTagParsingState.
+ *
+ * @package macro
+ * @version $Id$
  */
-class lmbMacroTagParsingState extends lmbMacroBaseParsingState implements lmbMacroTokenizerListener
-{
-  protected $tag_dictionary;
-
-  function __construct($parser, $tree_builder, $tag_dictionary)
-  {
-    parent :: __construct($parser, $tree_builder);
-    $this->tag_dictionary = $tag_dictionary;
-  }
-
-  function startElement($tag, $attrs)
-  {
-    $location = $this->locator->getCurrentLocation();
-
-    $lower_attributes = $this->normalizeAttributes($attrs, $location);
-
-    $tag_info = $this->tag_dictionary->findTagInfo($tag);
-
-    if($tag_info->isEndTagForbidden())
-    {
-      $tag_node = $this->buildTagNode($tag_info, $tag, $attrs, $self_closed_tag = true);
-      $tag_node->setHasClosingTag(false);
-      $this->tree_builder->pushNode($tag_node); // for cases like <%include%> we do pushNode() and popNode() here.
-      $this->tree_builder->popNode();      
-    }
-    else
-    {
-      $this->tree_builder->pushExpectedTag($tag, $location);
-      $tag_node = $this->buildTagNode($tag_info, $tag, $attrs, $self_closed_tag = false);
-      $result = $this->tree_builder->pushNode($tag_node);
-    }
-  }
-
-  function endElement($tag)
-  {
-    $tag_info = $this->tag_dictionary->getTagInfo($tag);
-    $location = $this->locator->getCurrentLocation();
-
-    if($tag_info->isEndTagForbidden())
-    {
-      throw new lmbMacroException('Closing tag forbidden',
-                              array('tag' => $tag_info->getTag(),
-                                    'file' => $location->getFile(),
-                                    'line' => $location->getLine()));
-    }
-
-    $this->tree_builder->popExpectedTag($tag, $location);
-    $this->tree_builder->popNode();
-  }
-
-  function emptyElement($tag, $attrs)
-  {
-    $location = $this->locator->getCurrentLocation();
-    $lower_attributes = $this->normalizeAttributes($attrs, $location);
-
-    $tag_info = $this->tag_dictionary->findTagInfo($tag);
-    $tag_info->load();
-
-    $tag_node = $this->buildTagNode($tag_info, $tag, $attrs, $self_closed_tag = true);
-    $tag_node->setHasClosingTag(false);
-    $this->tree_builder->pushNode($tag_node); // for cases like <%include%> we do pushNode() and popNode() here.
-    $this->tree_builder->popNode();
-  }
-  
-  /**
-  * Builds a component, adding attributes
-  * @param lmbMacroTagInfo
-  * @param string XML tag name of component
-  * @param array attributes for tag
-  * @param boolean whether the tag has contents
-  * @return lmbMacroNode
-  */
-  function buildTagNode($tag_info, $tag, $attrs, $isEmpty)
-  {
-    $tag_node = $this->_createTagNode($tag_info, $tag);
-    $tag_node->emptyClosedTag = $isEmpty;
-    $this->_addAttributesToTagNode($tag_node, $attrs);
-    return $tag_node;
-  }    
-  
-  protected function _addAttributesToTagNode($tag_node, $attrs)
-  {
-    foreach($attrs as $name => $value)
-    {
-      if($value === null)
-      {
-        $location = $this->locator->getCurrentLocation();
-        throw new lmbMacroException('Attribute should have a value',
-                              array('file' => $location->getFile(),
-                                    'line' => $location->getLine(),
-                                    'tag' => $tag_node->getTag(),
-                                    'attribute' => $name));
-      }
-      $tag_node->set($name, $value);
-    }
-  }  
-  
-  protected function _createTagNode($tag_info, $tag)
-  {
-    $class = $tag_info->getClass();
-    $tag_node = new $class($this->locator->getCurrentLocation(), $tag, $tag_info);
-    return $tag_node;
-  }    
-
-  function normalizeAttributes($attrs)
-  {
-    return array_change_key_case($attrs, CASE_LOWER);    
-  }
-
-  function characters($text)
-  {
-    $this->tree_builder->addTextNode($text);
-  }
-
-  function unexpectedEOF($text)
-  {
-    $this->tree_builder->addTextNode($text);
-  }
-
-  function invalidEntitySyntax($text)
-  {
-    $this->tree_builder->addTextNode($text);
-  }
-}
-?>
\ No newline at end of file
+class lmbMacroTagParsingState extends lmbMacroBaseParsingState implements lmbMacroTokenizerListener
+{
+  protected $tag_dictionary;
+
+  function __construct($parser, $tree_builder, $tag_dictionary)
+  {
+    parent :: __construct($parser, $tree_builder);
+    $this->tag_dictionary = $tag_dictionary;
+  }
+
+  function startElement($tag, $attrs)
+  {
+    $location = $this->locator->getCurrentLocation();
+
+    $lower_attributes = $this->normalizeAttributes($attrs, $location);
+
+    $tag_info = $this->tag_dictionary->findTagInfo($tag);
+
+    if($tag_info->isEndTagForbidden())
+    {
+      $tag_node = $this->buildTagNode($tag_info, $tag, $attrs, $self_closed_tag = true);
+      $tag_node->setHasClosingTag(false);
+      $this->tree_builder->pushNode($tag_node); // for cases like <%include%> we do pushNode() and popNode() here.
+      $this->tree_builder->popNode();      
+    }
+    else
+    {
+      $this->tree_builder->pushExpectedTag($tag, $location);
+      $tag_node = $this->buildTagNode($tag_info, $tag, $attrs, $self_closed_tag = false);
+      $result = $this->tree_builder->pushNode($tag_node);
+    }
+  }
+
+  function endElement($tag)
+  {
+    $tag_info = $this->tag_dictionary->getTagInfo($tag);
+    $location = $this->locator->getCurrentLocation();
+
+    if($tag_info->isEndTagForbidden())
+    {
+      throw new lmbMacroException('Closing tag forbidden',
+                              array('tag' => $tag_info->getTag(),
+                                    'file' => $location->getFile(),
+                                    'line' => $location->getLine()));
+    }
+
+    $this->tree_builder->popExpectedTag($tag, $location);
+    $this->tree_builder->popNode();
+  }
+
+  function emptyElement($tag, $attrs)
+  {
+    $location = $this->locator->getCurrentLocation();
+    $lower_attributes = $this->normalizeAttributes($attrs, $location);
+
+    $tag_info = $this->tag_dictionary->findTagInfo($tag);
+    $tag_info->load();
+
+    $tag_node = $this->buildTagNode($tag_info, $tag, $attrs, $self_closed_tag = true);
+    $tag_node->setHasClosingTag(false);
+    $this->tree_builder->pushNode($tag_node); // for cases like <%include%> we do pushNode() and popNode() here.
+    $this->tree_builder->popNode();
+  }
+  
+  /**
+  * Builds a component, adding attributes
+  * @param lmbMacroTagInfo
+  * @param string XML tag name of component
+  * @param array attributes for tag
+  * @param boolean whether the tag has contents
+  * @return lmbMacroNode
+  */
+  function buildTagNode($tag_info, $tag, $attrs, $isEmpty)
+  {
+    $tag_node = $this->_createTagNode($tag_info, $tag);
+    $tag_node->emptyClosedTag = $isEmpty;
+    $this->_addAttributesToTagNode($tag_node, $attrs);
+    return $tag_node;
+  }    
+  
+  protected function _addAttributesToTagNode($tag_node, $attrs)
+  {
+    foreach($attrs as $name => $value)
+    {
+      if($value === null)
+      {
+        $location = $this->locator->getCurrentLocation();
+        throw new lmbMacroException('Attribute should have a value',
+                              array('file' => $location->getFile(),
+                                    'line' => $location->getLine(),
+                                    'tag' => $tag_node->getTag(),
+                                    'attribute' => $name));
+      }
+      $tag_node->set($name, $value);
+    }
+  }  
+  
+  protected function _createTagNode($tag_info, $tag)
+  {
+    $class = $tag_info->getClass();
+    $tag_node = new $class($this->locator->getCurrentLocation(), $tag, $tag_info);
+    return $tag_node;
+  }    
+
+  function normalizeAttributes($attrs)
+  {
+    return array_change_key_case($attrs, CASE_LOWER);    
+  }
+
+  function characters($text)
+  {
+    $this->tree_builder->addTextNode($text);
+  }
+
+  function unexpectedEOF($text)
+  {
+    $this->tree_builder->addTextNode($text);
+  }
+
+  function invalidEntitySyntax($text)
+  {
+    $this->tree_builder->addTextNode($text);
+  }
+}
+?>

Modified: 3.x/trunk/limb/macro/src/lmbMacroTemplate.class.php
===================================================================
--- 3.x/trunk/limb/macro/src/lmbMacroTemplate.class.php	2007-08-03 10:25:31 UTC (rev 6211)
+++ 3.x/trunk/limb/macro/src/lmbMacroTemplate.class.php	2007-08-03 19:42:40 UTC (rev 6212)
@@ -1,4 +1,4 @@
-<?php
+<?php
 /*
  * Limb PHP Framework
  *
@@ -7,126 +7,126 @@
  * @license    LGPL http://www.gnu.org/copyleft/lesser.html 
  */
 
-/**
- * class lmbMacroTemplate.
- *
- * @package macro
- * @version $Id$
+/**
+ * class lmbMacroTemplate.
+ *
+ * @package macro
+ * @version $Id$
  */
-class lmbMacroTemplate
-{
-  protected $file;
-  protected $cache_dir;
-  protected $vars = array();
-  protected $includes = array();
-
-  function __construct($file, $cache_dir)
-  {
-    $this->file = $file;
-    $this->cache_dir = $cache_dir;
-  }
-
-  function set($name, $value)
-  {
-    $this->vars[$name] = $value;
-  }
-
-  function render()
-  {
-    ob_start();
-    $file = $this->_compile($class);
-    include($file);
-    $body = new $class($this->vars);
-    $body->paint();
-    $out = ob_get_contents();
-    ob_end_clean();
-    return $out;
-  }
-
-  protected function _compile(&$class_name)
-  {
-    $contents = file_get_contents($this->file);
-    $prefix = 'p' . md5($this->file);
-    $class_name = "{$prefix}Body";
-    
-    $this->_processVars($contents);
-    $body = $this->_generateBody($class_name, $contents);
-
-    $compiled_file = $this->cache_dir . '/' . $prefix . '.php';
-    file_put_contents($compiled_file, $body, LOCK_EX);
-    return $compiled_file;
-  }
-
-  protected function _generateBody($class_name, $contents)
-  {
-    $include_methods = '';
-    foreach($this->includes as $name => $body)
-      $include_methods .= "$body\n";
-
-    $code = <<<EOD
-<?php
-class {$class_name}
-{
-  protected \$vars = array();
-
-  function __construct(\$vars)
-  {
-    \$this->vars = \$vars;
-  }
-
-  function __get(\$name)
-  {
-    if(isset(\$this->vars[\$name]))
-      return \$this->vars[\$name];
-  }
-
-  $include_methods
-
-  function paint(){ ?>$contents<?php }
-}
-?>
-EOD;
-  return $code;
-  }
-
-  protected function _processVars(&$contents)
-  {
-    $contents = str_replace('<?=', '<?php echo ', $contents);
-    $contents = preg_replace('~<\?(?!php|=)~', '<?php ', $contents);    
-    $contents = str_replace('@$', '$this->', $contents);
-    $contents = preg_replace_callback('~\{(\$[^\W]+)\}~', array($this, '_varSugarCallback'), $contents);
-    $contents = preg_replace_callback('~\{([^\W]+\([^\}]+)\}~', array($this, '_functionSugarCallback'), $contents);
-  }
-
-  protected function _varSugarCallback($matches)
-  {
-    return '<?php echo ' . $matches[1] . ' ?>';
-  }
-
-  protected function _functionSugarCallback($matches)
-  {
-    return '<?php echo ' . $matches[1] . ' ?>';
-  }
-
-  protected function _includeCallback($matches)
-  {
-    if(!preg_match('~file=(?:"|\')([^"\']+)(?:"|\')~', $matches[0], $m))
-      throw new lmbException('Invalid <%INCLUDE..>: ' . $matches[0]);
-
-    $file = lmbFs :: normalizePath($m[1]);
-
-    $args = '';
-    if(preg_match('~args=(?:"|\')\(([^\)]+)\)(?:"|\')~', $matches[0], $m))
-      $args = $m[1];
-
-    $contents = file_get_contents($file);
-    $this->_processIncludes($contents);
-    $method_name = 'paintInclude' . sizeof($this->includes);
-    $method_body = "function $method_name(){ \$args = func_get_args();extract(\$args);?>$contents<?php }";
-
-    $this->includes[$method_name] = $method_body;
-
-    return "<?php \$this->$method_name(array($args)); ?>";
-  }
-}
-?>
+class lmbMacroTemplate
+{
+  protected $file;
+  protected $cache_dir;
+  protected $vars = array();
+  protected $includes = array();
+
+  function __construct($file, $cache_dir)
+  {
+    $this->file = $file;
+    $this->cache_dir = $cache_dir;
+  }
+
+  function set($name, $value)
+  {
+    $this->vars[$name] = $value;
+  }
+
+  function render()
+  {
+    ob_start();
+    $file = $this->_compile($class);
+    include($file);
+    $body = new $class($this->vars);
+    $body->paint();
+    $out = ob_get_contents();
+    ob_end_clean();
+    return $out;
+  }
+
+  protected function _compile(&$class_name)
+  {
+    $contents = file_get_contents($this->file);
+    $prefix = 'p' . md5($this->file);
+    $class_name = "{$prefix}Body";
+    
+    $this->_processVars($contents);
+    $body = $this->_generateBody($class_name, $contents);
+
+    $compiled_file = $this->cache_dir . '/' . $prefix . '.php';
+    file_put_contents($compiled_file, $body, LOCK_EX);
+    return $compiled_file;
+  }
+
+  protected function _generateBody($class_name, $contents)
+  {
+    $include_methods = '';
+    foreach($this->includes as $name => $body)
+      $include_methods .= "$body\n";
+
+    $code = <<<EOD
+<?php
+class {$class_name}
+{
+  protected \$vars = array();
+
+  function __construct(\$vars)
+  {
+    \$this->vars = \$vars;
+  }
+
+  function __get(\$name)
+  {
+    if(isset(\$this->vars[\$name]))
+      return \$this->vars[\$name];
+  }
+
+  $include_methods
+
+  function paint(){ ?>$contents<?php }
+}
+?>
+EOD;
+  return $code;
+  }
+
+  protected function _processVars(&$contents)
+  {
+    $contents = str_replace('<?=', '<?php echo ', $contents);
+    $contents = preg_replace('~<\?(?!php|=)~', '<?php ', $contents);    
+    $contents = str_replace('@$', '$this->', $contents);
+    $contents = preg_replace_callback('~\{(\$[^\W]+)\}~', array($this, '_varSugarCallback'), $contents);
+    $contents = preg_replace_callback('~\{([^\W]+\([^\}]+)\}~', array($this, '_functionSugarCallback'), $contents);
+  }
+
+  protected function _varSugarCallback($matches)
+  {
+    return '<?php echo ' . $matches[1] . ' ?>';
+  }
+
+  protected function _functionSugarCallback($matches)
+  {
+    return '<?php echo ' . $matches[1] . ' ?>';
+  }
+
+  protected function _includeCallback($matches)
+  {
+    if(!preg_match('~file=(?:"|\')([^"\']+)(?:"|\')~', $matches[0], $m))
+      throw new lmbException('Invalid <%INCLUDE..>: ' . $matches[0]);
+
+    $file = lmbFs :: normalizePath($m[1]);
+
+    $args = '';
+    if(preg_match('~args=(?:"|\')\(([^\)]+)\)(?:"|\')~', $matches[0], $m))
+      $args = $m[1];
+
+    $contents = file_get_contents($file);
+    $this->_processIncludes($contents);
+    $method_name = 'paintInclude' . sizeof($this->includes);
+    $method_body = "function $method_name(){ \$args = func_get_args();extract(\$args);?>$contents<?php }";
+
+    $this->includes[$method_name] = $method_body;
+
+    return "<?php \$this->$method_name(array($args)); ?>";
+  }
+}
+?>

Modified: 3.x/trunk/limb/macro/src/lmbMacroTemplateLocator.class.php
===================================================================
--- 3.x/trunk/limb/macro/src/lmbMacroTemplateLocator.class.php	2007-08-03 10:25:31 UTC (rev 6211)
+++ 3.x/trunk/limb/macro/src/lmbMacroTemplateLocator.class.php	2007-08-03 19:42:40 UTC (rev 6212)
@@ -7,11 +7,11 @@
  * @license    LGPL http://www.gnu.org/copyleft/lesser.html 
  */
 
-/**
- * class lmbMacroTemplateLocator.
- *
- * @package macro
- * @version $Id$
+/**
+ * class lmbMacroTemplateLocator.
+ *
+ * @package macro
+ * @version $Id$
  */
 class lmbMacroTemplateLocator
 {
@@ -39,4 +39,4 @@
     return file_get_contents($file_name, 1);
   }
 }
-?>
\ No newline at end of file
+?>

Modified: 3.x/trunk/limb/macro/src/lmbMacroTextNode.class.php
===================================================================
--- 3.x/trunk/limb/macro/src/lmbMacroTextNode.class.php	2007-08-03 10:25:31 UTC (rev 6211)
+++ 3.x/trunk/limb/macro/src/lmbMacroTextNode.class.php	2007-08-03 19:42:40 UTC (rev 6212)
@@ -1,4 +1,4 @@
-<?php
+<?php
 /*
  * Limb PHP Framework
  *
@@ -7,32 +7,32 @@
  * @license    LGPL http://www.gnu.org/copyleft/lesser.html 
  */
 
-/**
- * class lmbMacroTextNode.
- *
- * @package macro
- * @version $Id$
+/**
+ * class lmbMacroTextNode.
+ *
+ * @package macro
+ * @version $Id$
  */
-class lmbMacroTextNode extends lmbMacroNode
-{
-  protected $contents;
-
-  function __construct($location, $text)
-  {
-    parent :: __construct($location);
-    $this->contents = $text;
-  }
-
-  function generateContents($code_writer)
-  {
-    $code_writer->writeRaw($this->contents);
-    parent :: generateContents($code_writer);
-  }
-
-  function getText()
-  {
-    return $this->contents;
-  }
-}
-
-?>
\ No newline at end of file
+class lmbMacroTextNode extends lmbMacroNode
+{
+  protected $contents;
+
+  function __construct($location, $text)
+  {
+    parent :: __construct($location);
+    $this->contents = $text;
+  }
+
+  function generateContents($code_writer)
+  {
+    $code_writer->writeRaw($this->contents);
+    parent :: generateContents($code_writer);
+  }
+
+  function getText()
+  {
+    return $this->contents;
+  }
+}
+
+?>

Modified: 3.x/trunk/limb/macro/src/lmbMacroTokenizer.class.php
===================================================================
--- 3.x/trunk/limb/macro/src/lmbMacroTokenizer.class.php	2007-08-03 10:25:31 UTC (rev 6211)
+++ 3.x/trunk/limb/macro/src/lmbMacroTokenizer.class.php	2007-08-03 19:42:40 UTC (rev 6212)
@@ -1,4 +1,4 @@
-<?php
+<?php
 /*
  * Limb PHP Framework
  *
@@ -7,252 +7,252 @@
  * @license    LGPL http://www.gnu.org/copyleft/lesser.html 
  */
 
-/**
- * class lmbMacroTokenizer.
- *
- * @package macro
- * @version $Id$
+/**
+ * class lmbMacroTokenizer.
+ *
+ * @package macro
+ * @version $Id$
  */
-class lmbMacroTokenizer
-{
-  protected $publicId;
-  protected $observer;
-  protected $rawtext;
-  protected $position;
-  protected $length;
-
-  function __construct($observer)
-  {
-    $this->observer = $observer;
-  }
-
-  function getLineNumber()
-  {
-    return 1 + substr_count(substr($this->rawtext, 0, $this->position), "\n");
-  }
-
-  function getCurrentLocation()
-  {
-    return new lmbMacroSourceLocation($this->getPublicId(), $this->getLineNumber());
-  }
-
-  function getPublicId()
-  {
-    return $this->publicId;
-  }
-
-  /**
-  * Moves the position forward past any whitespace characters
-  */
-  function ignoreWhitespace()
-  {
-    while($this->position < $this->length &&
-        strpos(" \n\r\t", $this->rawtext{$this->position}) !== false)
-      $this->position++;
-  }
-
-  /**
-  * Begins the parsing operation, setting up any decorators, depending on
-  * parse options invoking _parse() to execute parsing
-  */
-  function parse($data, $publicId = null)
-  {
-    $this->rawtext = $data;
-    $this->length = strlen($data);
-    $this->position = 0;
-    $this->publicId = $publicId;
-
-    do
-    {
-      $start = $this->position;
-      $this->position = strpos($this->rawtext, '<%', $start);
-      if($this->position === false)
-      {
-        if($start < $this->length)
-          $this->observer->characters(substr($this->rawtext, $start));
-        return;
-      }
-
-      if($this->position > $start)
-      {
-        $this->observer->characters(substr($this->rawtext, $start, $this->position - $start));
-      }
-
-      $this->position += 2;   // ignore '<%' string
-      if($this->position >= $this->length)
-      {
-        $this->observer->unexpectedEOF('<%');
-        return;
-      }
-
-      $element_pos = $this->position;
-      $this->position += 1;
-
-      switch($this->rawtext{$element_pos})
-      {
-        case '/':
-          $start = $this->position;
-          while($this->position < $this->length &&
-                $this->rawtext{$this->position} != '%' &&
-                $this->rawtext{$this->position+1} != '>')
-            $this->position++;
-
-          if($this->position >= $this->length)
-          {
-            $this->observer->unexpectedEOF(substr($this->rawtext, $element_pos - 1));
-            return;
-          }
-
-          $tag = substr($this->rawtext, $start, $this->position - $start);
-
-          $this->observer->endElement($tag);
-          $this->position += 2;   // ignore '%>' string
-          break;
-
-      default:
-          while($this->position < $this->length && strpos("%/ \n\r\t", $this->rawtext{$this->position}) === false)
-            $this->position++;
-
-          if($this->position >= $this->length)
-          {
-            $this->observer->unexpectedEOF(substr($this->rawtext, $element_pos - 1));
-            return;
-          }
-
-          $tag = substr($this->rawtext, $element_pos, $this->position - $element_pos);
-          $attributes = array();
-
-          $this->ignoreWhitespace();
-
-          //tag attributes
-          while($this->position < $this->length &&
-                $this->rawtext{$this->position} != '%' &&
-                $this->rawtext{$this->position} != '/')
-          {
-            $start = $this->position;
-            while($this->position < $this->length && strpos("%= \n\r\t", $this->rawtext{$this->position}) === false)
-              $this->position++;
-
-            if($this->position >= $this->length)
-            {
-              $this->observer->unexpectedEOF(substr($this->rawtext, $element_pos - 1));
-              return;
-            }
-
-            $attribute_name = substr($this->rawtext, $start, $this->position - $start);
-            $attribute_value = null;
-
-            $this->ignoreWhitespace();
-            if($this->position >= $this->length)
-            {
-              $this->observer->unexpectedEOF(substr($this->rawtext, $element_pos - 1));
-              return;
-            }
-
-            if($this->rawtext{$this->position} == '=')
-            {
-              $attribute_value = "";
-
-              $this->position++;
-              $this->ignoreWhitespace();
-              if($this->position >= $this->length)
-              {
-                $this->observer->unexpectedEOF(substr($this->rawtext, $element_pos - 1));
-                return;
-              }
-
-              $quote = $this->rawtext{$this->position};
-              if($quote == '"' || $quote == "'")
-              {
-                $start = $this->position + 1;
-                $this->position = strpos($this->rawtext, $quote, $start);
-                if($this->position === false)
-                {
-                  $this->observer->unexpectedEOF(substr($this->rawtext, $element_pos - 1));
-                  return;
-                }
-
-                $attribute_value = substr($this->rawtext, $start, $this->position - $start);
-
-                $this->position++;
-                if($this->position >= $this->length)
-                {
-                  $this->observer->unexpectedEOF(substr($this->rawtext, $element_pos - 1));
-                  return;
-                }
-
-                if(strpos("% \n\r\t", $this->rawtext{$this->position}) === false)
-                  $this->observer->invalidAttributeSyntax();
-
-              }
-              else
-              {
-                $start = $this->position;
-                while($this->position < $this->length && strpos("% \n\r\t", $this->rawtext{$this->position}) === false)
-                  $this->position++;
-
-                if($this->position >= $this->length)
-                {
-                  $this->observer->unexpectedEOF(substr($this->rawtext, $element_pos - 1));
-                  return;
-                }
-                $attribute_value = substr($this->rawtext, $start, $this->position - $start);
-              }
-            }
-
-            $attributes[$attribute_name] = $attribute_value;
-
-            $this->ignoreWhitespace();
-          }
-
-          if($this->position >= $this->length)
-          {
-            $this->observer->unexpectedEOF(substr($this->rawtext, $element_pos - 1));
-            return;
-          }
-
-          //self closing tag check
-          if($this->rawtext{$this->position} == '/' && $this->rawtext{$this->position + 1} == '%')
-          {
-            $this->position += 2;
-            if($this->position >= $this->length)
-            {
-              $this->observer->unexpectedEOF(substr($this->rawtext, $element_pos - 1));
-              return;
-            }
-
-            if($this->rawtext{$this->position} != '>')
-            {
-              $start = $this->position;
-              while($this->position < $this->length && $this->rawtext{$this->position} != '>')
-                $this->position++;
-
-              if($this->position >= $this->length)
-              {
-                $this->observer->invalidEntitySyntax(substr($this->rawtext, $element_pos - 2));
-                break;
-              }
-
-              $this->observer->invalidEntitySyntax(substr($this->rawtext, $element_pos - 2,
-                                                          $this->position - $element_pos + 2));
-              $this->position += 1;
-              break;
-            }
-            $this->observer->emptyElement($tag, $attributes);
-          }
-          else
-          {
-            $this->observer->startElement($tag, $attributes);
-            //skipping %
-            $this->position += 1;
-          }
-
-          $this->position += 1;
-
-          break;
-        }
-    }
-    while ($this->position < $this->length);
-  }
-}
-?>
+class lmbMacroTokenizer
+{
+  protected $publicId;
+  protected $observer;
+  protected $rawtext;
+  protected $position;
+  protected $length;
+
+  function __construct($observer)
+  {
+    $this->observer = $observer;
+  }
+
+  function getLineNumber()
+  {
+    return 1 + substr_count(substr($this->rawtext, 0, $this->position), "\n");
+  }
+
+  function getCurrentLocation()
+  {
+    return new lmbMacroSourceLocation($this->getPublicId(), $this->getLineNumber());
+  }
+
+  function getPublicId()
+  {
+    return $this->publicId;
+  }
+
+  /**
+  * Moves the position forward past any whitespace characters
+  */
+  function ignoreWhitespace()
+  {
+    while($this->position < $this->length &&
+        strpos(" \n\r\t", $this->rawtext{$this->position}) !== false)
+      $this->position++;
+  }
+
+  /**
+  * Begins the parsing operation, setting up any decorators, depending on
+  * parse options invoking _parse() to execute parsing
+  */
+  function parse($data, $publicId = null)
+  {
+    $this->rawtext = $data;
+    $this->length = strlen($data);
+    $this->position = 0;
+    $this->publicId = $publicId;
+
+    do
+    {
+      $start = $this->position;
+      $this->position = strpos($this->rawtext, '<%', $start);
+      if($this->position === false)
+      {
+        if($start < $this->length)
+          $this->observer->characters(substr($this->rawtext, $start));
+        return;
+      }
+
+      if($this->position > $start)
+      {
+        $this->observer->characters(substr($this->rawtext, $start, $this->position - $start));
+      }
+
+      $this->position += 2;   // ignore '<%' string
+      if($this->position >= $this->length)
+      {
+        $this->observer->unexpectedEOF('<%');
+        return;
+      }
+
+      $element_pos = $this->position;
+      $this->position += 1;
+
+      switch($this->rawtext{$element_pos})
+      {
+        case '/':
+          $start = $this->position;
+          while($this->position < $this->length &&
+                $this->rawtext{$this->position} != '%' &&
+                $this->rawtext{$this->position+1} != '>')
+            $this->position++;
+
+          if($this->position >= $this->length)
+          {
+            $this->observer->unexpectedEOF(substr($this->rawtext, $element_pos - 1));
+            return;
+          }
+
+          $tag = substr($this->rawtext, $start, $this->position - $start);
+
+          $this->observer->endElement($tag);
+          $this->position += 2;   // ignore '%>' string
+          break;
+
+      default:
+          while($this->position < $this->length && strpos("%/ \n\r\t", $this->rawtext{$this->position}) === false)
+            $this->position++;
+
+          if($this->position >= $this->length)
+          {
+            $this->observer->unexpectedEOF(substr($this->rawtext, $element_pos - 1));
+            return;
+          }
+
+          $tag = substr($this->rawtext, $element_pos, $this->position - $element_pos);
+          $attributes = array();
+
+          $this->ignoreWhitespace();
+
+          //tag attributes
+          while($this->position < $this->length &&
+                $this->rawtext{$this->position} != '%' &&
+                $this->rawtext{$this->position} != '/')
+          {
+            $start = $this->position;
+            while($this->position < $this->length && strpos("%= \n\r\t", $this->rawtext{$this->position}) === false)
+              $this->position++;
+
+            if($this->position >= $this->length)
+            {
+              $this->observer->unexpectedEOF(substr($this->rawtext, $element_pos - 1));
+              return;
+            }
+
+            $attribute_name = substr($this->rawtext, $start, $this->position - $start);
+            $attribute_value = null;
+
+            $this->ignoreWhitespace();
+            if($this->position >= $this->length)
+            {
+              $this->observer->unexpectedEOF(substr($this->rawtext, $element_pos - 1));
+              return;
+            }
+
+            if($this->rawtext{$this->position} == '=')
+            {
+              $attribute_value = "";
+
+              $this->position++;
+              $this->ignoreWhitespace();
+              if($this->position >= $this->length)
+              {
+                $this->observer->unexpectedEOF(substr($this->rawtext, $element_pos - 1));
+                return;
+              }
+
+              $quote = $this->rawtext{$this->position};
+              if($quote == '"' || $quote == "'")
+              {
+                $start = $this->position + 1;
+                $this->position = strpos($this->rawtext, $quote, $start);
+                if($this->position === false)
+                {
+                  $this->observer->unexpectedEOF(substr($this->rawtext, $element_pos - 1));
+                  return;
+                }
+
+                $attribute_value = substr($this->rawtext, $start, $this->position - $start);
+
+                $this->position++;
+                if($this->position >= $this->length)
+                {
+                  $this->observer->unexpectedEOF(substr($this->rawtext, $element_pos - 1));
+                  return;
+                }
+
+                if(strpos("% \n\r\t", $this->rawtext{$this->position}) === false)
+                  $this->observer->invalidAttributeSyntax();
+
+              }
+              else
+              {
+                $start = $this->position;
+                while($this->position < $this->length && strpos("% \n\r\t", $this->rawtext{$this->position}) === false)
+                  $this->position++;
+
+                if($this->position >= $this->length)
+                {
+                  $this->observer->unexpectedEOF(substr($this->rawtext, $element_pos - 1));
+                  return;
+                }
+                $attribute_value = substr($this->rawtext, $start, $this->position - $start);
+              }
+            }
+
+            $attributes[$attribute_name] = $attribute_value;
+
+            $this->ignoreWhitespace();
+          }
+
+          if($this->position >= $this->length)
+          {
+            $this->observer->unexpectedEOF(substr($this->rawtext, $element_pos - 1));
+            return;
+          }
+
+          //self closing tag check
+          if($this->rawtext{$this->position} == '/' && $this->rawtext{$this->position + 1} == '%')
+          {
+            $this->position += 2;
+            if($this->position >= $this->length)
+            {
+              $this->observer->unexpectedEOF(substr($this->rawtext, $element_pos - 1));
+              return;
+            }
+
+            if($this->rawtext{$this->position} != '>')
+            {
+              $start = $this->position;
+              while($this->position < $this->length && $this->rawtext{$this->position} != '>')
+                $this->position++;
+
+              if($this->position >= $this->length)
+              {
+                $this->observer->invalidEntitySyntax(substr($this->rawtext, $element_pos - 2));
+                break;
+              }
+
+              $this->observer->invalidEntitySyntax(substr($this->rawtext, $element_pos - 2,
+                                                          $this->position - $element_pos + 2));
+              $this->position += 1;
+              break;
+            }
+            $this->observer->emptyElement($tag, $attributes);
+          }
+          else
+          {
+            $this->observer->startElement($tag, $attributes);
+            //skipping %
+            $this->position += 1;
+          }
+
+          $this->position += 1;
+
+          break;
+        }
+    }
+    while ($this->position < $this->length);
+  }
+}
+?>

Modified: 3.x/trunk/limb/macro/src/lmbMacroTokenizerListener.interface.php
===================================================================
--- 3.x/trunk/limb/macro/src/lmbMacroTokenizerListener.interface.php	2007-08-03 10:25:31 UTC (rev 6211)
+++ 3.x/trunk/limb/macro/src/lmbMacroTokenizerListener.interface.php	2007-08-03 19:42:40 UTC (rev 6212)
@@ -1,4 +1,4 @@
-<?php
+<?php
 /*
  * Limb PHP Framework
  *
@@ -7,21 +7,21 @@
  * @license    LGPL http://www.gnu.org/copyleft/lesser.html 
  */
 
-/**
- * interface lmbMacroTokenizerListener.
- *
- * @package macro
- * @version $Id$
+/**
+ * interface lmbMacroTokenizerListener.
+ *
+ * @package macro
+ * @version $Id$
  */
-interface lmbMacroTokenizerListener
-{
-  function startElement($tag_name, $attrs);
-  function endElement($tag_name);
-  function emptyElement($tag_name, $attrs);
-  function characters($data);
-  function unexpectedEOF($data);
-  function invalidEntitySyntax($data);
-  function invalidAttributeSyntax();
-  function setTemplateLocator($locator);
-}
-?>
\ No newline at end of file
+interface lmbMacroTokenizerListener
+{
+  function startElement($tag_name, $attrs);
+  function endElement($tag_name);
+  function emptyElement($tag_name, $attrs);
+  function characters($data);
+  function unexpectedEOF($data);
+  function invalidEntitySyntax($data);
+  function invalidAttributeSyntax();
+  function setTemplateLocator($locator);
+}
+?>

Modified: 3.x/trunk/limb/macro/src/lmbMacroTreeBuilder.class.php
===================================================================
--- 3.x/trunk/limb/macro/src/lmbMacroTreeBuilder.class.php	2007-08-03 10:25:31 UTC (rev 6211)
+++ 3.x/trunk/limb/macro/src/lmbMacroTreeBuilder.class.php	2007-08-03 19:42:40 UTC (rev 6212)
@@ -1,12 +1,12 @@
-<?php
+<?php
 /*
  * Limb PHP Framework
  *
  * @link http://limb-project.com 
  * @copyright  Copyright &copy; 2004-2007 BIT(http://bit-creative.com)
  * @license    LGPL http://www.gnu.org/copyleft/lesser.html 
- */
-
+ */
+
 /**
  * Acts on the root lmbMacroNode in response to events within the lmbMacroParser
  *
@@ -22,155 +22,155 @@
  * @package macro
  * @version $Id$
  */
-
-
-lmb_require('limb/macro/src/lmbMacroTextNode.class.php');class lmbMacroTreeBuilder
-{
-  protected $compiler;
-  protected $node;
-
-  /**
-  * Stack of tags pushed onto the tree builder
-  */
-  var $expected_tags = array();
-
-  function __construct($compiler)
-  {
-    $this->compiler = $compiler;
-  }
-
-  /**
-  * Returns the current node
-  */
-  function getCursor()
-  {
-    return $this->node;
-  }
-
-  /**
-  * Sets the cursor (the current working node) of the tree builder
-  */
-  function setCursor($node)
-  {
-    $this->node = $node;
-  }
-
-  /**
-  * Begins a node's build phase in relation to the node tree.
-  * Adds a node to the tree, then makes that node the 'cursor'.
-  */
-  function pushNode($node)
-  {
-    $this->node->addChild($node);
-    $this->setCursor($node);
-    return $this->node->preParse($this->compiler);
-  }
-
-  /**
-  * Adds a node to the tree, without descending into it.
-  * This begins and finishes the node's composition
-  */
-  function addNode($node)
-  {
-    $node->preParse($this->compiler);
-    $this->node->addChild($node);
-  }
-
-  function addTextNode($text)
-  {
-    $this->addNode(new lmbMacroTextNode(null, $text));
-  }
-
-  /**
-  * Ends a node's build phase in relation to the tree.
-  * Checks child server ids and moves the 'cursor' up the tree to the parent
-  * node.
-  */
-  function popNode()
-  {    
-    $this->node->checkChildrenIds();
-    $this->setCursor($this->node->getParent());
-  }
-
-  function pushExpectedTag($tag, $location = null)
-  {
-    array_push($this->expected_tags, array($tag, $location));
-  }
-
-  /**
-  * Sets the cursor to a new position, and pushes the old cursor onto the
-  * expected tags stack.
-  * @see popExpectedTag
-  */
-  function pushCursor($newPosition, $location)
-  {
-    // use of array() is to preserve reference from array_pop()
-    array_push($this->expected_tags, array($this->node, $location));
-    $this->setCursor($newPosition);
-  }
-
-  /**
-  * Tests the passed tag against what is expected.  Returns any info that
-  * was kept about the expected tag.
-  * If the item in the tag stack is a node, then the cursor is
-  * restored to that, and popExpectedTag is called again.
-  */
-  function popExpectedTag($tag, $location)
-  {
-    if(!$expected_tag_item = array_pop($this->expected_tags))
-    {
-      throw new lmbMacroException('Lonely closing tag', array('tag' => $tag,
-                                                          'file' => $location->getFile(),
-                                                          'line' => $location->getLine()));
-    }
-
-    // if we have a node on the stack, restore the cursor to that, and
-    // pop the stack again
-    if(is_object($expected_tag_item[0]))
-    {
-      $this->node = $expected_tag_item[0];
-      return $this->popExpectedTag($tag, $location);
-    }
-
-    $expected_tag = $expected_tag_item[0];    
-    $expected_location = $expected_tag_item[1];
-
-    if(strcasecmp($expected_tag, $tag) === 0)
-      return $tag;
- 
-    throw new lmbMacroException('Unexpected closing tag',
-                             array('file' => $location->getFile(),
-                                  'tag' => $tag,
-                                  'line' => $location->getLine(),
-                                  'expected_tag' => $expected_tag,
-                                  'expected_file' => $expected_location->getFile(),
-                                  'expected_line' => $expected_location->getLine()));
-  }
-
-  /**
-  * Return the size of the expected tags stack
-  */
-  function getExpectedTagCount()
-  {
-    return count($this->expected_tags);
-  }
-
-  /**
-  * Returns the current expected tag
-  */
-  function getExpectedTag()
-  {
-    // Returns the tagname of the first non-node item on the stack
-    $item = end($this->expected_tags);
-    while($item && !is_string($item[0]))
-      $item = prev($this->expected_tags);
-    return $item ? $item[0] : false;
-  }
-
-  function getExpectedTagLocation()
-  {
-    $item = end($this->expected_tags);
-    return $item[2];
-  }
-}
-?>
+
+
+lmb_require('limb/macro/src/lmbMacroTextNode.class.php');class lmbMacroTreeBuilder
+{
+  protected $compiler;
+  protected $node;
+
+  /**
+  * Stack of tags pushed onto the tree builder
+  */
+  var $expected_tags = array();
+
+  function __construct($compiler)
+  {
+    $this->compiler = $compiler;
+  }
+
+  /**
+  * Returns the current node
+  */
+  function getCursor()
+  {
+    return $this->node;
+  }
+
+  /**
+  * Sets the cursor (the current working node) of the tree builder
+  */
+  function setCursor($node)
+  {
+    $this->node = $node;
+  }
+
+  /**
+  * Begins a node's build phase in relation to the node tree.
+  * Adds a node to the tree, then makes that node the 'cursor'.
+  */
+  function pushNode($node)
+  {
+    $this->node->addChild($node);
+    $this->setCursor($node);
+    return $this->node->preParse($this->compiler);
+  }
+
+  /**
+  * Adds a node to the tree, without descending into it.
+  * This begins and finishes the node's composition
+  */
+  function addNode($node)
+  {
+    $node->preParse($this->compiler);
+    $this->node->addChild($node);
+  }
+
+  function addTextNode($text)
+  {
+    $this->addNode(new lmbMacroTextNode(null, $text));
+  }
+
+  /**
+  * Ends a node's build phase in relation to the tree.
+  * Checks child server ids and moves the 'cursor' up the tree to the parent
+  * node.
+  */
+  function popNode()
+  {    
+    $this->node->checkChildrenIds();
+    $this->setCursor($this->node->getParent());
+  }
+
+  function pushExpectedTag($tag, $location = null)
+  {
+    array_push($this->expected_tags, array($tag, $location));
+  }
+
+  /**
+  * Sets the cursor to a new position, and pushes the old cursor onto the
+  * expected tags stack.
+  * @see popExpectedTag
+  */
+  function pushCursor($newPosition, $location)
+  {
+    // use of array() is to preserve reference from array_pop()
+    array_push($this->expected_tags, array($this->node, $location));
+    $this->setCursor($newPosition);
+  }
+
+  /**
+  * Tests the passed tag against what is expected.  Returns any info that
+  * was kept about the expected tag.
+  * If the item in the tag stack is a node, then the cursor is
+  * restored to that, and popExpectedTag is called again.
+  */
+  function popExpectedTag($tag, $location)
+  {
+    if(!$expected_tag_item = array_pop($this->expected_tags))
+    {
+      throw new lmbMacroException('Lonely closing tag', array('tag' => $tag,
+                                                          'file' => $location->getFile(),
+                                                          'line' => $location->getLine()));
+    }
+
+    // if we have a node on the stack, restore the cursor to that, and
+    // pop the stack again
+    if(is_object($expected_tag_item[0]))
+    {
+      $this->node = $expected_tag_item[0];
+      return $this->popExpectedTag($tag, $location);
+    }
+
+    $expected_tag = $expected_tag_item[0];    
+    $expected_location = $expected_tag_item[1];
+
+    if(strcasecmp($expected_tag, $tag) === 0)
+      return $tag;
+ 
+    throw new lmbMacroException('Unexpected closing tag',
+                             array('file' => $location->getFile(),
+                                  'tag' => $tag,
+                                  'line' => $location->getLine(),
+                                  'expected_tag' => $expected_tag,
+                                  'expected_file' => $expected_location->getFile(),
+                                  'expected_line' => $expected_location->getLine()));
+  }
+
+  /**
+  * Return the size of the expected tags stack
+  */
+  function getExpectedTagCount()
+  {
+    return count($this->expected_tags);
+  }
+
+  /**
+  * Returns the current expected tag
+  */
+  function getExpectedTag()
+  {
+    // Returns the tagname of the first non-node item on the stack
+    $item = end($this->expected_tags);
+    while($item && !is_string($item[0]))
+      $item = prev($this->expected_tags);
+    return $item ? $item[0] : false;
+  }
+
+  function getExpectedTagLocation()
+  {
+    $item = end($this->expected_tags);
+    return $item[2];
+  }
+}
+?>

Modified: 3.x/trunk/limb/macro/tests/cases/lmbMacroCodeWriterTest.class.php
===================================================================
--- 3.x/trunk/limb/macro/tests/cases/lmbMacroCodeWriterTest.class.php	2007-08-03 10:25:31 UTC (rev 6211)
+++ 3.x/trunk/limb/macro/tests/cases/lmbMacroCodeWriterTest.class.php	2007-08-03 19:42:40 UTC (rev 6212)
@@ -1,110 +1,110 @@
-<?php
+<?php
 /*
  * Limb PHP Framework
  *
  * @link http://limb-project.com 
  * @copyright  Copyright &copy; 2004-2007 BIT(http://bit-creative.com)
  * @license    LGPL http://www.gnu.org/copyleft/lesser.html 
- */
-
-lmb_require('limb/macro/src/lmbMacroCodeWriter.class.php'); 
-
-class lmbMacroCodeWriterTest extends UnitTestCase
-{
-  protected $writer;
-
-  function setUp()
-  {
-    $this->writer = new lmbMacroCodeWriter();
-  }
-
-  function testGetCode()
-  {
-    $this->assertEqual($this->writer->renderCode(),'');
-  }
-
-  function testGetSetCode()
-  {
-    $this->writer->setCode($code = 'code');
-    $this->assertEqual($code, $this->writer->getCode());
-  }
-
-  function testWritePHP()
-  {
-    $this->writer->writePHP('echo ("Hello World!");');
-    $this->assertEqual($this->writer->renderCode(),'<?php echo ("Hello World!"); ?>');
-  }
-
-  function testWriteHTML()
-  {
-    $this->writer->writeHTML('<p>Hello World!</p>');
-    $this->assertEqual($this->writer->renderCode(),'<p>Hello World!</p>');
-  }
-
-  function testSwithBetweenPHPAndHTML()
-  {
-    $this->writer->writePHP('echo ("Hello World!");');
-    $this->writer->writeHTML('<p>Hello World!</p>');
-    $this->writer->writePHP('echo ("Hello World!");');
-    $this->assertEqual($this->writer->renderCode(),
-                       '<?php echo ("Hello World!"); ?><p>Hello World!</p><?php echo ("Hello World!"); ?>');
-  }
-
-  function testRegisterInclude()
-  {
-    $this->writer->registerInclude('test.php');
-    $this->assertEqual($this->writer->renderCode(),'<?php '."require_once('test.php');\n".'?>');
-  }
-
-  function testReset()
-  {
-    $this->writer->writePHP('echo ("Hello World!");');
-    $this->writer->registerInclude('test.php');
-    $this->writer->reset();
-    $this->assertEqual($this->writer->renderCode(), '');
-  }
-
-  function testBeginFunction()
-  {
-    $params = '($a,$b,$c)';
-    $this->writer->beginFunction($params);
-    $this->assertEqual($this->writer->renderCode(),'<?php function tpl1'.$params ." {\n ?>");
-  }
-
-  function testEndFunction()
-  {
-    $this->writer->endFunction();
-    $this->assertEqual($this->writer->renderCode(),'<?php '." }\n".' ?>');
-  }
-
-  function testSetFunctionPrefix()
-  {
-    $this->writer->setFunctionPrefix('Test');
-    $params = '($a,$b,$c)';
-    $this->writer->beginFunction($params);
-    $this->assertEqual($this->writer->renderCode(),'<?php function tplTest1'.$params ." {\n ?>");
-  }
-
-  function testGetTempVariable()
-  {
-    $var = $this->writer->getTempVariable();
-    $this->assertWantedPattern('/[a-z][a-z0-9]*/i', $var);
-  }
-
-  function testGetSecondTempVariable()
-  {
-    $A = $this->writer->getTempVariable();
-    $B = $this->writer->getTempVariable();
-    $this->assertNotEqual($A, $B);
-  }
-
-  function testGetTempVariablesMany()
-  {
-    for ($i = 1; $i <= 30; $i++)
-    {
-      $var = $this->writer->getTempVariable();
-      $this->assertWantedPattern('/[a-z][a-z0-9]*/i', $var);
-    }
-  }
-}
-?>
\ No newline at end of file
+ */
+
+lmb_require('limb/macro/src/lmbMacroCodeWriter.class.php'); 
+
+class lmbMacroCodeWriterTest extends UnitTestCase
+{
+  protected $writer;
+
+  function setUp()
+  {
+    $this->writer = new lmbMacroCodeWriter();
+  }
+
+  function testGetCode()
+  {
+    $this->assertEqual($this->writer->renderCode(),'');
+  }
+
+  function testGetSetCode()
+  {
+    $this->writer->setCode($code = 'code');
+    $this->assertEqual($code, $this->writer->getCode());
+  }
+
+  function testWritePHP()
+  {
+    $this->writer->writePHP('echo ("Hello World!");');
+    $this->assertEqual($this->writer->renderCode(),'<?php echo ("Hello World!"); ?>');
+  }
+
+  function testWriteHTML()
+  {
+    $this->writer->writeHTML('<p>Hello World!</p>');
+    $this->assertEqual($this->writer->renderCode(),'<p>Hello World!</p>');
+  }
+
+  function testSwithBetweenPHPAndHTML()
+  {
+    $this->writer->writePHP('echo ("Hello World!");');
+    $this->writer->writeHTML('<p>Hello World!</p>');
+    $this->writer->writePHP('echo ("Hello World!");');
+    $this->assertEqual($this->writer->renderCode(),
+                       '<?php echo ("Hello World!"); ?><p>Hello World!</p><?php echo ("Hello World!"); ?>');
+  }
+
+  function testRegisterInclude()
+  {
+    $this->writer->registerInclude('test.php');
+    $this->assertEqual($this->writer->renderCode(),'<?php '."require_once('test.php');\n".'?>');
+  }
+
+  function testReset()
+  {
+    $this->writer->writePHP('echo ("Hello World!");');
+    $this->writer->registerInclude('test.php');
+    $this->writer->reset();
+    $this->assertEqual($this->writer->renderCode(), '');
+  }
+
+  function testBeginFunction()
+  {
+    $params = '($a,$b,$c)';
+    $this->writer->beginFunction($params);
+    $this->assertEqual($this->writer->renderCode(),'<?php function tpl1'.$params ." {\n ?>");
+  }
+
+  function testEndFunction()
+  {
+    $this->writer->endFunction();
+    $this->assertEqual($this->writer->renderCode(),'<?php '." }\n".' ?>');
+  }
+
+  function testSetFunctionPrefix()
+  {
+    $this->writer->setFunctionPrefix('Test');
+    $params = '($a,$b,$c)';
+    $this->writer->beginFunction($params);
+    $this->assertEqual($this->writer->renderCode(),'<?php function tplTest1'.$params ." {\n ?>");
+  }
+
+  function testGetTempVariable()
+  {
+    $var = $this->writer->getTempVariable();
+    $this->assertWantedPattern('/[a-z][a-z0-9]*/i', $var);
+  }
+
+  function testGetSecondTempVariable()
+  {
+    $A = $this->writer->getTempVariable();
+    $B = $this->writer->getTempVariable();
+    $this->assertNotEqual($A, $B);
+  }
+
+  function testGetTempVariablesMany()
+  {
+    for ($i = 1; $i <= 30; $i++)
+    {
+      $var = $this->writer->getTempVariable();
+      $this->assertWantedPattern('/[a-z][a-z0-9]*/i', $var);
+    }
+  }
+}
+?>

Modified: 3.x/trunk/limb/macro/tests/cases/lmbMacroTagDictionaryTest.class.php
===================================================================
--- 3.x/trunk/limb/macro/tests/cases/lmbMacroTagDictionaryTest.class.php	2007-08-03 10:25:31 UTC (rev 6211)
+++ 3.x/trunk/limb/macro/tests/cases/lmbMacroTagDictionaryTest.class.php	2007-08-03 19:42:40 UTC (rev 6212)
@@ -1,56 +1,56 @@
-<?php
+<?php
 /*
  * Limb PHP Framework
  *
  * @link http://limb-project.com 
  * @copyright  Copyright &copy; 2004-2007 BIT(http://bit-creative.com)
  * @license    LGPL http://www.gnu.org/copyleft/lesser.html 
- */
-
-lmb_require('limb/macro/src/lmbMacroTag.class.php');
-lmb_require('limb/macro/src/lmbMacroTagInfo.class.php');
-lmb_require('limb/macro/src/lmbMacroTagDictionary.class.php');
-
-class lmbMacroTagDictionaryTest extends UnitTestCase
-{
-  protected $dictionary;
-  protected $tag_info;
-
-  function setUp()
-  {
-    $this->tag_info = new lmbMacroTagInfo('testtag', 'SomeTagClass');
-    $this->dictionary = new lmbMacroTagDictionary();
-    $this->dictionary->register($this->tag_info, $file = 'whaever');
-  }
-
-  protected function _createParentTag()
-  {
-    $tag_info = new lmbMacroTagInfo('some_tag', 'SomeTagClass');
-    return new lmbMacroTag(new lmbMacroSourceLocation('file', '10'), 'some_tag', $tag_info);
-  }
-
-  function testFindTagInfo()
-  {
-    $this->assertIsA($this->dictionary->findTagInfo('testtag'), 'lmbMacroTagInfo');
-  }
-
-  function testRegisterTagInfoOnceOnly()
-  {
-    $dictionary = new lmbMacroTagDictionary();
-    $tag_info1 = new lmbMacroTagInfo('some_tag', 'SomeTagClass');
-    $tag_info2 = new lmbMacroTagInfo('some_tag', 'SomeTagClass');
-    $dictionary->register($tag_info1, $file1 = 'whaever1');
-    $dictionary->register($tag_info2, $file2 = 'whaever2');
-
-    $this->assertEqual($dictionary->findTagInfo('some_tag'), $tag_info1);
-  }
-
-  function testNotATag()
-  {
-    $parent = $this->_createParentTag();
-    $tag = 'notatag';
-    $attrs = array();
-    $this->assertFalse($this->dictionary->findTagInfo($tag, $attrs, FALSE, $parent));
-  }
-}
-?>
\ No newline at end of file
+ */
+
+lmb_require('limb/macro/src/lmbMacroTag.class.php');
+lmb_require('limb/macro/src/lmbMacroTagInfo.class.php');
+lmb_require('limb/macro/src/lmbMacroTagDictionary.class.php');
+
+class lmbMacroTagDictionaryTest extends UnitTestCase
+{
+  protected $dictionary;
+  protected $tag_info;
+
+  function setUp()
+  {
+    $this->tag_info = new lmbMacroTagInfo('testtag', 'SomeTagClass');
+    $this->dictionary = new lmbMacroTagDictionary();
+    $this->dictionary->register($this->tag_info, $file = 'whaever');
+  }
+
+  protected function _createParentTag()
+  {
+    $tag_info = new lmbMacroTagInfo('some_tag', 'SomeTagClass');
+    return new lmbMacroTag(new lmbMacroSourceLocation('file', '10'), 'some_tag', $tag_info);
+  }
+
+  function testFindTagInfo()
+  {
+    $this->assertIsA($this->dictionary->findTagInfo('testtag'), 'lmbMacroTagInfo');
+  }
+
+  function testRegisterTagInfoOnceOnly()
+  {
+    $dictionary = new lmbMacroTagDictionary();
+    $tag_info1 = new lmbMacroTagInfo('some_tag', 'SomeTagClass');
+    $tag_info2 = new lmbMacroTagInfo('some_tag', 'SomeTagClass');
+    $dictionary->register($tag_info1, $file1 = 'whaever1');
+    $dictionary->register($tag_info2, $file2 = 'whaever2');
+
+    $this->assertEqual($dictionary->findTagInfo('some_tag'), $tag_info1);
+  }
+
+  function testNotATag()
+  {
+    $parent = $this->_createParentTag();
+    $tag = 'notatag';
+    $attrs = array();
+    $this->assertFalse($this->dictionary->findTagInfo($tag, $attrs, FALSE, $parent));
+  }
+}
+?>

Modified: 3.x/trunk/limb/macro/tests/cases/lmbMacroTagTest.class.php
===================================================================
--- 3.x/trunk/limb/macro/tests/cases/lmbMacroTagTest.class.php	2007-08-03 10:25:31 UTC (rev 6211)
+++ 3.x/trunk/limb/macro/tests/cases/lmbMacroTagTest.class.php	2007-08-03 19:42:40 UTC (rev 6212)
@@ -1,352 +1,352 @@
-<?php
+<?php
 /*
  * Limb PHP Framework
  *
  * @link http://limb-project.com 
  * @copyright  Copyright &copy; 2004-2007 BIT(http://bit-creative.com)
  * @license    LGPL http://www.gnu.org/copyleft/lesser.html 
- */
-
-lmb_require('limb/macro/src/lmbMacroNode.class.php'); 
-lmb_require('limb/macro/src/lmbMacroTag.class.php');
-lmb_require('limb/macro/src/lmbMacroTagInfo.class.php');
-lmb_require('limb/macro/src/lmbMacroSourceLocation.class.php');
-lmb_require('limb/macro/src/lmbMacroCodeWriter.class.php'); 
- 
-class MacroTagClass1CompilerTest extends lmbMacroTag{}
-class MacroTagClass2CompilerTest extends lmbMacroTag{}
-
-Mock::generate('lmbMacroNode', 'MockMacroNode');
-Mock::generate('lmbMacroCodeWriter', 'MockMacroCodeWriter');
-
-class lmbMacroTagTest extends UnitTestCase
-{
-  protected $node;
-  protected $tag_info;
-  protected $source_location;
-
-  function setUp()
-  {
-    $this->tag_info = new lmbMacroTagInfo('MacroTag', 'whatever');
-    $this->source_location = new lmbMacroSourceLocation('my_file', 10);
-    $this->node = $this->_createNode();
-  }
-
-  protected function _createNode()
-  {
-    return new lmbMacroTag($this->source_location, 'my_tag', $this->tag_info);
-  }
-  
-  function testGetIdAttribute()
-  {
-    $this->node->setId('Test');
-    $this->assertEqual($this->node->getId(), 'Test');
-  }
-
-  function testGetIdGenerated()
-  {
-    $id = $this->node->getId();
-    $this->assertEqual($this->node->getId(), $id);
-  }
-
-  function testFindChild()
-  {
-    $mock = new MockMacroNode();
-    $mock->setReturnValue('getId', 'Test');
-    $this->node->addChild($mock);
-    $this->assertIsA($this->node->findChild('Test'), 'MockMacroNode');
-  }
-
-  function testFindChildNotFound()
-  {
-    $this->assertFalse($this->node->findChild('Test'));
-  }
-
-  function testFindChildByClass()
-  {
-    $mock = new MockMacroNode();
-    $this->node->addChild($mock);
-    $this->assertIsA($this->node->findChildByClass('MockMacroNode'), 'MockMacroNode');
-  }
-
-  function testFindChildByClassNotFound()
-  {
-    $this->assertFalse($this->node->findChildByClass('Booo'));
-  }
-
-  function testFindParentByChilld()
-  {
-    $parent = new lmbMacroNode;
-    $parent->addChild($this->node);
-    $this->assertIsA($this->node->findParentByClass('lmbMacroNode'), 'lmbMacroNode');
-  }
-
-  function testFindParentByClassNotFound()
-  {
-    $this->assertFalse($this->node->findParentByClass('Test'));
-  }
-
-  function testRemoveChild()
-  {
-    $mock = new MockMacroNode();
-    $mock->setReturnValue('getId', 'Test');
-    $this->node->addChild($mock);
-    $this->assertIsA($this->node->removeChild('Test'), 'MockMacroNode');
-  }
-
-  function testGetChildren()
-  {
-    $mock = new MockMacroNode();
-    $this->node->addChild($mock);
-    $children = $this->node->getChildren();
-    $this->assertReference($mock, $children[0]);
-  }
-
-  function testPrepare()
-  {
-    $child = new MockMacroNode();
-    $this->node->addChild($child);
-    $child->expectCallCount('prepare', 1);
-    $this->node->prepare();
-  }
-
-  function testGenerateConstructor()
-  {
-    $code_writer = new MockMacroCodeWriter();
-    $child = new MockMacroNode();
-    $child->expectCallCount('generateConstructor', 1);
-    $this->node->addChild($child);
-    $this->node->generateConstructor($code_writer);
-  }
-
-  function testGenerateContents()
-  {
-    $code_writer = new MockMacroCodeWriter();
-    $child = new MockMacroNode();
-    $child->expectCallCount('generate', 1);
-    $this->node->addChild($child);
-    $this->node->generateContents($code_writer);
-  }
-
-  function testGenerate()
-  {
-    $code_writer = new MockMacroCodeWriter();
-    $child = new MockMacroNode();
-    $child->expectCallCount('generate', 1);
-    $this->node->addChild($child);
-    $this->node->generate($code_writer);
-  }
-
-  function testCheckIdsOk()
-  {
-    $root = new lmbMacroNode;
-    $child1 = new lmbMacroNode;
-    $child1->setId('id1');
-
-    $child2 = new lmbMacroNode;
-    $child2->setId('id2');
-
-    $root->addChild($child1);
-    $root->addChild($child2);
-
-    $root->checkChildrenIds();
-  }
-
-  function testDuplicateIdsError()
-  {
-    $root = new lmbMacroNode;
-    $child1 = new lmbMacroNode(new lmbMacroSourceLocation('my_file', 10));
-    $child1->setId('my_tag');
-    $root->addChild($child1);
-
-    $child2 = new lmbMacroNode(new lmbMacroSourceLocation('my_file2', 15));
-    $child2->setId('my_tag');
-    $root->addChild($child2);
-
-    try
-    {
-      $root->checkChildrenIds();
-      $this->assertTrue(false);
-    }
-    catch(lmbMacroException $e)
-    {
-      $this->assertWantedPattern('/Duplicate "id" attribute/', $e->getMessage());
-      $params = $e->getParams();
-      $this->assertEqual($params['file'], 'my_file2');
-      $this->assertEqual($params['line'], 15);
-      $this->assertEqual($params['duplicate_node_file'], 'my_file');
-      $this->assertEqual($params['duplicate_node_line'], 10);
-    }
-  }
-
-  function testDuplicateIdIsLegalInDifferentBranches()
-  {
-    $root = new lmbMacroNode;
-
-    $Branch = new lmbMacroNode;
-    $root->addChild($Branch);
-
-    $child1 = new lmbMacroNode;
-    $child1->setId('my_tag');
-    $Branch->addChild($child1);
-
-    $child2 = new MockMacroNode();
-    $child2->setId('my_tag');
-    $root->addChild($child2);
-
-    $root->checkChildrenIds();
-  }  
-  
-  function testGetIdByDefault()
-  {
-    $this->assertNotNull($this->node->getId());
-  }  
-
-  function testGetId()
-  {
-    $this->node->setId('TestId');
-    $this->assertEqual($this->node->getId(), 'TestId');
-  }
-  
-  function testGetAttributeUnset()
-  {
-    $this->assertNull($this->node->get('foo'));
-  }  
-
-  function testGetAttribute()
-  {
-    $this->node->set('foo', 'bar');
-    $this->assertEqual($this->node->get('foo'), 'bar');
-    $this->assertEqual($this->node->get('FOO'), 'bar');
-  }
-
-  function testHasAttribute()
-  {
-    $this->node->set('foo', 'bar');
-    $this->node->set('tricky', NULL);
-    $this->assertTrue($this->node->has('foo'));
-    $this->assertTrue($this->node->has('tricky'));
-    $this->assertFalse($this->node->has('missing'));
-    $this->assertTrue($this->node->has('FOO'));
-    $this->assertTrue($this->node->has('TRICKY'));
-    $this->assertFalse($this->node->has('MISSING'));
-  }
-
-  function testRemoveAttribute()
-  {
-    $this->node->set('foo', 'bar');
-    $this->node->set('untouched', 'value');
-    $this->assertTrue($this->node->has('foo'));
-    $this->node->remove('FOO');
-    $this->assertFalse($this->node->has('foo'));
-  }
-
-  function testBooleanAttribute()
-  {
-    //true cases
-    $this->node->set('B', 'True');
-    $this->assertTrue($this->node->getBool('B'));
-
-    $this->node->set('C', 'Something');
-    $this->assertTrue($this->node->getBool('C'));
-
-    //false cases
-    $this->node->set('A', NULL);
-    $this->assertFalse($this->node->getBool('A'));
-    
-    $this->node->set('D', 'False');
-    $this->assertFalse($this->node->getBool('D'));
-
-    $this->assertFalse($this->node->getBool('E'));
-
-    $this->node->set('F', 'n');
-    $this->assertFalse($this->node->getBool('F'));
-
-    $this->node->set('G', 'No');
-    $this->assertFalse($this->node->getBool('G'));
-
-    $this->node->set('H', 'none');
-    $this->assertFalse($this->node->getBool('H'));
-
-    $this->node->set('I', '0');
-    $this->assertFalse($this->node->getBool('I'));
-  }
-
-  function testPreparseAndCheckForRequiredAttributes()
-  {
-    $this->tag_info->setRequiredAttributes(array('bar'));
-    $this->node->set('bar', null);
-    $this->node->preParse();
-  }
-
-  function testPreparseAndCheckForMissedRequiredAttributes()
-  {
-    $this->tag_info->setRequiredAttributes(array('bar'));
-
-    try
-    {
-      $this->node->preParse();
-      $this->assertTrue(false);
-    }
-    catch(lmbMacroException $e)
-    {
-      $this->assertWantedPattern('/Missing required attribute/', $e->getMessage());
-      $this->assertEqual($e->getParam('attribute'), 'bar');
-    }
-  }
-
-  function testRestrictSelfNesting()
-  {
-    $tag_info = new lmbMacroTagInfo('CompilerTag', 'whatever');
-    $tag_info->setRestrictSelfNesting(true);
-
-    $node = new lmbMacroTag(new lmbMacroSourceLocation('my_file', 13), 'whatever', $tag_info);
-
-    $parent = new lmbMacroTag(new lmbMacroSourceLocation('my_file', 10), 'whatEver', $tag_info);
-    $node->setParent($parent);
-
-    try
-    {
-      $node->preParse();
-      $this->assertTrue(false);
-    }
-    catch(lmbMacroException $e)
-    {
-      $this->assertWantedPattern('/Tag cannot be nested within the same tag/', $e->getMessage());
-      $this->assertEqual($e->getParam('same_tag_file'), 'my_file');
-      $this->assertEqual($e->getParam('same_tag_line'), 10);
-    }
-  }
-
-  function testCheckParentTagClassOk()
-  {
-    $this->tag_info->setParentClass('MacroTagClass1CompilerTest');
-
-    $parent = new MacroTagClass1CompilerTest(null, null, null);
-    $this->node->setParent($parent);
-
-    $this->node->preParse();
-  }
-
-  function testCheckParentTagClassException()
-  {
-    $this->tag_info->setParentClass('MacroTagClass1CompilerTest');
-
-    $parent = new MacroTagClass2CompilerTest(null, null, null);
-    $this->node->setParent($parent);
-
-    try
-    {
-      $this->node->preParse();
-      $this->assertTrue(false);
-    }
-    catch(lmbMacroException $e)
-    {
-      $this->assertWantedPattern('/Tag must be enclosed by a proper parent tag/', $e->getMessage());
-      $this->assertEqual($e->getParam('required_parent_tag_class'), 'MacroTagClass1CompilerTest');
-      $this->assertEqual($e->getParam('file'), $this->source_location->getFile());
-      $this->assertEqual($e->getParam('line'), $this->source_location->getLine());
-    }
-  }  
-}
-?>
\ No newline at end of file
+ */
+
+lmb_require('limb/macro/src/lmbMacroNode.class.php'); 
+lmb_require('limb/macro/src/lmbMacroTag.class.php');
+lmb_require('limb/macro/src/lmbMacroTagInfo.class.php');
+lmb_require('limb/macro/src/lmbMacroSourceLocation.class.php');
+lmb_require('limb/macro/src/lmbMacroCodeWriter.class.php'); 
+ 
+class MacroTagClass1CompilerTest extends lmbMacroTag{}
+class MacroTagClass2CompilerTest extends lmbMacroTag{}
+
+Mock::generate('lmbMacroNode', 'MockMacroNode');
+Mock::generate('lmbMacroCodeWriter', 'MockMacroCodeWriter');
+
+class lmbMacroTagTest extends UnitTestCase
+{
+  protected $node;
+  protected $tag_info;
+  protected $source_location;
+
+  function setUp()
+  {
+    $this->tag_info = new lmbMacroTagInfo('MacroTag', 'whatever');
+    $this->source_location = new lmbMacroSourceLocation('my_file', 10);
+    $this->node = $this->_createNode();
+  }
+
+  protected function _createNode()
+  {
+    return new lmbMacroTag($this->source_location, 'my_tag', $this->tag_info);
+  }
+  
+  function testGetIdAttribute()
+  {
+    $this->node->setId('Test');
+    $this->assertEqual($this->node->getId(), 'Test');
+  }
+
+  function testGetIdGenerated()
+  {
+    $id = $this->node->getId();
+    $this->assertEqual($this->node->getId(), $id);
+  }
+
+  function testFindChild()
+  {
+    $mock = new MockMacroNode();
+    $mock->setReturnValue('getId', 'Test');
+    $this->node->addChild($mock);
+    $this->assertIsA($this->node->findChild('Test'), 'MockMacroNode');
+  }
+
+  function testFindChildNotFound()
+  {
+    $this->assertFalse($this->node->findChild('Test'));
+  }
+
+  function testFindChildByClass()
+  {
+    $mock = new MockMacroNode();
+    $this->node->addChild($mock);
+    $this->assertIsA($this->node->findChildByClass('MockMacroNode'), 'MockMacroNode');
+  }
+
+  function testFindChildByClassNotFound()
+  {
+    $this->assertFalse($this->node->findChildByClass('Booo'));
+  }
+
+  function testFindParentByChilld()
+  {
+    $parent = new lmbMacroNode;
+    $parent->addChild($this->node);
+    $this->assertIsA($this->node->findParentByClass('lmbMacroNode'), 'lmbMacroNode');
+  }
+
+  function testFindParentByClassNotFound()
+  {
+    $this->assertFalse($this->node->findParentByClass('Test'));
+  }
+
+  function testRemoveChild()
+  {
+    $mock = new MockMacroNode();
+    $mock->setReturnValue('getId', 'Test');
+    $this->node->addChild($mock);
+    $this->assertIsA($this->node->removeChild('Test'), 'MockMacroNode');
+  }
+
+  function testGetChildren()
+  {
+    $mock = new MockMacroNode();
+    $this->node->addChild($mock);
+    $children = $this->node->getChildren();
+    $this->assertReference($mock, $children[0]);
+  }
+
+  function testPrepare()
+  {
+    $child = new MockMacroNode();
+    $this->node->addChild($child);
+    $child->expectCallCount('prepare', 1);
+    $this->node->prepare();
+  }
+
+  function testGenerateConstructor()
+  {
+    $code_writer = new MockMacroCodeWriter();
+    $child = new MockMacroNode();
+    $child->expectCallCount('generateConstructor', 1);
+    $this->node->addChild($child);
+    $this->node->generateConstructor($code_writer);
+  }
+
+  function testGenerateContents()
+  {
+    $code_writer = new MockMacroCodeWriter();
+    $child = new MockMacroNode();
+    $child->expectCallCount('generate', 1);
+    $this->node->addChild($child);
+    $this->node->generateContents($code_writer);
+  }
+
+  function testGenerate()
+  {
+    $code_writer = new MockMacroCodeWriter();
+    $child = new MockMacroNode();
+    $child->expectCallCount('generate', 1);
+    $this->node->addChild($child);
+    $this->node->generate($code_writer);
+  }
+
+  function testCheckIdsOk()
+  {
+    $root = new lmbMacroNode;
+    $child1 = new lmbMacroNode;
+    $child1->setId('id1');
+
+    $child2 = new lmbMacroNode;
+    $child2->setId('id2');
+
+    $root->addChild($child1);
+    $root->addChild($child2);
+
+    $root->checkChildrenIds();
+  }
+
+  function testDuplicateIdsError()
+  {
+    $root = new lmbMacroNode;
+    $child1 = new lmbMacroNode(new lmbMacroSourceLocation('my_file', 10));
+    $child1->setId('my_tag');
+    $root->addChild($child1);
+
+    $child2 = new lmbMacroNode(new lmbMacroSourceLocation('my_file2', 15));
+    $child2->setId('my_tag');
+    $root->addChild($child2);
+
+    try
+    {
+      $root->checkChildrenIds();
+      $this->assertTrue(false);
+    }
+    catch(lmbMacroException $e)
+    {
+      $this->assertWantedPattern('/Duplicate "id" attribute/', $e->getMessage());
+      $params = $e->getParams();
+      $this->assertEqual($params['file'], 'my_file2');
+      $this->assertEqual($params['line'], 15);
+      $this->assertEqual($params['duplicate_node_file'], 'my_file');
+      $this->assertEqual($params['duplicate_node_line'], 10);
+    }
+  }
+
+  function testDuplicateIdIsLegalInDifferentBranches()
+  {
+    $root = new lmbMacroNode;
+
+    $Branch = new lmbMacroNode;
+    $root->addChild($Branch);
+
+    $child1 = new lmbMacroNode;
+    $child1->setId('my_tag');
+    $Branch->addChild($child1);
+
+    $child2 = new MockMacroNode();
+    $child2->setId('my_tag');
+    $root->addChild($child2);
+
+    $root->checkChildrenIds();
+  }  
+  
+  function testGetIdByDefault()
+  {
+    $this->assertNotNull($this->node->getId());
+  }  
+
+  function testGetId()
+  {
+    $this->node->setId('TestId');
+    $this->assertEqual($this->node->getId(), 'TestId');
+  }
+  
+  function testGetAttributeUnset()
+  {
+    $this->assertNull($this->node->get('foo'));
+  }  
+
+  function testGetAttribute()
+  {
+    $this->node->set('foo', 'bar');
+    $this->assertEqual($this->node->get('foo'), 'bar');
+    $this->assertEqual($this->node->get('FOO'), 'bar');
+  }
+
+  function testHasAttribute()
+  {
+    $this->node->set('foo', 'bar');
+