LCOV - code coverage report
Current view: top level - lib - parser_class.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 171 171 100.0 %
Date: 2014-11-22 Functions: 5 5 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* parser_class.cpp -- written by Alexis WILKE for Made to Order Software Corp. (c) 2005-2014 */
       2             : 
       3             : /*
       4             : 
       5             : Copyright (c) 2005-2014 Made to Order Software Corp.
       6             : 
       7             : http://snapwebsites.org/project/as2js
       8             : 
       9             : Permission is hereby granted, free of charge, to any
      10             : person obtaining a copy of this software and
      11             : associated documentation files (the "Software"), to
      12             : deal in the Software without restriction, including
      13             : without limitation the rights to use, copy, modify,
      14             : merge, publish, distribute, sublicense, and/or sell
      15             : copies of the Software, and to permit persons to whom
      16             : the Software is furnished to do so, subject to the
      17             : following conditions:
      18             : 
      19             : The above copyright notice and this permission notice
      20             : shall be included in all copies or substantial
      21             : portions of the Software.
      22             : 
      23             : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
      24             : ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
      25             : LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
      26             : FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
      27             : EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
      28             : LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
      29             : WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
      30             : ARISING FROM, OUT OF OR IN CONNECTION WITH THE
      31             : SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
      32             : SOFTWARE.
      33             : 
      34             : */
      35             : 
      36             : #include    "as2js/parser.h"
      37             : #include    "as2js/message.h"
      38             : 
      39             : 
      40             : namespace as2js
      41             : {
      42             : 
      43             : 
      44             : /**********************************************************************/
      45             : /**********************************************************************/
      46             : /***  PARSER CLASS  ***************************************************/
      47             : /**********************************************************************/
      48             : /**********************************************************************/
      49             : 
      50      262162 : void Parser::class_declaration(Node::pointer_t& node, Node::node_t type)
      51             : {
      52      262162 :     node = f_lexer->get_new_node(type);
      53             : 
      54             :     // *** NAME ***
      55      262162 :     if(f_node->get_type() != Node::node_t::NODE_IDENTIFIER)
      56             :     {
      57       32768 :         Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INVALID_CLASS, f_lexer->get_input()->get_position());
      58       32768 :         msg << "the name of the class is expected after the keyword 'class'.";
      59             : 
      60       32768 :         switch(f_node->get_type())
      61             :         {
      62             :         case Node::node_t::NODE_EXTENDS:
      63             :         case Node::node_t::NODE_IMPLEMENTS:
      64             :         case Node::node_t::NODE_OPEN_CURVLY_BRACKET:
      65             :         //case Node::node_t::NODE_SEMICOLON: -- not necessary here
      66       32768 :             break;
      67             : 
      68             :         default:
      69      262162 :             return;
      70             : 
      71       32768 :         }
      72             :     }
      73             :     else
      74             :     {
      75      229394 :         node->set_string(f_node->get_string());
      76      229394 :         get_token();
      77             :     }
      78             : 
      79             :     // *** INHERITANCE ***
      80      262162 :     if(f_node->get_type() == Node::node_t::NODE_COLON)
      81             :     {
      82             :         // if we have a colon, followed by private, protected, or public
      83             :         // then it looks like a C++ declaration
      84       57344 :         Node::pointer_t save(f_node);
      85       57344 :         get_token();
      86      114688 :         if(f_node->get_type() == Node::node_t::NODE_EXTENDS
      87       57344 :         || f_node->get_type() == Node::node_t::NODE_IMPLEMENTS)
      88             :         {
      89       16384 :             Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INCOMPATIBLE, f_lexer->get_input()->get_position());
      90       16384 :             msg << "the 'extends' and 'implements' instructions cannot be preceeded by a colon.";
      91             :         }
      92       81920 :         else if(f_node->get_type() == Node::node_t::NODE_OPEN_CURVLY_BRACKET
      93       40960 :              || f_node->get_type() == Node::node_t::NODE_SEMICOLON)
      94             :         {
      95        8192 :             Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_CURVLY_BRACKETS_EXPECTED, f_lexer->get_input()->get_position());
      96        8192 :             msg << "the 'class' keyword cannot be followed by a colon.";
      97       57344 :         }
      98             :     }
      99             :     enum class status_t
     100             :     {
     101             :         STATUS_EXTENDS,
     102             :         STATUS_IMPLEMENTS,
     103             :         STATUS_DONE
     104             :     };
     105      262162 :     status_t status(status_t::STATUS_EXTENDS);
     106             :     // XXX: enforce extends, then implements? Or is that just me thinking
     107             :     //      that it should be in that order?
     108     1179736 :     while(f_node->get_type() == Node::node_t::NODE_EXTENDS
     109      376850 :        || f_node->get_type() == Node::node_t::NODE_IMPLEMENTS
     110      311314 :        || f_node->get_type() == Node::node_t::NODE_PRIVATE
     111      294930 :        || f_node->get_type() == Node::node_t::NODE_PROTECTED
     112      737333 :        || f_node->get_type() == Node::node_t::NODE_PUBLIC)
     113             :     {
     114      196625 :         Node::pointer_t inherits(f_node);
     115             : 
     116      196625 :         Node::node_t const extend_type(f_node->get_type());
     117             : 
     118             :         // this is used because C++ programmers are not unlikely to use one
     119             :         // of those keywords instead of 'exends' or 'implements'
     120      393250 :         if(f_node->get_type() == Node::node_t::NODE_PRIVATE
     121      180241 :         || f_node->get_type() == Node::node_t::NODE_PROTECTED
     122      360482 :         || f_node->get_type() == Node::node_t::NODE_PUBLIC)
     123             :         {
     124             :             // just skip the keyword and read the expression as expected
     125             :             // the expression can be a list
     126       49152 :             Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INCOMPATIBLE, f_lexer->get_input()->get_position());
     127       49152 :             msg << "please use 'extends' or 'implements' to define a list of base classes. 'public', 'private', and 'protected' are used in C++ only.";
     128             : 
     129       49152 :             inherits = f_node->create_replacement(Node::node_t::NODE_EXTENDS);
     130             :         }
     131      147473 :         else if(status != status_t::STATUS_EXTENDS
     132      147473 :              && f_node->get_type() != Node::node_t::NODE_IMPLEMENTS)
     133             :         {
     134        8192 :             Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INCOMPATIBLE, f_lexer->get_input()->get_position());
     135        8192 :             msg << "a class definition expects 'extends' first and then 'implements'.";
     136             :         }
     137      139281 :         else if(status == status_t::STATUS_DONE)
     138             :         {
     139        8192 :             Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INCOMPATIBLE, f_lexer->get_input()->get_position());
     140        8192 :             msg << "a class definition expects zero or one 'extends' and then zero or one 'implements'. Use commas to separate multiple inheritance names.";
     141             :         }
     142             : 
     143      196625 :         node->append_child(inherits);
     144             : 
     145      196625 :         get_token();
     146             : 
     147      393250 :         Node::pointer_t expr;
     148      196625 :         expression(expr);
     149             :         // TODO: EXTENDS and IMPLEMENTS do not accept assignments.
     150             :         //       verify that expr does not include any
     151      196625 :         inherits->append_child(expr);
     152             : 
     153      196625 :         if(status == status_t::STATUS_EXTENDS && extend_type == Node::node_t::NODE_EXTENDS)
     154             :         {
     155       73745 :             status = status_t::STATUS_IMPLEMENTS;
     156             :         }
     157             :         else
     158             :         {
     159      122880 :             status = status_t::STATUS_DONE;
     160             :         }
     161      196625 :     }
     162             : 
     163      262162 :     if(f_node->get_type() == Node::node_t::NODE_OPEN_CURVLY_BRACKET)
     164             :     {
     165      237586 :         get_token();
     166             : 
     167             :         // *** DECLARATION ***
     168      237586 :         if(f_node->get_type() != Node::node_t::NODE_CLOSE_CURVLY_BRACKET)
     169             :         {
     170      196619 :             Node::pointer_t directive_list_node;
     171      196619 :             directive_list(directive_list_node);
     172      196619 :             node->append_child(directive_list_node);
     173             :         }
     174             :         else
     175             :         {
     176             :             // this is important to distinguish an empty node from
     177             :             // a forward declaration
     178       40967 :             Node::pointer_t empty_node(f_lexer->get_new_node(Node::node_t::NODE_EMPTY));
     179       40967 :             node->append_child(empty_node);
     180             :         }
     181             : 
     182      237586 :         if(f_node->get_type() == Node::node_t::NODE_CLOSE_CURVLY_BRACKET)
     183             :         {
     184      229394 :             get_token();
     185             :         }
     186             :         else
     187             :         {
     188        8192 :             Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_CURVLY_BRACKETS_EXPECTED, f_lexer->get_input()->get_position());
     189        8192 :             msg << "'}' expected to close the 'class' definition.";
     190             :         }
     191             :     }
     192       24576 :     else if(f_node->get_type() != Node::node_t::NODE_SEMICOLON)
     193             :     {
     194       16384 :         Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_CURVLY_BRACKETS_EXPECTED, f_lexer->get_input()->get_position());
     195       16384 :         msg << "'{' expected to start the 'class' definition.";
     196             :     }
     197             :     // else -- accept empty class definitions (for typedef's and forward declaration)
     198             : }
     199             : 
     200             : 
     201             : 
     202             : 
     203             : /**********************************************************************/
     204             : /**********************************************************************/
     205             : /***  PARSER ENUM  ****************************************************/
     206             : /**********************************************************************/
     207             : /**********************************************************************/
     208             : 
     209      122881 : void Parser::enum_declaration(Node::pointer_t& node)
     210             : {
     211      122881 :     node = f_lexer->get_new_node(Node::node_t::NODE_ENUM);
     212             : 
     213      122881 :     bool const is_class(f_node->get_type() == Node::node_t::NODE_CLASS);
     214      122881 :     if(is_class)
     215             :     {
     216       32768 :         get_token();
     217       32768 :         node->set_flag(Node::flag_t::NODE_ENUM_FLAG_CLASS, true);
     218             :     }
     219             : 
     220             :     // enumerations can be unamed
     221      122881 :     if(f_node->get_type() == Node::node_t::NODE_IDENTIFIER)
     222             :     {
     223      114689 :         node->set_string(f_node->get_string());
     224      114689 :         get_token();
     225             :     }
     226             : 
     227             :     // in case the name was not specified, we can still have a type
     228      122881 :     if(f_node->get_type() == Node::node_t::NODE_COLON)
     229             :     {
     230       40960 :         get_token();
     231       40960 :         Node::pointer_t expr;
     232       40960 :         expression(expr);
     233       81920 :         Node::pointer_t type(f_lexer->get_new_node(Node::node_t::NODE_TYPE));
     234       40960 :         type->append_child(expr);
     235       81920 :         node->append_child(type);
     236             :     }
     237             : 
     238      122881 :     if(f_node->get_type() != Node::node_t::NODE_OPEN_CURVLY_BRACKET)
     239             :     {
     240       24576 :         if(f_node->get_type() == Node::node_t::NODE_SEMICOLON)
     241             :         {
     242             :             // empty enumeration (i.e. forward declaration)
     243       16384 :             if(node->get_string().empty())
     244             :             {
     245        8192 :                 Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INVALID_ENUM, f_lexer->get_input()->get_position());
     246        8192 :                 msg << "a forward enumeration must be named.";
     247             :             }
     248       16384 :             return;
     249             :         }
     250        8192 :         Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_CURVLY_BRACKETS_EXPECTED, f_lexer->get_input()->get_position());
     251        8192 :         msg << "'{' expected to start the 'enum' definition.";
     252        8192 :         return;
     253             :     }
     254             : 
     255       98305 :     get_token();
     256             : 
     257       98305 :     Node::pointer_t previous(f_lexer->get_new_node(Node::node_t::NODE_NULL));
     258      868361 :     while(f_node->get_type() != Node::node_t::NODE_CLOSE_CURVLY_BRACKET
     259      303107 :        && f_node->get_type() != Node::node_t::NODE_SEMICOLON
     260      679943 :        && f_node->get_type() != Node::node_t::NODE_EOF)
     261             :     {
     262      286723 :         if(f_node->get_type() == Node::node_t::NODE_COMMA)
     263             :         {
     264             :             // skip to the next token
     265       16384 :             get_token();
     266             : 
     267       16384 :             Message msg(message_level_t::MESSAGE_LEVEL_WARNING, err_code_t::AS_ERR_UNEXPECTED_PUNCTUATION, f_lexer->get_input()->get_position());
     268       16384 :             msg << "',' unexpected without a name.";
     269       16384 :             continue;
     270             :         }
     271      270339 :         String current_name("null");
     272      540678 :         Node::pointer_t entry(f_lexer->get_new_node(Node::node_t::NODE_VARIABLE));
     273      270339 :         node->append_child(entry);
     274      270339 :         if(f_node->get_type() == Node::node_t::NODE_IDENTIFIER)
     275             :         {
     276      245763 :             entry->set_flag(Node::flag_t::NODE_VARIABLE_FLAG_CONST, true);
     277      245763 :             entry->set_flag(Node::flag_t::NODE_VARIABLE_FLAG_ENUM, true);
     278      245763 :             current_name = f_node->get_string();
     279      245763 :             entry->set_string(current_name);
     280      245763 :             get_token();
     281             :         }
     282             :         else
     283             :         {
     284       24576 :             Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INVALID_ENUM, f_lexer->get_input()->get_position());
     285       24576 :             msg << "each 'enum' entry needs to include an identifier.";
     286       49152 :             if(f_node->get_type() != Node::node_t::NODE_ASSIGNMENT
     287        8192 :             && f_node->get_type() != Node::node_t::NODE_COMMA
     288       32768 :             && f_node->get_type() != Node::node_t::NODE_CLOSE_CURVLY_BRACKET)
     289             :             {
     290             :                 // skip that token otherwise we'd loop forever doing
     291             :                 // nothing more than generate errors
     292        8192 :                 get_token();
     293       24576 :             }
     294             :         }
     295      540678 :         Node::pointer_t expr;
     296      270339 :         if(f_node->get_type() == Node::node_t::NODE_ASSIGNMENT)
     297             :         {
     298      114691 :             get_token();
     299      114691 :             conditional_expression(expr, false);
     300             :         }
     301      155648 :         else if(previous->get_type() == Node::node_t::NODE_NULL)
     302             :         {
     303             :             // very first time
     304       65536 :             expr = f_lexer->get_new_node(Node::node_t::NODE_INT64);
     305             :             //expr->set_int64(0); -- this is the default
     306             :         }
     307             :         else
     308             :         {
     309       90112 :             expr = f_lexer->get_new_node(Node::node_t::NODE_ADD);
     310       90112 :             expr->append_child(previous); // left handside
     311       90112 :             Node::pointer_t one(f_lexer->get_new_node(Node::node_t::NODE_INT64));
     312       90112 :             Int64 int64_one;
     313       90112 :             int64_one.set(1);
     314       90112 :             one->set_int64(int64_one);
     315       90112 :             expr->append_child(one);
     316             :         }
     317             : 
     318      540678 :         Node::pointer_t set(f_lexer->get_new_node(Node::node_t::NODE_SET));
     319      270339 :         set->append_child(expr);
     320      270339 :         entry->append_child(set);
     321             : 
     322      270339 :         previous = f_lexer->get_new_node(Node::node_t::NODE_IDENTIFIER);
     323      270339 :         previous->set_string(current_name);
     324             : 
     325      270339 :         if(f_node->get_type() == Node::node_t::NODE_COMMA)
     326             :         {
     327      155650 :             get_token();
     328             :         }
     329      229378 :         else if(f_node->get_type() != Node::node_t::NODE_CLOSE_CURVLY_BRACKET
     330      114689 :              && f_node->get_type() != Node::node_t::NODE_SEMICOLON)
     331             :         {
     332       24576 :             Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_COMMA_EXPECTED, f_lexer->get_input()->get_position());
     333       24576 :             msg << "',' expected between enumeration elements.";
     334             :         }
     335      270339 :     }
     336             : 
     337       98305 :     if(f_node->get_type() == Node::node_t::NODE_CLOSE_CURVLY_BRACKET)
     338             :     {
     339       81921 :         get_token();
     340             :     }
     341             :     else
     342             :     {
     343       16384 :         Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_CURVLY_BRACKETS_EXPECTED, f_lexer->get_input()->get_position());
     344       16384 :         msg << "'}' expected to close the 'enum' definition.";
     345       98305 :     }
     346             : }
     347             : 
     348             : 
     349       73728 : void Parser::contract_declaration(Node::pointer_t& node, Node::node_t type)
     350             : {
     351       73728 :     node = f_lexer->get_new_node(type);
     352             : 
     353             :     // contract are labeled expressions
     354             :     for(;;)
     355             :     {
     356      131072 :         Node::pointer_t label(f_lexer->get_new_node(Node::node_t::NODE_LABEL));
     357      131072 :         node->append_child(label);
     358      131072 :         if(f_node->get_type() != Node::node_t::NODE_IDENTIFIER)
     359             :         {
     360        8192 :             Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INVALID_LABEL, f_lexer->get_input()->get_position());
     361        8192 :             msg << "'" << node->get_type_name() << "' must be followed by a list of labeled expressions.";
     362             :         }
     363             :         else
     364             :         {
     365      122880 :             label->set_string(f_node->get_string());
     366             :             // skip the identifier
     367      122880 :             get_token();
     368             :         }
     369      131072 :         if(f_node->get_type() != Node::node_t::NODE_COLON)
     370             :         {
     371        8192 :             Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_COLON_EXPECTED, f_lexer->get_input()->get_position());
     372        8192 :             msg << "the '" << node->get_type_name() << "' label must be followed by a colon (:).";
     373             :         }
     374             :         else
     375             :         {
     376             :             // skip the colon
     377      122880 :             get_token();
     378             :         }
     379      188416 :         Node::pointer_t expr;
     380      131072 :         conditional_expression(expr, false);
     381      131072 :         label->append_child(expr);
     382      131072 :         if(f_node->get_type() != Node::node_t::NODE_COMMA)
     383             :         {
     384       73728 :             break;
     385             :         }
     386             :         // skip the comma
     387       57344 :         get_token();
     388       57344 :     }
     389       73728 : }
     390             : 
     391             : 
     392          63 : }
     393             : // namespace as2js
     394             : 
     395             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.10