Code

Some changes for the sieve filter
[gosa.git] / include / sieve / class_parser.inc
1 <?php
2 class Parser
3 {
4         var $scanner_;
5         var $script_;
6         var $tree_;
7         var $status_;
9         var $status_text;
11         function parse($script)
12         {
13                 $this->status_text = "incomplete";
15                 $this->script_ = $script;
16                 $this->tree_ = new Tree(Scanner::scriptStart());
17                 $this->tree_->setDumpFunc(array(&$this, 'dumpToken_'));
18                 $this->scanner_ = new Scanner($this->script_);
19                 $this->scanner_->setCommentFunc(array($this, 'comment_'));
21                 if ($this->commands_($this->tree_->getRoot()) &&
22                     $this->scanner_->nextTokenIs('script-end'))
23                 {
24                         return $this->success_('success');
25                 }
27                 return $this->status_;
28         }
30         function dumpParseTree()
31         {
32                 return $this->tree_->dump();
33         }
35         function dumpToken_(&$token)
36         {
37                 if (is_array($token))
38                 {
39                         $str = "<" . $token['text'] . "> ";
40                         foreach ($token as $k => $v)
41                         {
42                                 $str .= " $k:$v";
43                         }
44                         return $str;
45                 }
47                 return strval($token);
48         }
50         function success_($text = null)
51         {
52                 if ($text != null)
53                 {
54                         $this->status_text = $text;
55                 }
57                 return $this->status_ = true;
58         }
60         function error_($text, $token = null)
61         {
62                 if ($token != null)
63                 {
64                         $text = 'line '. $token['line'] .': '. $token['class'] . " where $text expected near ". $token['text'];
65                 }
67                 $this->status_text = $text;
68                 return $this->status_ = false;
69         }
71         function done_()
72         {
73                 $this->status_ = true;
74                 return false;
75         }
77         function comment_($token)
78         {
79                 $this->tree_->addChild($token);
80         }
82         function commands_($parent_id)
83         {
84                 while ($this->command_($parent_id))
85                         ;
87                 return $this->status_;
88         }
90         function command_($parent_id)
91         {
92                 if (!$this->scanner_->nextTokenIs('identifier'))
93                 {
94                         if ($this->scanner_->nextTokenIs(array('block-end', 'script-end')))
95                         {
96                                 return $this->done_();
97                         }
98                         return $this->error_('identifier', $this->scanner_->peekNextToken());
99                 }
101                 // Get and check a command token
102                 $token = $this->scanner_->nextToken();
103                 $semantics = new Semantics($token['text']);
104                 if ($semantics->unknown)
105                 {
106                         return $this->error_('unknown command: '. $token['text']);
107                 }
109                 $last = $this->tree_->getLastNode($parent_id);
110                 if (!$semantics->validAfter($last['text']))
111                 {
112                         return $this->error_('"'. $token['text'] .'" may not appear after "'. $last['text'] .'"');
113                 }
115                 // Process eventual arguments
116                 $this_node = $this->tree_->addChildTo($parent_id, $token);
117                 if ($this->arguments_($this_node, $semantics) == false)
118                 {
119                         return false;
120                 }
122                 $token = $this->scanner_->nextToken();
123                 if ($token['class'] != 'semicolon')
124                 {
125                         if (!$semantics->validToken($token['class'], $token['text'], $token['line']))
126                         {
127                                 return $this->error_($semantics->message);
128                         }
130                         if ($token['class'] == 'block-start')
131                         {
132                                 $this->tree_->addChildTo($this_node, $token);
133                                 $ret = $this->block_($this_node, $semantics);
134                                 return $ret;
135                         }
137                         return $this->error_('semicolon', $token);
138                 }
140                 $this->tree_->addChildTo($this_node, $token);
141                 return $this->success_();
142         }
144         function arguments_($parent_id, &$semantics)
145         {
146                 while ($this->argument_($parent_id, &$semantics))
147                         ;
149                 if ($this->status_ == true)
150                 {
151                         $this->testlist_($parent_id, $semantics);
152                 }
154                 return $this->status_;
155         }
157         function argument_($parent_id, &$semantics)
158         {
159                 if ($this->scanner_->nextTokenIs(array('number', 'tag')))
160                 {
161                         // Check if semantics allow a number or tag
162                         $token = $this->scanner_->nextToken();
163                         if (!$semantics->validToken($token['class'], $token['text'], $token['line']))
164                         {
165                                 return $this->error_($semantics->message);
166                         }
168                         $this->tree_->addChildTo($parent_id, $token);
169                         return $this->success_();
170                 }
172                 return $this->stringlist_($parent_id, &$semantics);
173         }
175         function stringlist_($parent_id, &$semantics)
176         {
177                 if (!$this->scanner_->nextTokenIs('left-bracket'))
178                 {
179                         return $this->string_($parent_id, &$semantics);
180                 }
182                 $token = $this->scanner_->nextToken();
183                 if (!$semantics->startStringList($token['line']))
184                 {
185                         return $this->error_($semantics->message);
186                 }
187                 $this->tree_->addChildTo($parent_id, $token);
189                 while ($token['class'] != 'right-bracket')
190                 {
191                         if (!$this->string_($parent_id, &$semantics))
192                         {
193                                 return $this->status_;
194                         }
196                         $token = $this->scanner_->nextToken();
198                         if ($token['class'] != 'comma' && $token['class'] != 'right-bracket')
199                         {
200                                 return $this->error_('comma or closing bracket', $token);
201                         }
203                         $this->tree_->addChildTo($parent_id, $token);
204                 }
206                 $semantics->endStringList();
207                 return $this->success_();
208         }
210         function string_($parent_id, &$semantics)
211         {
212                 if (!$this->scanner_->nextTokenIs(array('quoted-string', 'multi-line')))
213                 {
214                         return $this->done_();
215                 }
217                 $token = $this->scanner_->nextToken();
218                 if (!$semantics->validToken('string', $token['text'], $token['line']))
219                 {
220                         return $this->error_($semantics->message);
221                 }
223                 $this->tree_->addChildTo($parent_id, $token);
224                 return $this->success_();
225         }
227         function testlist_($parent_id, &$semantics)
228         {
229                 if (!$this->scanner_->nextTokenIs('left-parant'))
230                 {
231                         return $this->test_($parent_id, $semantics);
232                 }
234                 $token = $this->scanner_->nextToken();
235                 if (!$semantics->validToken($token['class'], $token['text'], $token['line']))
236                 {
237                         return $this->error_($semantics->message);
238                 }
239                 $this->tree_->addChildTo($parent_id, $token);
241                 while ($token['class'] != 'right-parant')
242                 {
243                         if (!$this->test_($parent_id, $semantics))
244                         {
245                                 return $this->status_;
246                         }
248                         $token = $this->scanner_->nextToken();
250                         if ($token['class'] != 'comma' && $token['class'] != 'right-parant')
251                         {
252                                 return $this->error_('comma or closing paranthesis', $token);
253                         }
255                         $this->tree_->addChildTo($parent_id, $token);
256                 }
258                 return $this->success_();
259         }
261         function test_($parent_id, &$semantics)
262         {
263                 if (!$this->scanner_->nextTokenIs('identifier'))
264                 {
265                         // There is no test
266                         return $this->done_();
267                 }
269                 // Check if semantics allow an identifier
270                 $token = $this->scanner_->nextToken();
271                 if (!$semantics->validToken($token['class'], $token['text'], $token['line']))
272                 {
273                         return $this->error_($semantics->message);
274                 }
276                 // Get semantics for this test command
277                 $this_semantics = new Semantics($token['text']);
278                 if ($this_semantics->unknown)
279                 {
280                         return $this->error_('unknown test: '. $token['text']);
281                 }
283                 $this_node = $this->tree_->addChildTo($parent_id, $token);
285                 // Consume eventual argument tokens
286                 if (!$this->arguments_($this_node, $this_semantics))
287                 {
288                         return false;
289                 }
291                 // Check if arguments were all there
292                 $token = $this->scanner_->peekNextToken();
293                 if (!$this_semantics->done($token['class'], $token['text'], $token['line']))
294                 {
295                         return $this->error_($this_semantics->message);
296                 }
298                 return true;
299         }
301         function block_($parent_id, &$semantics)
302         {
303                 if ($this->commands_($parent_id, $semantics))
304                 {
305                         $token = $this->scanner_->nextToken();
306         
307                         if ($token['class'] != 'block-end')
308                         {
309                                 return $this->error_('closing curly brace', $token);
310                         }
311         
312                         $this->tree_->addChildTo($parent_id, $token);
313                         return $this->success_();
314                 }
315                 return $this->status_;
316         }
319 ?>