definitions[$symbol->value] && $token->reserved) {
throw new Exception("Already defined: {$symbol->value}");
}
$this->definitions[$symbol->value] = $symbol;
$symbol->reserved = FALSE;
$symbol->nud = 'nud_itself';
$symbol->led = NULL;
$symbol->std = NULL;
$symbol->lbp = 0;
$symbol->scope = $this;
$symbol->global_scope = empty($this->_parent);
return $symbol;
}
/**
* Mark an assignment made in the current scope between two symbols
*
* @param Symbol $to_expression The expression $expression is assigned to
* @param Symbol $expression The expression being assigned
*/
public function assignment($to_expression, $expression) {
if ($to_expression->arity == 'name' || $to_expression->arity == 'literal') {
$this->assignments[$to_expression->value] = $expression;
}
}
public function assigned($variable) {
return $this->assignments[$variable];
}
/**
* Sets the current scope's parent
*
* @param Scope $parent
*/
public function setParent($parent) {
if ($parent instanceof Scope) {
return ($this->_parent = $parent);
}
}
/**
* Returns the current parent
*/
public function parent() {
// This is how pop() will work as well
return $this->_parent;
}
public function definition($name) {
return $this->definitions[$name];
}
/**
* Tries to look up through each scope
* to find a symbol with the same name
* and returns the global symbol or empty
* (name) symbol instead
*/
public function find ($name, $symbol_table) {
if ($symbol_table[$name]) {
return clone $symbol_table[$name];
}
$scope = $this;
while (1) {
if ($symbol = $scope->definition($name)) {
return clone $symbol;
}
if (!$scope->parent()) {
if (array_key_exists($name, $symbol_table)) {
return $symbol_table[$name];
}
$symbol = $symbol_table['(name)'];
$s = clone $symbol;
$s->global_scope = true;
$s->reserved = false;
$s->nud = 'nud_itself';
$s->led = null;
$s->std = null;
$s->lbp = 0;
$s->scope = $scope;
return $s;
}
$scope = $scope->parent();
}
}
/**
* Marks a variable symbol as being reserved in the current scope
*
* @param Symbol @symbol The variable symbol to mark reserved
*/
public function reserve($symbol) {
if ($symbol->arity != 'name' || $symbol->reserved) {
return;
}
if ($token = $this->definitions[$symbol->value]) {
if ($token->reserved) {
return;
}
if ($token->arity == 'name') {
throw new Exception("Already defined: {$symbol->value}");
}
}
$this->definitions[$symbol->value] = $symbol;
$symbol->reserved = true;
}
}