Line data Source code
1 : // Copyright (c) 2005-2023 Made to Order Software Corp. All Rights Reserved
2 : //
3 : // https://snapwebsites.org/project/as2js
4 : // contact@m2osw.com
5 : //
6 : // This program is free software: you can redistribute it and/or modify
7 : // it under the terms of the GNU General Public License as published by
8 : // the Free Software Foundation, either version 3 of the License, or
9 : // (at your option) any later version.
10 : //
11 : // This program is distributed in the hope that it will be useful,
12 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : // GNU General Public License for more details.
15 : //
16 : // You should have received a copy of the GNU General Public License
17 : // along with this program. If not, see <https://www.gnu.org/licenses/>.
18 :
19 : // self
20 : //
21 : #include "as2js/parser.h"
22 : #include "as2js/message.h"
23 :
24 :
25 : namespace as2js
26 : {
27 :
28 :
29 : /**********************************************************************/
30 : /**********************************************************************/
31 : /*** PARSER CLASS ***************************************************/
32 : /**********************************************************************/
33 : /**********************************************************************/
34 :
35 414336 : void parser::class_declaration(node::pointer_t & class_node, node_t type)
36 : {
37 414336 : class_node = f_lexer->get_new_node(type);
38 :
39 : // *** NAME ***
40 414336 : if(f_node->get_type() != node_t::NODE_IDENTIFIER)
41 : {
42 32768 : message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INVALID_CLASS, f_lexer->get_position());
43 16384 : msg << "the name of the class is expected after the keyword \"class\".";
44 :
45 16384 : switch(f_node->get_type())
46 : {
47 16384 : case node_t::NODE_EXTENDS:
48 : case node_t::NODE_IMPLEMENTS:
49 : case node_t::NODE_OPEN_CURVLY_BRACKET:
50 : //case node_t::NODE_SEMICOLON: -- not necessary here
51 16384 : break;
52 :
53 0 : default:
54 0 : return;
55 :
56 : }
57 16384 : }
58 : else
59 : {
60 397952 : class_node->set_string(f_node->get_string());
61 397952 : get_token();
62 : }
63 :
64 : // *** INHERITANCE ***
65 414336 : if(f_node->get_type() == node_t::NODE_COLON)
66 : {
67 : // if we have a colon, followed by private, protected, or public
68 : // then it looks like a C++ declaration
69 28672 : node::pointer_t save(f_node);
70 28672 : get_token();
71 28672 : if(f_node->get_type() == node_t::NODE_EXTENDS
72 28672 : || f_node->get_type() == node_t::NODE_IMPLEMENTS)
73 : {
74 16384 : message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INCOMPATIBLE, f_lexer->get_position());
75 8192 : msg << "the \"extends\" and \"implements\" instructions cannot be preceeded by a colon.";
76 8192 : }
77 20480 : else if(f_node->get_type() == node_t::NODE_OPEN_CURVLY_BRACKET
78 20480 : || f_node->get_type() == node_t::NODE_SEMICOLON)
79 : {
80 8192 : message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_CURVLY_BRACKETS_EXPECTED, f_lexer->get_position());
81 4096 : msg << "the \"class\" keyword cannot be followed by a colon.";
82 4096 : }
83 28672 : }
84 : enum class status_t
85 : {
86 : STATUS_EXTENDS,
87 : STATUS_IMPLEMENTS,
88 : STATUS_DONE
89 : };
90 414336 : status_t status(status_t::STATUS_EXTENDS);
91 : // XXX: enforce extends, then implements? Or is that just me thinking
92 : // that it should be in that order?
93 759010 : while(f_node->get_type() == node_t::NODE_EXTENDS
94 471680 : || f_node->get_type() == node_t::NODE_IMPLEMENTS
95 438912 : || f_node->get_type() == node_t::NODE_PRIVATE
96 430720 : || f_node->get_type() == node_t::NODE_PROTECTED
97 1230690 : || f_node->get_type() == node_t::NODE_PUBLIC)
98 : {
99 344674 : node::pointer_t inherits(f_node);
100 :
101 344674 : node_t const extend_type(f_node->get_type());
102 :
103 : // this is used because C++ programmers are not unlikely to use one
104 : // of those keywords instead of 'extends' or 'implements'
105 : //
106 344674 : if(f_node->get_type() == node_t::NODE_PRIVATE
107 336482 : || f_node->get_type() == node_t::NODE_PROTECTED
108 681156 : || f_node->get_type() == node_t::NODE_PUBLIC)
109 : {
110 : // just skip the keyword and read the expression as expected
111 : // the expression can be a list
112 : //
113 49152 : message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INCOMPATIBLE, f_lexer->get_position());
114 24576 : msg << "please use \"extends\" or \"implements\" to define a list of base classes. \"public\", \"private\", and \"protected\" are used in C++ only.";
115 :
116 24576 : inherits = f_node->create_replacement(node_t::NODE_EXTENDS);
117 24576 : }
118 320098 : else if(status != status_t::STATUS_EXTENDS
119 320098 : && f_node->get_type() != node_t::NODE_IMPLEMENTS)
120 : {
121 8192 : message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INCOMPATIBLE, f_lexer->get_position());
122 4096 : msg << "a class definition expects \"extends\" first and then \"implements\".";
123 4096 : }
124 316002 : else if(status == status_t::STATUS_DONE)
125 : {
126 8192 : message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INCOMPATIBLE, f_lexer->get_position());
127 4096 : msg << "a class definition expects zero or one \"extends\" and then zero or one \"implements\". Use commas to separate multiple inheritance names.";
128 4096 : }
129 :
130 344674 : class_node->append_child(inherits);
131 :
132 344674 : get_token();
133 :
134 344674 : node::pointer_t expr;
135 344674 : expression(expr);
136 : // TODO: EXTENDS and IMPLEMENTS do not accept assignments.
137 : // verify that expr does not include any
138 344674 : inherits->append_child(expr);
139 :
140 344674 : if(status == status_t::STATUS_EXTENDS && extend_type == node_t::NODE_EXTENDS)
141 : {
142 283234 : status = status_t::STATUS_IMPLEMENTS;
143 : }
144 : else
145 : {
146 61440 : status = status_t::STATUS_DONE;
147 : }
148 344674 : }
149 :
150 414336 : if(f_node->get_type() == node_t::NODE_OPEN_CURVLY_BRACKET)
151 : {
152 402048 : get_token();
153 :
154 : // *** DECLARATION ***
155 402048 : if(f_node->get_type() != node_t::NODE_CLOSE_CURVLY_BRACKET)
156 : {
157 266684 : node::pointer_t directive_list_node;
158 266684 : directive_list(directive_list_node);
159 266684 : class_node->append_child(directive_list_node);
160 266684 : }
161 : else
162 : {
163 : // this is important to distinguish an empty node from
164 : // a forward declaration
165 135364 : node::pointer_t empty_node(f_lexer->get_new_node(node_t::NODE_EMPTY));
166 135364 : class_node->append_child(empty_node);
167 135364 : }
168 :
169 402048 : if(f_node->get_type() == node_t::NODE_CLOSE_CURVLY_BRACKET)
170 : {
171 397952 : get_token();
172 : }
173 : else
174 : {
175 8192 : message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_CURVLY_BRACKETS_EXPECTED, f_lexer->get_position());
176 4096 : msg << "\"}\" expected to close the \"class\" definition.";
177 4096 : }
178 : }
179 12288 : else if(f_node->get_type() != node_t::NODE_SEMICOLON)
180 : {
181 16384 : message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_CURVLY_BRACKETS_EXPECTED, f_lexer->get_position());
182 8192 : msg << "\"{\" expected to start the \"class\" definition.";
183 8192 : }
184 : // else -- accept empty class definitions (for typedef's and forward declaration)
185 : }
186 :
187 :
188 36864 : void parser::contract_declaration(node::pointer_t & contract, node_t type)
189 : {
190 36864 : contract = f_lexer->get_new_node(type);
191 :
192 : // contract are labeled expressions
193 : for(;;)
194 : {
195 65536 : node::pointer_t label(f_lexer->get_new_node(node_t::NODE_LABEL));
196 65536 : contract->append_child(label);
197 65536 : if(f_node->get_type() != node_t::NODE_IDENTIFIER)
198 : {
199 8192 : message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INVALID_LABEL, f_lexer->get_position());
200 4096 : msg << "\"" << contract->get_type_name() << "\" must be followed by a list of labeled expressions.";
201 4096 : }
202 : else
203 : {
204 61440 : label->set_string(f_node->get_string());
205 : // skip the identifier
206 61440 : get_token();
207 : }
208 65536 : if(f_node->get_type() != node_t::NODE_COLON)
209 : {
210 8192 : message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_COLON_EXPECTED, f_lexer->get_position());
211 4096 : msg << "the \"" << contract->get_type_name() << "\" label must be followed by a colon (:).";
212 4096 : }
213 : else
214 : {
215 : // skip the colon
216 61440 : get_token();
217 : }
218 65536 : node::pointer_t expr;
219 65536 : conditional_expression(expr, false);
220 65536 : label->append_child(expr);
221 65536 : if(f_node->get_type() != node_t::NODE_COMMA)
222 : {
223 36864 : break;
224 : }
225 : // skip the comma
226 28672 : get_token();
227 131072 : }
228 36864 : }
229 :
230 :
231 :
232 :
233 : /**********************************************************************/
234 : /**********************************************************************/
235 : /*** PARSER ENUM ****************************************************/
236 : /**********************************************************************/
237 : /**********************************************************************/
238 :
239 94236 : void parser::enum_declaration(node::pointer_t & enum_node)
240 : {
241 94236 : enum_node = f_lexer->get_new_node(node_t::NODE_ENUM);
242 :
243 : // like in C++ allow for the "class" keyword
244 : //
245 94236 : bool const is_class(f_node->get_type() == node_t::NODE_CLASS);
246 94236 : if(is_class)
247 : {
248 16384 : get_token();
249 16384 : enum_node->set_flag(flag_t::NODE_ENUM_FLAG_CLASS, true);
250 : }
251 :
252 : // enumerations can be unamed
253 : //
254 94236 : if(f_node->get_type() == node_t::NODE_IDENTIFIER)
255 : {
256 90140 : enum_node->set_string(f_node->get_string());
257 90140 : get_token();
258 : }
259 :
260 : // in case the name was not specified, we can still have a type
261 : //
262 94236 : if(f_node->get_type() == node_t::NODE_COLON)
263 : {
264 20480 : get_token();
265 20480 : node::pointer_t expr;
266 20480 : expression(expr);
267 20480 : node::pointer_t type(f_lexer->get_new_node(node_t::NODE_TYPE));
268 20480 : type->append_child(expr);
269 20480 : enum_node->append_child(type);
270 20480 : }
271 :
272 94236 : if(f_node->get_type() != node_t::NODE_OPEN_CURVLY_BRACKET)
273 : {
274 12288 : if(f_node->get_type() == node_t::NODE_SEMICOLON)
275 : {
276 : // empty enumeration (i.e. forward declaration)
277 : //
278 8192 : if(enum_node->get_string().empty())
279 : {
280 8192 : message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INVALID_ENUM, f_lexer->get_position());
281 4096 : msg << "a forward enumeration declaration must be named.";
282 4096 : }
283 8192 : return;
284 : }
285 8192 : message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_CURVLY_BRACKETS_EXPECTED, f_lexer->get_position());
286 4096 : msg << "\"{\" expected to start the \"enum\" definition.";
287 4096 : return;
288 4096 : }
289 :
290 81948 : get_token();
291 81948 : if(f_node->get_type() == node_t::NODE_CLOSE_CURVLY_BRACKET)
292 : {
293 : // this is required to be able to distinguish between an empty
294 : // enumeration (how useful though?!) and a forward definition
295 : //
296 8192 : node::pointer_t empty_node(f_lexer->get_new_node(node_t::NODE_EMPTY));
297 8192 : enum_node->append_child(empty_node);
298 8192 : }
299 : else
300 : {
301 73756 : node::pointer_t previous(f_lexer->get_new_node(node_t::NODE_NULL));
302 290928 : while(f_node->get_type() != node_t::NODE_CLOSE_CURVLY_BRACKET
303 225364 : && f_node->get_type() != node_t::NODE_SEMICOLON
304 516292 : && f_node->get_type() != node_t::NODE_EOF)
305 : {
306 217172 : if(f_node->get_type() == node_t::NODE_COMMA)
307 : {
308 : // skip to the next token
309 8192 : get_token();
310 :
311 16384 : message msg(message_level_t::MESSAGE_LEVEL_WARNING, err_code_t::AS_ERR_UNEXPECTED_PUNCTUATION, f_lexer->get_position());
312 8192 : msg << "\",\" unexpected without a name.";
313 8192 : continue;
314 8192 : }
315 417960 : std::string current_name("null");
316 208980 : node::pointer_t entry(f_lexer->get_new_node(node_t::NODE_VARIABLE));
317 208980 : enum_node->append_child(entry);
318 208980 : if(f_node->get_type() == node_t::NODE_IDENTIFIER)
319 : {
320 196692 : entry->set_flag(flag_t::NODE_VARIABLE_FLAG_CONST, true);
321 196692 : entry->set_flag(flag_t::NODE_VARIABLE_FLAG_ENUM, true);
322 196692 : current_name = f_node->get_string();
323 196692 : entry->set_string(current_name);
324 196692 : get_token();
325 : }
326 : else
327 : {
328 24576 : message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INVALID_ENUM, f_lexer->get_position());
329 12288 : msg << "each \"enum\" entry needs to include an identifier.";
330 12288 : if(f_node->get_type() != node_t::NODE_ASSIGNMENT
331 4096 : && f_node->get_type() != node_t::NODE_COMMA
332 16384 : && f_node->get_type() != node_t::NODE_CLOSE_CURVLY_BRACKET)
333 : {
334 : // skip that token otherwise we'd loop forever doing
335 : // nothing more than generate errors
336 : //
337 4096 : get_token();
338 : }
339 12288 : }
340 208980 : node::pointer_t expr;
341 208980 : if(f_node->get_type() == node_t::NODE_ASSIGNMENT)
342 : {
343 118868 : get_token();
344 118868 : conditional_expression(expr, false);
345 : }
346 90112 : else if(previous->get_type() == node_t::NODE_NULL)
347 : {
348 : // very first time
349 : //
350 36864 : expr = f_lexer->get_new_node(node_t::NODE_INTEGER);
351 : //expr->set_integer(0); -- this is the default
352 : }
353 : else
354 : {
355 53248 : expr = f_lexer->get_new_node(node_t::NODE_ADD);
356 53248 : expr->append_child(previous); // left handside
357 53248 : node::pointer_t one(f_lexer->get_new_node(node_t::NODE_INTEGER));
358 53248 : integer int_one;
359 53248 : int_one.set(1);
360 53248 : one->set_integer(int_one);
361 53248 : expr->append_child(one);
362 53248 : }
363 :
364 208980 : node::pointer_t set(f_lexer->get_new_node(node_t::NODE_SET));
365 208980 : set->append_child(expr);
366 208980 : entry->append_child(set);
367 :
368 208980 : previous = f_lexer->get_new_node(node_t::NODE_IDENTIFIER);
369 208980 : previous->set_string(current_name);
370 :
371 208980 : if(f_node->get_type() == node_t::NODE_COMMA)
372 : {
373 127032 : get_token();
374 : }
375 81948 : else if(f_node->get_type() != node_t::NODE_CLOSE_CURVLY_BRACKET
376 81948 : && f_node->get_type() != node_t::NODE_SEMICOLON)
377 : {
378 24576 : message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_COMMA_EXPECTED, f_lexer->get_position());
379 12288 : msg << "\",\" expected between enumeration elements.";
380 12288 : }
381 208980 : }
382 73756 : }
383 :
384 81948 : if(f_node->get_type() == node_t::NODE_CLOSE_CURVLY_BRACKET)
385 : {
386 73756 : get_token();
387 : }
388 : else
389 : {
390 16384 : message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_CURVLY_BRACKETS_EXPECTED, f_lexer->get_position());
391 8192 : msg << "\"}\" expected to close the \"enum\" definition.";
392 8192 : }
393 : }
394 :
395 :
396 : } // namespace as2js
397 : // vim: ts=4 sw=4 et
|