PageRenderTime 27ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/bindings/php/generator/scheme.php

https://code.google.com/p/oscats/
PHP | 504 lines | 439 code | 32 blank | 33 comment | 37 complexity | 1e1877aeac438b394cfcaccf58390ad0 MD5 | raw file
Possible License(s): GPL-3.0, GPL-2.0, LGPL-2.1
  1. <?php
  2. /*
  3. * PHP-GTK - The PHP language bindings for GTK+
  4. *
  5. * Copyright (C) 2001-2008 Andrei Zmievski <andrei@php.net>
  6. *
  7. * This library is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU Lesser General Public
  9. * License as published by the Free Software Foundation; either
  10. * version 2.1 of the License, or (at your option) any later version.
  11. *
  12. * This library is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with this library; if not, write to the Free Software
  19. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  20. */
  21. /* $Id: scheme.php,v 1.33 2008/02/29 19:05:53 andrei Exp $ */
  22. require "definitions.php";
  23. $char_table = str_repeat(' ', 256);
  24. foreach (range(0, 255) as $i)
  25. $char_table[$i] = chr($i);
  26. $translation_table = preg_replace('![^a-zA-Z_]!', '_', $char_table);
  27. function parse($filename)
  28. {
  29. if (!is_file($filename)) {
  30. die("Unable to open file $filename\n");
  31. }
  32. $fp = fopen($filename, 'r');
  33. $stack = array(array());
  34. $whitespace = " \t\n\r";
  35. $nonsymbol = $whitespace . '();\'"';
  36. $lineno = 0;
  37. $openlines = array();
  38. while ($line = fgets($fp, 4096)) {
  39. $pos = 0;
  40. $len = strlen($line);
  41. $lineno++;
  42. while ($pos < $len) {
  43. if (strpos($whitespace, $line{$pos}) !== false) {
  44. $pos++; continue;
  45. } else if ($line{$pos} == ';') {
  46. break;
  47. } else if (substr($line, $pos, 2) == "'(") {
  48. $pos++; continue;
  49. } else if ($line{$pos} == '(') {
  50. array_push($stack, array());
  51. $openlines[] = $lineno;
  52. } else if ($line{$pos} == ')') {
  53. if (!$openlines) {
  54. trigger_error("[$filename:$lineno] Closing parenthesis found without a match");
  55. return;
  56. }
  57. $closed = array_pop($stack);
  58. array_push($stack[count($stack)-1], $closed);
  59. array_pop($openlines);
  60. } else if ($line{$pos} == '"') {
  61. if (!$openlines) {
  62. trigger_error("[$filename:$lineno] String found outside of s-expression");
  63. return;
  64. }
  65. $endpos = strpos($line, '"', $pos+1);
  66. if ($endpos === false) {
  67. trigger_error("[$filename:$lineno] Unclosed quoted string");
  68. return;
  69. }
  70. array_push($stack[count($stack)-1], substr($line, $pos+1, $endpos-$pos-1));
  71. $pos = $endpos;
  72. } else {
  73. if (!$openlines) {
  74. trigger_error("[$filename:$lineno] Identifier found outside of s-expression");
  75. return;
  76. }
  77. $span = strcspn($line, $nonsymbol, $pos);
  78. $symbol = substr($line, $pos, $span);
  79. $pos += $span-1;
  80. if (is_numeric($symbol)) {
  81. $symbol = (double)$symbol;
  82. }
  83. array_push($stack[count($stack)-1], $symbol);
  84. }
  85. $pos++;
  86. }
  87. }
  88. if ($openlines) {
  89. trigger_error(sprintf("[$filename] Unclosed parentheses found on lines: %s", join(', ', $openlines)));
  90. return;
  91. }
  92. return $stack[0];
  93. }
  94. class Defs_Parser {
  95. var $parse_tree = null;
  96. var $parse_cache = null;
  97. var $file_path = null;
  98. var $file_name = null;
  99. var $objects = array(); // objects
  100. var $functions = array(); // module functions
  101. var $constructors = array(); // object constructors
  102. var $methods = array(); // object methods
  103. var $enums = array(); // enums and flags
  104. var $interfaces = array(); // interfaces
  105. var $boxed = array(); // boxed types
  106. var $pointers = array(); // pointers
  107. var $c_name = array(); // C names of entities
  108. var $gtkversion = null; // gtk lib version
  109. public function __construct($arg, $gtkversion = 0)
  110. {
  111. if (version_compare($gtkversion, '2.6', '<')) {
  112. $gtkversion = '2.6';
  113. }
  114. $this->gtkversion = $gtkversion;
  115. switch (gettype($arg)) {
  116. case 'string':
  117. $this->file_path = dirname($arg);
  118. $this->_set_file_version($arg, $this->gtkversion);
  119. $this->_parse_or_load();
  120. break;
  121. case 'array':
  122. $this->parse_tree = $arg;
  123. break;
  124. default:
  125. trigger_error('Constructor argument must be filename or array');
  126. break;
  127. }
  128. }
  129. private function _set_file_version($file_name, $gtkversion)
  130. {
  131. while (version_compare($gtkversion, '2.6', '>')) {
  132. $split = explode('.', $file_name);
  133. $try = $split[0].'-'.$gtkversion.'.'.$split[1];
  134. if (file_exists($try)) {
  135. $file_name = $try;
  136. break;
  137. }
  138. $point = substr($gtkversion, 2);
  139. $gtkversion = '2.'.($point - 2);
  140. $this->_set_file_version($file_name, $gtkversion);
  141. }
  142. $this->file_name = $file_name;
  143. }
  144. private function _parse_or_load()
  145. {
  146. $cache_file = $this->file_name.'.cache';
  147. if (@is_file($cache_file) &&
  148. filemtime($cache_file) > filemtime($this->file_name)) {
  149. error_log("Loading cache '". basename($cache_file) ."'");
  150. $fp = fopen($cache_file, 'r');
  151. $this->parse_cache = fread($fp, filesize($cache_file));
  152. fclose($fp);
  153. } else {
  154. error_log("Parsing file '$this->file_name'.");
  155. $this->parse_tree = parse($this->file_name, 'r');
  156. }
  157. }
  158. function start_parsing($tree = NULL)
  159. {
  160. if (isset($this->parse_cache)) {
  161. $this->unserialize($this->parse_cache);
  162. } else {
  163. if (!isset($tree))
  164. $tree = $this->parse_tree;
  165. foreach ($tree as $node)
  166. $this->handle($node);
  167. /*
  168. * Sort the objects list so that the child objects always come after
  169. * parent ones.
  170. */
  171. $objects = $this->objects;
  172. $pos = 0;
  173. $num_obj = count($objects);
  174. while ($pos < $num_obj) {
  175. $object = $objects[$pos];
  176. $parent = $object->parent;
  177. for ($i = $pos+1; $i < $num_obj; $i++) {
  178. if ($objects[$i]->c_name == $parent) {
  179. unset($objects[$pos]);
  180. array_splice($objects, $i+1, 0, array($object));
  181. break;
  182. }
  183. }
  184. if ($i == $num_obj)
  185. $pos++;
  186. }
  187. $this->objects = $objects;
  188. if (is_writeable($this->file_path)) {
  189. $cache_file = $this->file_name . '.cache';
  190. $fp = fopen($cache_file, 'w');
  191. fwrite($fp, $this->serialize());
  192. fclose($fp);
  193. }
  194. }
  195. }
  196. function serialize()
  197. {
  198. return serialize((array)$this);
  199. }
  200. function unserialize($buffer)
  201. {
  202. foreach (unserialize($buffer) as $var => $content) {
  203. $this->$var = $content;
  204. }
  205. }
  206. function merge_parse_tree($parser)
  207. {
  208. $this->parse_tree = array_merge($this->parse_tree, $parser->parse_tree);
  209. }
  210. function merge($old, $merge_params)
  211. {
  212. $all_defs = array_merge($this->objects, $this->boxed, $this->interfaces, $this->pointers);
  213. foreach ($all_defs as $def) {
  214. if (isset($old->c_name[$def->c_name])) {
  215. $def->merge($old->c_name[$def->c_name]);
  216. }
  217. }
  218. $all_defs = array_merge($this->functions, $this->constructors, $this->methods);
  219. foreach ($all_defs as $def) {
  220. if (isset($old->c_name[$def->c_name])) {
  221. $def->merge($old->c_name[$def->c_name], $merge_params);
  222. }
  223. }
  224. }
  225. function sort_defs($defs)
  226. {
  227. usort($defs, create_function('$a, $b', 'return strcasecmp($a->c_name, $b->c_name);'));
  228. return $defs;
  229. }
  230. function cmp_defs($a, $b)
  231. {
  232. if (($ca = get_class($a)) == ($cb = get_class($b))) {
  233. return strcasecmp($a->c_name, $b->c_name);
  234. } else {
  235. return strcmp($ca, $cb);
  236. }
  237. }
  238. function write_defs($fp = null)
  239. {
  240. if (!$fp) {
  241. $fp = STDOUT;
  242. }
  243. if ($this->boxed) {
  244. $my_defs = $this->boxed;
  245. usort($my_defs, array($this, 'cmp_defs'));
  246. fwrite($fp, ";; Boxed types ...\n\n");
  247. foreach ($my_defs as $object) {
  248. $object->write_defs($fp);
  249. }
  250. }
  251. if ($this->enums) {
  252. $my_defs = $this->enums;
  253. usort($my_defs, array($this, 'cmp_defs'));
  254. fwrite($fp, ";; Enumerations ...\n\n");
  255. foreach ($my_defs as $object) {
  256. $object->write_defs($fp);
  257. }
  258. }
  259. if ($this->interfaces) {
  260. $my_defs = $this->interfaces;
  261. usort($my_defs, array($this, 'cmp_defs'));
  262. fwrite($fp, ";; Interfaces ...\n\n");
  263. foreach ($my_defs as $object) {
  264. $object->write_defs($fp);
  265. }
  266. }
  267. /* don't sort objects */
  268. if ($this->objects) {
  269. fwrite($fp, ";; Objects ...\n\n");
  270. foreach ($this->objects as $object) {
  271. $object->write_defs($fp);
  272. }
  273. }
  274. if ($this->pointers) {
  275. $my_defs = $this->pointers;
  276. usort($my_defs, array($this, 'cmp_defs'));
  277. fwrite($fp, ";; Pointers ...\n\n");
  278. foreach ($my_defs as $pointer) {
  279. $pointer->write_defs($fp);
  280. }
  281. }
  282. if ($this->functions || $this->constructors || $this->methods) {
  283. $my_defs = $this->sort_defs(array_merge($this->functions, $this->constructors, $this->methods));
  284. fwrite($fp, ";; Functions, constructors, and methods ...\n\n");
  285. foreach ($my_defs as $object) {
  286. $object->write_defs($fp);
  287. }
  288. }
  289. }
  290. function write_missing_defs($old, $fp = null)
  291. {
  292. if (!$fp) {
  293. $fp = STDOUT;
  294. }
  295. foreach ($this->sort_defs($this->boxed) as $object) {
  296. if (!isset($old->c_name[$object->c_name])) {
  297. $object->write_defs($fp);
  298. }
  299. }
  300. foreach ($this->sort_defs($this->interfaces) as $object) {
  301. if (!isset($old->c_name[$object->c_name])) {
  302. $object->write_defs($fp);
  303. }
  304. }
  305. foreach ($this->sort_defs($this->objects) as $object) {
  306. if (!isset($old->c_name[$object->c_name])) {
  307. $object->write_defs($fp);
  308. }
  309. }
  310. foreach ($this->sort_defs($this->enums) as $object) {
  311. if (!isset($old->c_name[$object->c_name])) {
  312. $object->write_defs($fp);
  313. }
  314. }
  315. foreach ($this->sort_defs(array_merge($this->constructors, $this->functions, $this->methods)) as $object) {
  316. if (!isset($old->c_name[$object->c_name])) {
  317. $object->write_defs($fp);
  318. }
  319. }
  320. }
  321. function handle($node)
  322. {
  323. global $char_table,
  324. $translation_table;
  325. $cmd = "handle_" . strtr($node[0], $char_table, $translation_table);
  326. if (method_exists($this, $cmd))
  327. $this->$cmd(array_slice($node, 1));
  328. else
  329. $this->handle_unknown($node);
  330. }
  331. function handle_define_enum($arg)
  332. {
  333. $enum_def = new Enum_Def($arg);
  334. if (basename($this->file_path) == 'gtk+')
  335. $enum_def->simple = false;
  336. $this->enums[] = $enum_def;
  337. $this->c_name[$enum_def->c_name] = $enum_def;
  338. }
  339. function handle_define_flags($arg)
  340. {
  341. $flag_def = new Flag_Def($arg);
  342. $this->enums[] = $flag_def;
  343. $this->c_name[$flag_def->c_name] = $flag_def;
  344. }
  345. function handle_define_function($arg)
  346. {
  347. $function_def = new Function_Def($arg);
  348. if (isset($function_def->is_constructor_of)) {
  349. $old_def = @$this->functions[$function_def->c_name];
  350. if (!isset($old_def) || $old_def->c_name == $old_def->name) {
  351. $this->constructors[$function_def->c_name] = $function_def;
  352. }
  353. } else {
  354. $old_def = @$this->functions[$function_def->c_name];
  355. if (!isset($old_def) || $old_def->c_name == $old_def->name) {
  356. $this->functions[$function_def->c_name] = $function_def;
  357. }
  358. }
  359. $this->c_name[$function_def->c_name] = $function_def;
  360. }
  361. function handle_define_method($arg)
  362. {
  363. $method_def = new Method_Def($arg);
  364. $this->methods[] = $method_def;
  365. $this->c_name[$method_def->c_name] = $method_def;
  366. }
  367. function handle_define_object($arg)
  368. {
  369. $object_def = new Object_Def($arg);
  370. $this->objects[] = $object_def;
  371. $this->c_name[$object_def->c_name] = $object_def;
  372. }
  373. function handle_define_interface($arg)
  374. {
  375. $interface_def = new Interface_Def($arg);
  376. $this->interfaces[$interface_def->c_name] = $interface_def;
  377. $this->c_name[$interface_def->c_name] = $interface_def;
  378. }
  379. function handle_define_boxed($arg)
  380. {
  381. $boxed_def = new Boxed_Def($arg);
  382. $this->boxed[] = $boxed_def;
  383. $this->c_name[$boxed_def->c_name] = $boxed_def;
  384. }
  385. function handle_define_pointer($arg)
  386. {
  387. $pointer_def = new Pointer_Def($arg);
  388. $this->pointers[] = $pointer_def;
  389. $this->c_name[$pointer_def->c_name] = $pointer_def;
  390. }
  391. function handle_include($arg)
  392. {
  393. $include_file = $this->file_path . DIRECTORY_SEPARATOR . $arg[0];
  394. error_log("Parsing file '$include_file'.");
  395. $include_tree = parse($include_file, 'r');
  396. $this->start_parsing($include_tree);
  397. }
  398. function handle_define_virtual($arg)
  399. {
  400. /* do nothing for now */
  401. }
  402. function handle_unknown($node)
  403. {
  404. /* noop */
  405. die("unknown node:\n". var_export($node, 1));
  406. }
  407. function find_methods($object)
  408. {
  409. $obj_methods = array();
  410. foreach ($this->methods as $method) {
  411. if ($method->of_object == $object->c_name)
  412. $obj_methods[] = $method;
  413. }
  414. return $obj_methods;
  415. }
  416. function find_constructor($obj, $overrides)
  417. {
  418. $constructors = array();
  419. foreach ($this->constructors as $constructor) {
  420. if ($constructor->is_constructor_of == $obj->c_name &&
  421. !$overrides->is_ignored($constructor->c_name)) {
  422. $constructors[] = $constructor;
  423. }
  424. }
  425. return $constructors;
  426. }
  427. function find_parent($obj)
  428. {
  429. if (isset($obj->parent)) {
  430. return $this->objects[$obj->parent[1] . $obj->parent[0]];
  431. }
  432. }
  433. }
  434. #require './arg_types.php';
  435. #$d = new Defs_Parser('test.defs');
  436. #$d->start_parsing();
  437. #var_dump($d->constructors);
  438. #var_dump($d->functions);
  439. #var_dump($d->methods);
  440. #var_dump($d->objects);
  441. #var_dump($d->enums);
  442. #var_dump($d->boxed);
  443. #var_dump($d->interfaces);
  444. /* vim: set et sts=4: */
  445. ?>