/public/js/util/docscripts/lib/parser2/Symbol.php

https://github.com/Nerutiz/trades · PHP · 252 lines · 198 code · 36 blank · 18 comment · 104 complexity · af70e59ad846713ee42746031efb60a2 MD5 · raw file

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