PageRenderTime 52ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/erlang_term_parser.php

http://erlang-term-php-parser.googlecode.com/
PHP | 254 lines | 194 code | 13 blank | 47 comment | 32 complexity | ef90cc7ce49365df5cc97a9e29b8d7e0 MD5 | raw file
  1. <?php
  2. /*
  3. @author Alexxz
  4. @project_url http://code.google.com/p/erlang-term-php-parser/
  5. This program is free software: you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation, either version 3 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. // just internal config function
  17. function erl_config($param){
  18. if($param === 'atom_string') return '_abcdefghijklmnopqrstuvwxyz';
  19. if($param === 'number_string') return '-0123456789.';
  20. return false;
  21. }
  22. /**
  23. * internal function parses erlang term from $i position
  24. * function looks at fist symbol and makes decision what kind of term it must parse
  25. *
  26. */
  27. function erl_parse_all($string, $i){
  28. $len = strlen($string);
  29. while($i < $len){
  30. $l = $string[$i];
  31. switch(true){
  32. case in_array($l, array(' ', "\n")): // stuff
  33. break;
  34. case $l === '[': // list
  35. return erl_parse_list($string, $i);
  36. break;
  37. case $l === '"': // quoted_list
  38. return erl_parse_quoted_list($string, $i);
  39. break;
  40. case $l === '{': // tuple
  41. return erl_parse_tuple($string, $i);
  42. break;
  43. case $l === '<': // pid
  44. return erl_parse_pid($string, $i);
  45. break;
  46. case false !== strpos(erl_config('atom_string'), $l):
  47. return erl_parse_atom($string, $i);
  48. break;
  49. case false !== strpos(erl_config('number_string'), $l):
  50. return erl_parse_number($string, $i);
  51. break;
  52. default:
  53. throw new Exception("Unexpected symbol $l in $i");
  54. break;
  55. }
  56. $i++;
  57. }
  58. throw new Exception("Error while parsing term");
  59. }
  60. /**
  61. * internal funtcion parses "square bracket list" from $i position of string
  62. */
  63. function erl_parse_list($string, $i){
  64. $sb_started = false; // square_bracket
  65. $list = array();
  66. $len = strlen($string);
  67. while($i < $len){
  68. $l = $string[$i]; // letter
  69. $n = ($i+1) < $len ? $string[$i+1] : false; // next letter
  70. switch(true){
  71. case $l === '[' && !$sb_started && $n === ']':
  72. $sb_started = true;
  73. break;
  74. case $l === '[' && !$sb_started :
  75. $sb_started = true;
  76. list($list[], $i) = erl_parse_all($string, $i+1);
  77. continue;
  78. case $l === ',':
  79. list($list[], $i) = erl_parse_all($string, $i+1);
  80. continue;
  81. case $l === ']' && $sb_started:
  82. return array(array('type'=>'list', 'data'=>$list), $i);
  83. break;
  84. default:
  85. throw new Exception("Unexpected symbol $l in $i");
  86. break;
  87. }
  88. $i++;
  89. }
  90. throw new Exception("Error while parsing list");
  91. }
  92. /**
  93. * internal function parses "quoted list from $i position of string"
  94. */
  95. function erl_parse_quoted_list($string, $i){
  96. $started = false;
  97. $escape = false;
  98. $list = array();
  99. $len = strlen($string);
  100. while($i < $len){
  101. $l = $string[$i]; // letter
  102. switch(true){
  103. case $l === '"' && !$started:
  104. $started = true;
  105. break;
  106. case $l === "\\" && !$escape:
  107. $escape = true;
  108. break;
  109. case $l === '"' && $escape:
  110. case $l === "\\" && $escape:
  111. $list[] = ord($l);
  112. $escape = false;
  113. break;
  114. case $l === '"' && $started:
  115. return array(array('type'=>'list', 'data'=>$list), $i);
  116. var_dump($list);
  117. break;
  118. default:
  119. $list[] = ord($l);
  120. $escape = false;
  121. break;
  122. }
  123. $i++;
  124. }
  125. throw new Exception("Error while parsing quoted list");
  126. }
  127. /**
  128. * internal function parses tuple from $i position of string
  129. */
  130. function erl_parse_tuple($string, $i){
  131. $started = false; //
  132. $list = array();
  133. $len = strlen($string);
  134. while($i < $len){
  135. $l = $string[$i];
  136. $n = ($i+1) < $len ? $string[$i+1] : false; // next letter
  137. switch(true){
  138. case $l === '{' && !$started && $n === '}':
  139. $started = true;
  140. break;
  141. case $l === '{' && !$started:
  142. list($list[], $i) = erl_parse_all($string, $i+1);
  143. $started = true;
  144. continue;
  145. case $l === ',':
  146. list($list[], $i) = erl_parse_all($string, $i+1);
  147. continue;
  148. case $l === '}' && $started:
  149. return array(array('type'=>'tuple', 'data'=>$list), $i);
  150. break;
  151. default:
  152. throw new Exception("Unexpected symbol $l in $i");
  153. break;
  154. }
  155. $i++;
  156. }
  157. throw new Exception("Error while parsing tuple");
  158. }
  159. /**
  160. * internal function parses atom from $i position of string
  161. */
  162. function erl_parse_atom($string, $i){
  163. $atom = '';
  164. $len = strlen($string);
  165. while($i < $len){
  166. $l = $string[$i];
  167. switch(true){
  168. case false !== strpos(erl_config('atom_string'), $l):
  169. $atom .= $l;
  170. break;
  171. default:
  172. return array(array('type'=>'atom', 'data'=>$atom), $i-1);
  173. break;
  174. }
  175. $i++;
  176. }
  177. throw new Exception("Error while parsing quoted atom");
  178. }
  179. /**
  180. * internal function parses int or float from $i position of string
  181. */
  182. function erl_parse_number($string, $i){
  183. $substr = substr($string, $i);
  184. $number_regexp = '/^[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?/';
  185. $out = array();
  186. if(!preg_match_all($number_regexp, substr($string, $i), $out)){
  187. throw new Exception("Unexpected sequence in $i");
  188. }
  189. $float = (float)$out[0][0];
  190. $int = (int)$out[0][0];
  191. $result = ((float)$int === $float) ? $int : $float;
  192. return array($result, $i+strlen($out[0][0])-1);
  193. }
  194. /**
  195. * internal function parses pid from $i position of string
  196. */
  197. function erl_parse_pid($string, $i){
  198. $out = array();
  199. if(!preg_match_all("/^<[0-9]+\.[0-9]+\.[0-9]+>/",substr($string, $i), $out)){
  200. throw new Exception("Unexpected sequence in $i");
  201. }
  202. return array(array('type'=>'pid', 'data'=>$out[0][0]), $i+strlen($out[0][0])-1);
  203. }
  204. /**
  205. * public function recurrently goes by resulted term and replaces "stringable" lists to strings
  206. */
  207. function erl_list2string($node){
  208. if(!is_array($node)){return $node;}
  209. if($node['type'] === 'tuple'){
  210. $new_data = array();
  211. foreach($node['data'] as $subnode) $new_data[] = erl_list2string($subnode);
  212. $node['data'] = $new_data;
  213. }
  214. if($node['type'] === 'list'){
  215. $is_string = true;
  216. $possible_string = '';
  217. foreach($node['data'] as $subnode){
  218. if($is_string = $is_string && is_int($subnode) && $subnode > 0 && $subnode < 256){
  219. $possible_string .= chr($subnode);
  220. }
  221. }
  222. if($is_string && strlen($possible_string) > 0){
  223. $node = $possible_string;
  224. } else {
  225. $new_data = array();
  226. foreach($node['data'] as $subnode) $new_data[] = erl_list2string($subnode);
  227. $node['data'] = $new_data;
  228. }
  229. }
  230. return $node;
  231. }
  232. /**
  233. * public function to parse string into term
  234. */
  235. function erl_parse_term($term_string){
  236. list($result, $offset) = erl_parse_all($term_string, 0);
  237. return $result;
  238. }