LCOV - code coverage report
Current view: top level - as2js/parser - parser_class.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 192 194 99.0 %
Date: 2023-07-29 22:00:24 Functions: 3 3 100.0 %
Legend: Lines: hit not hit

          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

Generated by: LCOV version 1.14