| <?php |
| /** |
| * File containing the ezcTemplateSymbolTable class. |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| * @package Template |
| * @version //autogen// |
| * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 |
| * @access private |
| */ |
| |
| /** |
| * Symbol table |
| * |
| * @package Template |
| * @version //autogen// |
| * @access private |
| */ |
| class ezcTemplateSymbolTable |
| { |
| const VARIABLE = 1; |
| const CYCLE = 2; |
| const IMPORT = 3; // USE is a keyword. |
| |
| // Messages. |
| const SYMBOL_REDECLARATION = "The symbol <\$%s> is already declared."; |
| const SYMBOL_TYPES_NOT_EQUAL = "The %s <\$%s> is already declared as '%s'."; |
| const SYMBOL_NOT_DECLARED = "The symbol <\$%s> is not declared"; |
| const SYMBOL_INVALID_SCOPE = "The %s <\$%s> is cannot be declared in a subblock: while, foreach, if, etc"; |
| const SYMBOL_IMPORT_FIRST = "'Use' should be declared before other declarations"; |
| |
| /** |
| * Keeps track of the symbols with its type. |
| * |
| * @var array(string=>int) |
| */ |
| protected $symbols; |
| |
| |
| /** |
| * Maps the variable name to the typehint integer. |
| * The integer has one of the values: ezcTemplateAstNode::TYPE_ARRAY, |
| * ezcTemplatesAstNode::TYPE_VALUE, or both (use bitwise OR). |
| * |
| * @var array(string=>int) |
| */ |
| protected $typehints; |
| |
| /** |
| * Keeps track of the current scope. Inside a block the scope is higher |
| * than outside the block. |
| * |
| * Example: |
| * <code> |
| * |
| * Scope 1 |
| * |
| * {if true} |
| * Scope 2 |
| * {/if} |
| * |
| * Scope 1 |
| * </code> |
| * |
| * @var int |
| */ |
| private $scope; |
| |
| /** |
| * Keeps track of the type that is declared first. |
| * The first declared type should be a 'use' variable, if any. |
| * |
| * @var int |
| */ |
| private $firstDeclaredType; |
| |
| /** |
| * Stores the last error message. |
| * |
| * @var string |
| */ |
| private $errorMessage = ""; |
| |
| |
| /** |
| * This class is a singleton. Reference to itself. |
| * |
| * @var ezcTemplateSymbolTable |
| */ |
| private static $instance = null; |
| |
| |
| |
| /** |
| * Instantiate this class and reset() all the values. |
| * |
| * The constructor is private and getInstance() should be used |
| * to instantiate the symbolTable. |
| */ |
| private function __construct() |
| { |
| $this->reset(); |
| } |
| |
| /** |
| * Return the existing instance of the symbol table if it exists. |
| * Otherwise a new instance is created. (Singleton) |
| * |
| * @return ezcTemplateSymbolTable |
| */ |
| static public function getInstance() |
| { |
| if ( self::$instance === null) |
| { |
| self::$instance = new ezcTemplateSymbolTable(); |
| } |
| |
| return self::$instance; |
| } |
| |
| /** |
| * Reset the symbol table. |
| * Set the scope to one. Remove all registered symbols and typehints. |
| * |
| * @return void |
| */ |
| public function reset() |
| { |
| $this->typehints = array(); |
| $this->symbols = array(); |
| $this->scope = 1; |
| |
| $this->firstDeclaredType = false; |
| } |
| |
| /** |
| * Add a new or existing symbol $symbol with its type $type to the |
| * symbolTable. |
| * |
| * If $isAutoDeclared is set to false (default), the added symbol must |
| * apply to all following rules: |
| * |
| * - The symbol cannot be redeclared. |
| * - The current scope must be one; thus only the top scope allows |
| * variable declaration. |
| * - The 'use' variables should all be declared before the other type of |
| * variables. |
| * |
| * When $isAutoDeclared is set to true: |
| * |
| * - Variables can be redeclared as long as the type does not change. |
| * - It is allowed to declare and redeclare at any scope. |
| * - The 'use' variables should all be declared before the other type of |
| * variables. |
| * |
| * @param string $symbol |
| * @param int $type The type is usually one of the constants: |
| * ezcTemplateSymbolTable::VARIABLE, |
| * ezcTemplateSymbolTable::CYCLE, and |
| * ezcTemplateSymbolTable::IMPORT. |
| * |
| * @param bool $isAutoDeclared Usually this parameter is set to true when |
| * a construct automatically declares a |
| * variable. For example the: {foreach}. |
| * |
| * @return bool Return true if the variable is added. If |
| * false is returned check the errorMessage. |
| */ |
| public function enter( $symbol, $type, $isAutoDeclared = false ) |
| { |
| // Check for redeclaration. |
| if ( isset( $this->symbols[ $symbol ] ) ) |
| { |
| if ( $isAutoDeclared ) |
| { |
| $storedType = $this->symbols[ $symbol ]; |
| |
| // Check whether the types are equal, when redeclaration is allowed. |
| if ( $type != $storedType ) |
| { |
| $this->errorMessage = sprintf( self::SYMBOL_TYPES_NOT_EQUAL, self::symbolTypeToString( $type ), $symbol, self::symbolTypeToString( $storedType ) ); |
| return false; |
| } |
| } |
| else |
| { |
| $this->errorMessage = sprintf( self::SYMBOL_REDECLARATION, $symbol ); |
| return false; |
| } |
| } |
| |
| // Check whether the declaration is at the top scope. Scope level 1. |
| if ( !$isAutoDeclared && $this->scope != 1 ) |
| { |
| $this->errorMessage = sprintf( self::SYMBOL_INVALID_SCOPE, self::symbolTypeToString( $type ), $symbol ); |
| return false; |
| } |
| |
| if ( $this->firstDeclaredType === false ) |
| { |
| $this->firstDeclaredType = $type; |
| } |
| else |
| { |
| if ( $type === self::IMPORT && $this->firstDeclaredType !== self::IMPORT ) |
| { |
| $this->errorMessage = sprintf( self::SYMBOL_IMPORT_FIRST ); |
| return false; |
| } |
| } |
| |
| $this->symbols[ $symbol ] = $type; |
| return true; |
| } |
| |
| /** |
| * Return the type of the given symbol $symbol. |
| * |
| * If the symbol is not registered in the symbol table the method returns |
| * false and sets an error message. |
| * |
| * @param string $symbol |
| * @return bool |
| */ |
| public function retrieve( $symbol ) |
| { |
| if ( !isset( $this->symbols[ $symbol ] ) ) |
| { |
| $this->errorMessage = sprintf ( self::SYMBOL_NOT_DECLARED, $symbol ); |
| return false; |
| } |
| |
| return $this->symbols[ $symbol ]; |
| } |
| |
| /** |
| * Return an array with all symbols that have the given types $typeArray. |
| * |
| * @param array(int) $typeArray The array can have one or more of the |
| * following values: |
| * ezcTemplateSymbolTable::VARIABLE, |
| * ezcTemplateSymbolTable::CYCLE, and |
| * ezcTemplateSymbolTable::IMPORT. |
| * |
| * @return array(string) |
| */ |
| public function retrieveSymbolsWithType( $typeArray ) |
| { |
| $total = array(); |
| |
| foreach ( $typeArray as $type ) |
| { |
| // Search for all the keys in the array, and merge it. |
| $total = array_merge($total, array_keys( $this->symbols, $type ) ); |
| } |
| |
| return $total; |
| } |
| |
| /** |
| * Return the last error message. |
| * |
| * @return string |
| */ |
| public function getErrorMessage() |
| { |
| return $this->errorMessage; |
| } |
| |
| /** |
| * Translates a symbol type to a string. |
| * It returns one of the following strings: 'variable', 'cycle', or 'use'. |
| * |
| * @param int $type |
| * @return string |
| */ |
| public static function symbolTypeToString( $type ) |
| { |
| switch ( $type ) |
| { |
| case self::VARIABLE: return "variable"; |
| case self::CYCLE: return "cycle"; |
| case self::IMPORT: return "use"; |
| } |
| } |
| |
| /** |
| * Increase the current scope with one. |
| * |
| * @return void |
| */ |
| public function increaseScope() |
| { |
| ++$this->scope; |
| } |
| |
| /** |
| * Decreases the current scope with one. |
| * |
| * @return void |
| */ |
| public function decreaseScope() |
| { |
| --$this->scope; |
| } |
| |
| /** |
| * Set the typehint with the symbol $name to the type hint value $hint. |
| * |
| * @param string $name |
| * @param int $hint The integer has one of the values: ezcTemplateAstNode::TYPE_ARRAY, |
| * ezcTemplatesAstNode::TYPE_VALUE, or both (use bitwise OR). |
| * |
| * @return void |
| */ |
| public function setTypeHint( $name, $hint ) |
| { |
| $this->typehints[$name] = $hint; |
| } |
| |
| /** |
| * Return the typehint of the given symbol $name. |
| * |
| * @param string $name |
| * |
| * @return int The integer has one of the values: ezcTemplateAstNode::TYPE_ARRAY, |
| * ezcTemplatesAstNode::TYPE_VALUE, or both (use bitwise OR). |
| */ |
| public function getTypeHint( $name ) |
| { |
| return isset( $this->typehints[$name] ) ? $this->typehints[$name] : false; |
| |
| } |
| |
| } |
| |
| |
| ?> |