/src/php/Snowscript/Visitors.php

https://gitlab.com/oytunistrator/snowscript · PHP · 230 lines · 221 code · 9 blank · 0 comment · 23 complexity · 1cd9d36f75f155c0ac657243957c7da0 MD5 · raw file

  1. <?php
  2. function rpl($string, $search, $replace)
  3. {
  4. return str_replace($search, $replace, $string);
  5. };
  6. function sjoin($l, $separator = ", ")
  7. {
  8. return join($l->arr, $separator);
  9. };
  10. function type($guy)
  11. {
  12. return gettype($guy);
  13. };
  14. function uu($l)
  15. {
  16. return sjoin($l, '__');
  17. };
  18. function pp($obj, $indent = 0)
  19. {
  20. foreach ($obj as $k => $v) {
  21. $type = gettype($v);
  22. if ((\snow_eq($type, "string") || \snow_eq($type, "integer")) || \snow_eq($type, "NULL")) {
  23. echo sprintf("%s%s: %s\n", str_repeat(" ", $indent * 2), (string) $k, (string) $v);
  24. } elseif (\snow_eq($type, "boolean")) {
  25. echo sprintf("%s%s: %s\n", str_repeat(" ", $indent * 2), (string) $k, $v ? "true" : "false");
  26. } elseif (\snow_eq($type, "object")) {
  27. echo sprintf("%s%s - %s\n", str_repeat(" ", $indent * 2), $k, get_class($v));
  28. pp($v, $indent + 1);
  29. } elseif (\snow_eq($type, "array")) {
  30. echo sprintf("%s%s - %s\n", str_repeat(" ", $indent * 2), $k, "array");
  31. pp($v, $indent + 1);
  32. } else {
  33. var_dump($type);
  34. throw new Exception("Type not implemented: " . $type);
  35. }
  36. }
  37. unset($k, $v);
  38. };
  39. function v($x)
  40. {
  41. var_dump($x);
  42. };
  43. class Snowscript_Visitors_Scope extends PHPParser_NodeVisitorAbstract
  44. {
  45. public function __construct($ns)
  46. {
  47. $this->ns = $ns;
  48. $this->scopes = snow_list(array(snow_dict(array('names' => snow_dict(array()), 'prefix' => snow_list(array())))));
  49. $this->in_assign = false;
  50. $this->global_vars = snow_list(array());
  51. }
  52. public function scope_has_name($name, $index)
  53. {
  54. try {
  55. return $this->scopes[$index]->names->get($name);
  56. } catch (IndexError $e) {
  57. return False;
  58. }
  59. }
  60. public function global_name($name)
  61. {
  62. if (\snow_eq(count($this->scopes), 1)) {
  63. return uu(snow_list(array($this->ns, $name)));
  64. } else {
  65. return uu(snow_list(array(uu($this->scopes[-1]->prefix), $name)));
  66. }
  67. }
  68. public function add_node_to_scope($node, $name, $new_name, $is_global, $global_name)
  69. {
  70. if (!$this->scopes[-1]->names->get($name)) {
  71. $this->scopes[-1]->names[$name] = snow_dict(array('nodes' => snow_list(array()), 'new_name' => null, 'is_global' => null, 'global_name' => $global_name, 'func' => null));
  72. }
  73. $this->scopes[-1]->names[$name]->is_global = $is_global;
  74. $this->scopes[-1]->names[$name]->nodes->append($node);
  75. $this->rename_nodes($name, $new_name, -1);
  76. if ($is_global && $this->scopes[-1]->get('func')) {
  77. $this->scopes[-1]->func->add_global_var($new_name);
  78. if ($this->scopes[-2]->get('func')) {
  79. $this->scopes[-2]->func->add_global_var($new_name);
  80. }
  81. }
  82. if ($is_global) {
  83. $this->global_vars->append($new_name);
  84. }
  85. }
  86. public function rename_nodes($name, $new_name, $scope_index)
  87. {
  88. $this->scopes[$scope_index]->names[$name]->new_name = $new_name;
  89. foreach ($this->scopes[$scope_index]->names[$name]->nodes as $node) {
  90. if (($node instanceof PHPParser_Node_Expr_Assign)) {
  91. $node->var->name = $new_name;
  92. } elseif (($node instanceof PHPParser_Node_Stmt_Function)) {
  93. $node->name = $new_name;
  94. } elseif (($node instanceof PHPParser_Node_Expr_FuncCall)) {
  95. $node->name->parts[0] = $new_name;
  96. } elseif (($node instanceof PHPParser_Node_Expr_Variable)) {
  97. $node->name = $new_name;
  98. } else {
  99. throw new Exception(get_class("Not supported: " . $node));
  100. }
  101. }
  102. unset($node);
  103. }
  104. public function rename_nodes_all_scopes($name, $new_name)
  105. {
  106. foreach ($this->scopes as $k => $scope) {
  107. if ($scope->names->get($name)) {
  108. $this->rename_nodes($name, $new_name, $k);
  109. }
  110. }
  111. unset($k, $scope);
  112. }
  113. public function mark_name_as_global($name, $new_name)
  114. {
  115. foreach ($this->scopes as $scope) {
  116. try {
  117. $scope->names[$name]->is_global = true;
  118. } catch (KeyError $e) {
  119. }
  120. }
  121. unset($scope);
  122. $this->global_vars->append($new_name);
  123. }
  124. public function create_name($node, $name, $allow_redefinition, $allow_creation)
  125. {
  126. $is_global = false;
  127. $global_name = $this->global_name($name);
  128. if ($this->scope_has_name($name, -2)) {
  129. if (!$allow_redefinition) {
  130. throw new Exception("Cant redefine name from outer scope: " . $name);
  131. }
  132. $is_global = true;
  133. $new_name = $this->scopes[-2]->names[$name]->global_name;
  134. if (!$this->scopes[-2]->names[$name]->is_global) {
  135. $new_name = $this->scopes[-2]->names[$name]->global_name;
  136. $this->mark_name_as_global($name, $new_name);
  137. $this->rename_nodes_all_scopes($name, $new_name);
  138. }
  139. } elseif ($this->scopes[-1]->names->get($name)) {
  140. if (!$allow_redefinition) {
  141. throw new Exception("Cant redefine name from same scope: " . $name);
  142. }
  143. $new_name = $this->scopes[-1]->names[$name]->new_name;
  144. } else {
  145. if ($allow_creation) {
  146. if (\snow_eq(count($this->scopes), 1)) {
  147. $new_name = uu(snow_list(array($this->ns, $name)));
  148. $is_global = true;
  149. } else {
  150. $new_name = $name;
  151. }
  152. } else {
  153. throw new Exception("Variable doesn't exist: " . $name);
  154. }
  155. }
  156. $this->add_node_to_scope($node, $name, $new_name, $is_global, $global_name);
  157. }
  158. public function enterNode(PHPParser_Node $node)
  159. {
  160. if (($node instanceof PHPParser_Node_Expr_Assign)) {
  161. $this->create_name($node, $node->var->name, true, true);
  162. $this->in_assign = true;
  163. } elseif (($node instanceof PHPParser_Node_Stmt_Function)) {
  164. $this->create_name($node, $node->name, false, true);
  165. $this->scopes->append($this->scopes[-1]->copy());
  166. $this->scopes[-1]->prefix->append($node->name);
  167. $this->scopes[-1]->func = $node;
  168. } elseif (($node instanceof PHPParser_Node_Expr_Variable)) {
  169. if (!$this->in_assign) {
  170. $this->create_name($node, $node->name, true, false);
  171. }
  172. } elseif (($node instanceof PHPParser_Node_Expr_FuncCall)) {
  173. if (\snow_eq(count($node->name->parts), 1)) {
  174. $this->create_name($node, $node->name->parts[0], true, false);
  175. $node->as_variable = true;
  176. }
  177. }
  178. }
  179. public function leaveNode(PHPParser_Node $node)
  180. {
  181. if (($node instanceof PHPParser_Node_Stmt_Imports)) {
  182. return false;
  183. }
  184. if (($node instanceof PHPParser_Node_Stmt_Function)) {
  185. $this->scopes->pop();
  186. }
  187. if (($node instanceof PHPParser_Node_Expr_Assign)) {
  188. $this->in_assign = false;
  189. }
  190. }
  191. public function afterTraverse(array $nodes)
  192. {
  193. $hmm = snow_list(array());
  194. if ($this->global_vars) {
  195. $node = new PHPParser_Node_Stmt_Global($hmm->arr);
  196. foreach ($this->global_vars as $global_var) {
  197. $node->vars[$global_var] = new PHPParser_Node_Expr_Variable($global_var);
  198. }
  199. unset($global_var);
  200. }
  201. array_unshift($nodes, $node);
  202. return $nodes;
  203. }
  204. public function add_imports($node)
  205. {
  206. $paths = snow_list(array());
  207. foreach ($node->import_paths as $import_path) {
  208. $paths[] = $import_path->name;
  209. }
  210. unset($import_path);
  211. $prefix = uu($paths);
  212. foreach ($node->imports as $imp) {
  213. $this->scopes[0]['imports'][$imp->name] = uu(snow_list(array($prefix, $imp->name)));
  214. }
  215. unset($imp);
  216. }
  217. }