Code

Replaced in_array calls for gosa-plugins
[gosa.git] / gosa-plugins / mail / personal / mail / sieve / class_parser.inc
1 <?php
3 #include_once 'class.tree.php';
4 #include_once 'class.scanner.php';
5 #include_once 'class.semantics.php';
7 class Parser
8 {
9         var $scanner_;
10         var $script_;
11         var $tree_;
12         var $status_;
13         var $registeredExtensions_;
15         var $status_text;
17         function parse($script)
18         {
19                 $this->registeredExtensions_ = array();
20                 $this->status_text = "incomplete";
22                 $this->script_ = $script;
23                 $this->tree_ = new Tree(Scanner::scriptStart());
24                 $this->tree_->setDumpFunc(array(&$this, 'dumpToken_'));
25                 $this->scanner_ = new Scanner($this->script_);
26                 $this->scanner_->setCommentFunc(array($this, 'comment_'));
28                 if ($this->commands_($this->tree_->getRoot()) &&
29                     $this->scanner_->nextTokenIs('script-end'))
30                 {
31                         return $this->success_('success');
32                 }
34                 return $this->status_;
35         }
37         function dumpParseTree()
38         {
39                 return $this->tree_->dump();
40         }
42         function dumpToken_(&$token)
43         {
44                 if (is_array($token))
45                 {
46                         $str = "<" . $token['text'] . "> ";
47                         foreach ($token as $k => $v)
48                         {
49                                 $str .= " $k:$v";
50                         }
51                         return $str;
52                 }
54                 return strval($token);
55         }
57         function getPrevTokenText_($parent_id)
58         {
59                 $childs = $this->tree_->getChilds($parent_id);
61                 for ($i=count($childs); $i>0; --$i)
62                 {
63                         $prev = $this->tree_->getNode($childs[$i-1]);
65                         if (in_array_strict($prev['text'], array('{', '(', ',')))
66                         {
67                                 // use command owning a block or list
68                                 $prev = $this->tree_->getNode($parent_id);
69                         }
71                         if ($prev['class'] != 'comment')
72                         {
73                                 return $prev['text'];
74                         }
75                 }
77                 $prev = $this->tree_->getNode($parent_id);
78                 return $prev['text'];
79         }
81         function getSemantics_($token_text)
82         {
83                 $semantics = new Semantics($token_text);
84                 $semantics->setExtensionFuncs(array(&$this, 'registerExtension_'), array(&$this, 'isExtensionRegistered_'));
85                 return $semantics;
86         }
88         function registerExtension_($extension)
89         {
90                 array_push($this->registeredExtensions_, str_replace('"', '', $extension));
91         }
93         function isExtensionRegistered_($extension)
94         {
95                 return (in_array_strict($extension, $this->registeredExtensions_) ? true : false);
96         }
98         function success_($text = null)
99         {
100                 if ($text != null)
101                 {
102                         $this->status_text = $text;
103                 }
105                 return $this->status_ = true;
106         }
108         function error_($text, $token = null)
109         {
110                 if ($token != null)
111                 {
112                         $text = 'line '. $token['line'] .': '. $token['class'] . " where $text expected near ". $token['text'];
113                 }
115                 $this->status_text = $text;
116                 return $this->status_ = false;
117         }
119         function done_()
120         {
121                 $this->status_ = true;
122                 return false;
123         }
125         /*******************************************************************************
126          * methods for recursive descent start below
127          */
129         function comment_($token)
130         {
131                 $this->tree_->addChild($token);
132         }
134         function commands_($parent_id)
135         {
136                 while ($this->command_($parent_id))
137                         ;
139                 return $this->status_;
140         }
142         function command_($parent_id)
143         {
144                 if (!$this->scanner_->nextTokenIs('identifier'))
145                 {
146                         if ($this->scanner_->nextTokenIs(array('block-end', 'script-end')))
147                         {
148                                 return $this->done_();
149                         }
150                         return $this->error_('identifier', $this->scanner_->peekNextToken());
151                 }
153                 // Get and check a command token
154                 $token = $this->scanner_->nextToken();
155                 $semantics = $this->getSemantics_($token['text']);
156                 if (!$semantics->validCommand($this->getPrevTokenText_($parent_id), $token['line']))
157                 {
158                         return $this->error_($semantics->message);
159                 }
161                 // Process eventual arguments
162                 $this_node = $this->tree_->addChildTo($parent_id, $token);
163                 if ($this->arguments_($this_node, $semantics) == false)
164                 {
165                         return false;
166                 }
168                 $token = $this->scanner_->nextToken();
169                 if ($token['class'] != 'semicolon')
170                 {
171                         if (!$semantics->validToken($token['class'], $token['text'], $token['line']))
172                         {
173                                 return $this->error_($semantics->message);
174                         }
176                         if ($token['class'] == 'block-start')
177                         {
178                                 $this->tree_->addChildTo($this_node, $token);
179                                 $ret = $this->block_($this_node, $semantics);
180                                 return $ret;
181                         }
183                         return $this->error_('semicolon', $token);
184                 }
186                 $this->tree_->addChildTo($this_node, $token);
187                 return $this->success_();
188         }
190         function arguments_($parent_id, &$semantics)
191         {
192                 while ($this->argument_($parent_id, $semantics))
193                         ;
195                 if ($this->status_ == true)
196                 {
197                         $this->testlist_($parent_id, $semantics);
198                 }
200                 return $this->status_;
201         }
203         function argument_($parent_id, &$semantics)
204         {
205                 if ($this->scanner_->nextTokenIs(array('number', 'tag')))
206                 {
207                         // Check if semantics allow a number or tag
208                         $token = $this->scanner_->nextToken();
209                         if (!$semantics->validToken($token['class'], $token['text'], $token['line']))
210                         {
211                                 return $this->error_($semantics->message);
212                         }
214                         $this->tree_->addChildTo($parent_id, $token);
215                         return $this->success_();
216                 }
218                 return $this->stringlist_($parent_id, $semantics);
219         }
221         function stringlist_($parent_id, &$semantics)
222         {
223                 if (!$this->scanner_->nextTokenIs('left-bracket'))
224                 {
225                         return $this->string_($parent_id, $semantics);
226                 }
228                 $token = $this->scanner_->nextToken();
229                 if (!$semantics->startStringList($token['line']))
230                 {
231                         return $this->error_($semantics->message);
232                 }
233                 $this->tree_->addChildTo($parent_id, $token);
235                 while ($token['class'] != 'right-bracket')
236                 {
237                         if (!$this->string_($parent_id, $semantics))
238                         {
239                                 return $this->status_;
240                         }
242                         $token = $this->scanner_->nextToken();
244                         if ($token['class'] != 'comma' && $token['class'] != 'right-bracket')
245                         {
246                                 return $this->error_('comma or closing bracket', $token);
247                         }
249                         $this->tree_->addChildTo($parent_id, $token);
250                 }
252                 $semantics->endStringList();
253                 return $this->success_();
254         }
256         function string_($parent_id, &$semantics)
257         {
258                 if (!$this->scanner_->nextTokenIs(array('quoted-string', 'multi-line')))
259                 {
260                         return $this->done_();
261                 }
263                 $token = $this->scanner_->nextToken();
264                 if (!$semantics->validToken('string', $token['text'], $token['line']))
265                 {
266                         return $this->error_($semantics->message);
267                 }
269                 $this->tree_->addChildTo($parent_id, $token);
270                 return $this->success_();
271         }
273         function testlist_($parent_id, &$semantics)
274         {
275                 if (!$this->scanner_->nextTokenIs('left-parant'))
276                 {
277                         return $this->test_($parent_id, $semantics);
278                 }
280                 $token = $this->scanner_->nextToken();
281                 if (!$semantics->validToken($token['class'], $token['text'], $token['line']))
282                 {
283                         return $this->error_($semantics->message);
284                 }
285                 $this->tree_->addChildTo($parent_id, $token);
287                 while ($token['class'] != 'right-parant')
288                 {
289                         if (!$this->test_($parent_id, $semantics))
290                         {
291                                 return $this->status_;
292                         }
294                         $token = $this->scanner_->nextToken();
296                         if ($token['class'] != 'comma' && $token['class'] != 'right-parant')
297                         {
298                                 return $this->error_('comma or closing paranthesis', $token);
299                         }
301                         $this->tree_->addChildTo($parent_id, $token);
302                 }
304                 return $this->success_();
305         }
307         function test_($parent_id, &$semantics)
308         {
309                 if (!$this->scanner_->nextTokenIs('identifier'))
310                 {
311                         // There is no test
312                         return $this->done_();
313                 }
315                 // Check if semantics allow an identifier
316                 $token = $this->scanner_->nextToken();
317                 if (!$semantics->validToken($token['class'], $token['text'], $token['line']))
318                 {
319                         return $this->error_($semantics->message);
320                 }
322                 // Get semantics for this test command
323                 $this_semantics = $this->getSemantics_($token['text']);
324                 if (!$this_semantics->validCommand($this->getPrevTokenText_($parent_id), $token['line']))
325                 {
326                         return $this->error_($this_semantics->message);
327                 }
329                 $this_node = $this->tree_->addChildTo($parent_id, $token);
331                 // Consume eventual argument tokens
332                 if (!$this->arguments_($this_node, $this_semantics))
333                 {
334                         return false;
335                 }
337                 // Check if arguments were all there
338                 $token = $this->scanner_->peekNextToken();
339                 if (!$this_semantics->done($token['class'], $token['text'], $token['line']))
340                 {
341                         return $this->error_($this_semantics->message);
342                 }
344                 return true;
345         }
347         function block_($parent_id, &$semantics)
348         {
349                 if ($this->commands_($parent_id, $semantics))
350                 {
351                         $token = $this->scanner_->nextToken();
352         
353                         if ($token['class'] != 'block-end')
354                         {
355                                 return $this->error_('closing curly brace', $token);
356                         }
357         
358                         $this->tree_->addChildTo($parent_id, $token);
359                         return $this->success_();
360                 }
361                 return $this->status_;
362         }
365 ?>