| 
<?phpnamespace eMacros;
 
 class Scope implements \ArrayAccess, \IteratorAggregate {
 /**
 * Symboil table
 * @var array
 */
 public $symbols = array();
 
 /**
 * Macros list
 * @var array
 */
 public $macros = array();
 
 protected static function symbol($symbol) {
 if ($symbol instanceof Symbol) {
 return $symbol->symbol;
 }
 elseif (is_string($symbol)) {
 return $symbol;
 }
 
 throw new \UnexpectedValueException(sprintf("Unexpected value of type '%s'.", is_object($symbol) ? get_class($symbol) : gettype($symbol)));
 }
 
 /**
 * Obtains a symbol from table
 * (non-PHPdoc)
 * @see ArrayAccess::offsetGet()
 */
 public function offsetGet($symbol) {
 $sym = self::symbol($symbol);
 
 //is symbol defined on this scope?
 if (array_key_exists($sym, $this->symbols)) {
 return $this->symbols[$sym];
 }
 else {
 foreach ($this->macros as $regex => $callback) {
 if (preg_match($regex, $sym, $matches)) {
 $this->symbols[$sym] = $callback->__invoke($matches);
 return $this->symbols[$sym];
 }
 }
 }
 
 return null;
 }
 
 public function offsetExists($symbol) {
 return true;
 }
 
 /**
 * Stores a symbol
 * Used when setting up a Scope/Package
 * Ex: $this['.'] = new Concatenation();
 * (non-PHPdoc)
 * @see ArrayAccess::offsetSet()
 */
 public function offsetSet($symbol, $value) {
 $symbol = Symbol::validateSymbol($symbol);
 $this->symbols[$symbol] = $value;
 }
 
 /**
 * Removes a symbol from table
 * (non-PHPdoc)
 * @see ArrayAccess::offsetUnset()
 */
 public function offsetUnset($symbol) {
 unset($this->symbols[$symbol]);
 }
 
 /**
 * Obtains a symbol iterator
 * (non-PHPdoc)
 * @see IteratorAggregate::getIterator()
 */
 public function getIterator() {
 $symbols = array();
 
 foreach ($this->listSymbols() as $name) {
 $symbols[$name] = $this[$name];
 }
 
 return new \ArrayIterator($symbols);
 }
 
 /**
 * Obtains all defined symbols
 * @return array
 */
 public function listSymbols() {
 return array_keys($this->symbols);
 }
 
 /**
 * Adds a new macro
 * @param string $regex
 * @param \Closure $handler
 */
 public function macro($regex, \Closure $handler) {
 $this->macros[$regex] = $handler;
 }
 }
 ?>
 |