source: Dev/trunk/src/client/util/docscripts/lib/parser2/Symbol.php

Last change on this file was 483, checked in by hendrikvanantwerpen, 11 years ago

Added Dojo 1.9.3 release.

File size: 8.2 KB
Line 
1<?php
2
3class Symbol {
4  public $id = NULL;
5  public $name = NULL;
6  public $value = NULL;
7  public $first = NULL;
8  public $second = NULL;
9  public $third = NULL;
10  public $lbp = 0;
11  public $reserved = FALSE;
12  public $global_scope = FALSE;
13  public $assignment = FALSE;
14  public $arity;
15  public $type;
16  public $line_number;
17  public $char_pos;
18
19  public $nud = 'nud_default';
20  public $led = 'led_default';
21  public $std = NULL;
22
23  public $bp = 0;
24
25  public function possible_variable() {
26    return $this->value == '.' || $this->value == '[' || $this->arity == 'name';
27  }
28
29  public function is_option() {
30    return $this->first && ($this->value == '||' || $this->value == '&&');
31  }
32
33  public function is_lookup($statement = NULL) {
34    if (!$statement) {
35      $statement = $this;
36    }
37
38    $first = $statement->first;
39    $second = $statement->second;
40
41    if ($first && $statement->arity == 'binary' && ($statement->id == '.' || $statement->id == '[')) {
42      return (is_object($first) && $first->is_lookup() && $second->arity == 'literal');
43    }
44    else {
45      return ($statement->arity == 'name' || $statement->arity == 'literal' || $statement->arity == 'this');
46    }
47  }
48
49  public function resolve($as_array = FALSE, $statement = NULL, $public = FALSE, $firsts = array()) {
50    if (!$statement) {
51      $public = TRUE; // Whether the call is non-resursive
52      $statement = $this;
53    }
54
55    $first = $statement->first;
56    $second = $statement->second;
57
58    $results = array();
59
60    if ($first && $statement->arity == 'binary' && ($statement->id == '.' || $statement->id == '[')) {
61      // foo.bar.baz or foo["bar"].baz
62      foreach ($this->resolve(TRUE, $first, FALSE, $firsts) as $resolved) {
63        list($is_global, $name) = $resolved;
64
65        if (!$second->arity == 'literal') {
66          throw new Exception(sprintf('Line %d, char %d: Lookup is not by literal: %s', $statement->line_number, $statement->char_pos, $second));
67        }
68
69        if (is_object($name) && $name->id == '{') {
70          $is_global = $first->global_scope;
71
72          // The parent item resolved to an object
73          // so we need to continue the lookup
74          foreach ($name->first as $value) {
75            // -> first has all values with their key
76            if ($value->key == $second->value) {
77              if ($value->first() == $statement->first()) {
78                 // Object references itself, within itself
79                continue;
80              }
81              if ($value->arity == 'name') {
82                // Contains an actual variable name
83                $results[] = array($value->global_scope, $value->value);
84                break 2;
85              }
86              elseif ($value->arity == 'binary' && ($value->id == '.' || $value->id == '[')) {
87                // Contains a new variable for us to resolve
88                $results = array_merge($results, $this->resolve(TRUE, $value, TRUE, $firsts));
89                break 2;
90              }
91              elseif (!$public && $value->id == '{') {
92                // Contains an object
93                $results[] = array(NULL, $value);
94                break 2;
95              }
96            }
97          }
98
99          $name = $first->value;
100        }
101
102        if (!is_string($name)) {
103          throw new Exception(sprintf('Line %d, char %d: Parent variable resolution returned an unknown (%s)', $statement->line_number, $statement->char_pos, $statement));
104        }
105
106        if ($is_global && $name == 'this') {
107          $results[] = array($is_global, $second->value);
108        }
109        else {
110          $results[] = array($is_global, sprintf('%s.%s', $name, $second->value));
111        }
112      }
113
114      return $as_array ? $results : $results[0];
115    }
116    elseif ($statement->arity == 'name' || $statement->arity == 'literal' || $statement->arity == 'this') {
117      // This is the first item in the variable (e.g. for foo.bar.baz, it would be foo)
118      // It only matters if it's an object or an assignment
119      if ($assignments = $statement->scope->assigned($statement->value, TRUE)) {
120        foreach ($assignments as $assignment) {
121          if ($assignment->first() != $statement->first() && !in_array($statement->first(), $firsts)) {
122            if ($assignment->arity == 'name') {
123              $results[] = array($assignment->global_scope, $assignment->value);
124            }
125            elseif ($assignment->arity == 'binary' && ($assignment->id == '.' || $assignment->id == '[')) {
126              // Deal with stuff like c = p.constructor;
127              // followed by p = c.superclass
128              // where they "look each other up"
129              $results = array_merge($results, $this->resolve(TRUE, $assignment, TRUE, array_merge($firsts, array($statement->first()))));
130            }
131            elseif (!$public && $assignment->id == '{') {
132              $results[] = array(NULL, $assignment);
133            }
134          }
135        }
136      }
137
138      if (count($results)) {
139        return $as_array ? $results : $results[0];
140      }
141
142      $result = array($statement->global_scope, $statement->value);
143      return $as_array ? array($result) : $result;
144    }
145
146    throw new Exception(sprintf('Line %d, char %d: Expected a variable in the form foo.bar with %s', $statement->line_number, $statement->char_pos, $statement->id));
147  }
148
149  public function first($statement = NULL) {
150    if (!$statement) {
151      $statement = $this;
152    }
153
154    $first = $statement->first;
155    $second = $statement->second;
156
157    if ($first && $statement->arity == 'binary' && ($statement->id == '.' || $statement->id == '[')) {
158      return $this->first($first);
159    }
160    elseif ($statement->arity == 'name') {
161      return $statement->value;
162    }
163  }
164
165  /**
166   * Creates a symbol with a statement denotation function
167   * that reads until it finds an opening {
168   */
169  public function block($parser) {
170    $parser->peek('{');
171    $token = $parser->token;
172    $parser->advance('{');
173    return $token->std($parser);
174  }
175
176  public function nud_default($parser) {
177    throw new Exception("Syntax error on line {$this->line_number}, character {$this->char_pos} ({$this->id}:'{$this->value}')");
178  }
179
180  public function nud_prefix($parser) {
181    $this->first = $parser->expression(70);
182    return $this;
183  }
184
185  public function nud_itself($parser) {
186    return $this;
187  }
188
189  public function nud_constant($parser) {
190    $parser->scope->reserve($this);
191    $this->value = $parser->new_symbol($this->id, TRUE)->value;
192    $this->arity = 'literal';
193    return $this;
194  }
195
196  public function led_default($parser, $left) {
197    throw new Exception("Unknown operator ({$this->id}:'{$this->value}')");
198  }
199
200  public function led_infix($parser, $left) {
201    $this->first = $left;
202    $this->second = $parser->expression($this->bp);
203    return $this;
204  }
205
206  public function led_infixr($parser, $left) {
207    $this->first = $left;
208    $this->second = $parser->expression($this->bp - 1);
209    return $this;
210  }
211
212  public function led_assignment($parser, $left) {
213    if ($left->id != '.' && $left->id != '[' && $left->arity != 'name') {
214      throw new Error('Bad lvalue');
215    }
216    $this->first = $left;
217    $this->second = $parser->expression(9);
218    $this->assignment = true;
219    $this->arity = 'binary';
220    return $this;
221  }
222
223  public function __call($method, $args) {
224    if ($method == 'lbp') {
225      if (is_numeric($this->lbp)) {
226        return $this->lbp;
227      }
228      return call_user_func_array(array($this, $this->lbp), $args);
229    }
230    if ($method == 'nud') {
231      return call_user_func_array(array($this, $this->nud), $args);
232    }
233    if ($method == 'led') {
234      return call_user_func_array(array($this, $this->led), $args);
235    }
236    if ($method == 'std') {
237      return call_user_func_array(array($this, $this->std), $args);
238    }
239  }
240
241  public function __toString() {
242    // debug_backtrace_clean();
243    if ($this->id == '(name)' || $this->id == '(literal)') {
244      return '(' . substr($this->id, 1, strlen($this->id) - 2) . " {$this->value})";
245    }
246    $first = is_array($this->first) ? ('[' . implode(', ', $this->first) . ']') : $this->first;
247    $second = is_array($this->second) ? ('[' . implode(', ', $this->second) . ']') : $this->second;
248    $third = is_array($this->third) ? ('[' . implode(', ', $this->third) . ']') : $this->third;
249    $out = array_diff(array($this->id, $first, $second, $third), array(NULL));
250    return '(' . implode(' ', $out) . ')';
251  }
252}
Note: See TracBrowser for help on using the repository browser.