LCOV - code coverage report
Current view: top level - as2js/lib - parser_package.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 181 181 100.0 %
Date: 2014-08-10 Functions: 6 6 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* parser_package.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 PACKAGE  *************************************************/
      47             : /**********************************************************************/
      48             : /**********************************************************************/
      49             : 
      50      114702 : void Parser::package(Node::pointer_t& node)
      51             : {
      52      114702 :     String        name;
      53             : 
      54      114702 :     node = f_lexer->get_new_node(Node::node_t::NODE_PACKAGE);
      55             : 
      56      114702 :     if(f_node->get_type() == Node::node_t::NODE_IDENTIFIER)
      57             :     {
      58       57351 :         name = f_node->get_string();
      59       57351 :         get_token();
      60      139281 :         while(f_node->get_type() == Node::node_t::NODE_MEMBER)
      61             :         {
      62       81930 :             get_token();
      63       81930 :             if(f_node->get_type() != Node::node_t::NODE_IDENTIFIER)
      64             :             {
      65             :                 // unexpected token/missing name
      66       24579 :                 Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INVALID_PACKAGE_NAME, f_lexer->get_input()->get_position());
      67       24579 :                 msg << "invalid package name (expected an identifier after the last '.').";
      68       49158 :                 if(f_node->get_type() == Node::node_t::NODE_OPEN_CURVLY_BRACKET
      69       16386 :                 || f_node->get_type() == Node::node_t::NODE_CLOSE_CURVLY_BRACKET
      70       40965 :                 || f_node->get_type() == Node::node_t::NODE_SEMICOLON)
      71             :                 {
      72       24579 :                     break;
      73       24579 :                 }
      74             :                 // try some more...
      75             :             }
      76             :             else
      77             :             {
      78       57351 :                 name += ".";
      79       57351 :                 name += f_node->get_string();
      80             :             }
      81       73737 :             get_token();
      82             :         }
      83             :     }
      84       57351 :     else if(f_node->get_type() == Node::node_t::NODE_STRING)
      85             :     {
      86       57351 :         name = f_node->get_string();
      87             :         // TODO: Validate Package Name (in case of a STRING)
      88             :         // I think we need to check out the name here to make sure
      89             :         // that's a valid package name (not too sure though whether
      90             :         // we can't just have any name)
      91       57351 :         get_token();
      92             :     }
      93             : 
      94             :     // set the name and flags of this package
      95      114702 :     node->set_string(name);
      96             : 
      97      114702 :     if(f_node->get_type() == Node::node_t::NODE_OPEN_CURVLY_BRACKET)
      98             :     {
      99      106509 :         get_token();
     100             :     }
     101             :     else
     102             :     {
     103        8193 :         Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_CURVLY_BRACKETS_EXPECTED, f_lexer->get_input()->get_position());
     104        8193 :         msg << "'{' expected after the package name.";
     105             :         // TODO: should we return and not try to read the package?
     106             :     }
     107             : 
     108      114702 :     Node::pointer_t directives;
     109      114702 :     directive_list(directives);
     110      114702 :     node->append_child(directives);
     111             : 
     112             :     // when we return we should have a '}'
     113      114702 :     if(f_node->get_type() == Node::node_t::NODE_CLOSE_CURVLY_BRACKET)
     114             :     {
     115      106509 :         get_token();
     116             :     }
     117             :     else
     118             :     {
     119        8193 :         Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_CURVLY_BRACKETS_EXPECTED, f_lexer->get_input()->get_position());
     120        8193 :         msg << "'}' expected after the package declaration.";
     121      114702 :     }
     122      114702 : }
     123             : 
     124             : 
     125             : 
     126             : 
     127             : /**********************************************************************/
     128             : /**********************************************************************/
     129             : /***  PARSER IMPORT  **************************************************/
     130             : /**********************************************************************/
     131             : /**********************************************************************/
     132             : 
     133      163860 : void Parser::import(Node::pointer_t& node)
     134             : {
     135      163860 :     node = f_lexer->get_new_node(Node::node_t::NODE_IMPORT);
     136             : 
     137      163860 :     if(f_node->get_type() == Node::node_t::NODE_IMPLEMENTS)
     138             :     {
     139        8193 :         node->set_flag(Node::flag_t::NODE_IMPORT_FLAG_IMPLEMENTS, true);
     140        8193 :         get_token();
     141             :     }
     142             : 
     143      163860 :     if(f_node->get_type() == Node::node_t::NODE_IDENTIFIER)
     144             :     {
     145      147474 :         String name;
     146      294948 :         Node::pointer_t first(f_node);
     147      147474 :         get_token();
     148      147474 :         bool const is_renaming = f_node->get_type() == Node::node_t::NODE_ASSIGNMENT;
     149      147474 :         if(is_renaming)
     150             :         {
     151             :             // add first as the package alias
     152       40965 :             node->append_child(first);
     153             : 
     154       40965 :             get_token();
     155       40965 :             if(f_node->get_type() == Node::node_t::NODE_STRING)
     156             :             {
     157       16386 :                 name = f_node->get_string();
     158       16386 :                 get_token();
     159       32772 :                 if(f_node->get_type() == Node::node_t::NODE_MEMBER
     160        8193 :                 || f_node->get_type() == Node::node_t::NODE_RANGE
     161       24579 :                 || f_node->get_type() == Node::node_t::NODE_REST)
     162             :                 {
     163        8193 :                     Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INVALID_PACKAGE_NAME, f_lexer->get_input()->get_position());
     164       16386 :                     msg << "a package name is either a string or a list of identifiers separated by periods (.); you cannot mixed both.";
     165             :                 }
     166             :             }
     167       24579 :             else if(f_node->get_type() == Node::node_t::NODE_IDENTIFIER)
     168             :             {
     169       16386 :                 name = f_node->get_string();
     170       16386 :                 get_token();
     171             :             }
     172             :             else
     173             :             {
     174        8193 :                 Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INVALID_PACKAGE_NAME, f_lexer->get_input()->get_position());
     175       40965 :                 msg << "the name of a package was expected.";
     176             :             }
     177             :         }
     178             :         else
     179             :         {
     180      106509 :             name = first->get_string();
     181             :         }
     182             : 
     183      147474 :         int everything(0);
     184      737370 :         while(f_node->get_type() == Node::node_t::NODE_MEMBER
     185      172053 :            || f_node->get_type() == Node::node_t::NODE_RANGE
     186      540738 :            || f_node->get_type() == Node::node_t::NODE_REST)
     187             :         {
     188      458808 :             if(f_node->get_type() == Node::node_t::NODE_RANGE
     189      229404 :             || f_node->get_type() == Node::node_t::NODE_REST)
     190             :             {
     191       32772 :                 Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INVALID_PACKAGE_NAME, f_lexer->get_input()->get_position());
     192       32772 :                 msg << "the name of a package is expected to be separated by single periods (.).";
     193             :             }
     194      229404 :             if(everything == 1)
     195             :             {
     196       16386 :                 everything = 2;
     197       16386 :                 Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INVALID_PACKAGE_NAME, f_lexer->get_input()->get_position());
     198       16386 :                 msg << "the * notation can only be used once at the end of a name.";
     199             :             }
     200      229404 :             name += ".";
     201      229404 :             get_token();
     202      229404 :             if(f_node->get_type() == Node::node_t::NODE_MULTIPLY)
     203             :             {
     204       32772 :                 if(is_renaming && everything == 0)
     205             :                 {
     206        8193 :                     Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INVALID_PACKAGE_NAME, f_lexer->get_input()->get_position());
     207        8193 :                     msg << "the * notation cannot be used when renaming an import.";
     208        8193 :                     everything = 2;
     209             :                 }
     210             :                 // everything in that directory
     211       32772 :                 name += "*";
     212       32772 :                 if(everything == 0)
     213             :                 {
     214       32772 :                     everything = 1;
     215             :                 }
     216             :             }
     217      196632 :             else if(f_node->get_type() != Node::node_t::NODE_IDENTIFIER)
     218             :             {
     219       16386 :                 if(f_node->get_type() == Node::node_t::NODE_STRING)
     220             :                 {
     221        8193 :                     Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INVALID_PACKAGE_NAME, f_lexer->get_input()->get_position());
     222        8193 :                     msg << "a package name is either a string or a list of identifiers separated by periods (.); you cannot mixed both.";
     223             :                     // skip the string, just in case
     224        8193 :                     get_token();
     225             :                 }
     226             :                 else
     227             :                 {
     228        8193 :                     Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INVALID_PACKAGE_NAME, f_lexer->get_input()->get_position());
     229        8193 :                     msg << "the name of a package was expected.";
     230             :                 }
     231       32772 :                 if(f_node->get_type() == Node::node_t::NODE_MEMBER
     232        8193 :                 || f_node->get_type() == Node::node_t::NODE_RANGE
     233       24579 :                 || f_node->get_type() == Node::node_t::NODE_REST)
     234             :                 {
     235             :                     // in case of another '.' (or a few other '.')
     236        8193 :                     continue;
     237             :                 }
     238        8193 :                 break;
     239             :             }
     240             :             else
     241             :             {
     242      180246 :                 name += f_node->get_string();
     243             :             }
     244      213018 :             get_token();
     245             :         }
     246             : 
     247      294948 :         node->set_string(name);
     248             :     }
     249       16386 :     else if(f_node->get_type() == Node::node_t::NODE_STRING)
     250             :     {
     251             :         // TODO: Validate Package Name (in case of a STRING)
     252        8193 :         node->set_string(f_node->get_string());
     253        8193 :         get_token();
     254             :     }
     255             :     else
     256             :     {
     257        8193 :         Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INVALID_PACKAGE_NAME, f_lexer->get_input()->get_position());
     258        8193 :         msg << "a composed name or a string was expected after 'import'.";
     259        8193 :         if(f_node->get_type() != Node::node_t::NODE_SEMICOLON && f_node->get_type() != Node::node_t::NODE_COMMA)
     260             :         {
     261        8193 :             get_token();
     262        8193 :         }
     263             :     }
     264             : 
     265             :     // Any namespace and/or include/exclude info?
     266             :     // NOTE: We accept multiple namespace and multiple include
     267             :     //     or exclude.
     268             :     //     However, include and exclude are mutually exclusive.
     269      163860 :     long include_exclude = 0;
     270      278562 :     while(f_node->get_type() == Node::node_t::NODE_COMMA)
     271             :     {
     272      114702 :         get_token();
     273      114702 :         if(f_node->get_type() == Node::node_t::NODE_NAMESPACE)
     274             :         {
     275        8193 :             get_token();
     276             :             // read the namespace (an expression)
     277        8193 :             Node::pointer_t expr;
     278        8193 :             conditional_expression(expr, false);
     279       16386 :             Node::pointer_t use(f_lexer->get_new_node(Node::node_t::NODE_USE /*namespace*/));
     280        8193 :             use->append_child(expr);
     281       16386 :             node->append_child(use);
     282             :         }
     283      106509 :         else if(f_node->get_type() == Node::node_t::NODE_IDENTIFIER)
     284             :         {
     285       90123 :             if(f_node->get_string() == "include")
     286             :             {
     287       32772 :                 if(include_exclude == 2)
     288             :                 {
     289        8193 :                     Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INVALID_IMPORT, f_lexer->get_input()->get_position());
     290        8193 :                     msg << "include and exclude are mutually exclusive.";
     291        8193 :                     include_exclude = 3;
     292             :                 }
     293       24579 :                 else if(include_exclude == 0)
     294             :                 {
     295       24579 :                     include_exclude = 1;
     296             :                 }
     297       32772 :                 get_token();
     298             :                 // read the list of inclusion (an expression)
     299       32772 :                 Node::pointer_t expr;
     300       32772 :                 conditional_expression(expr, false);
     301       65544 :                 Node::pointer_t include(f_lexer->get_new_node(Node::node_t::NODE_INCLUDE));
     302       32772 :                 include->append_child(expr);
     303       65544 :                 node->append_child(include);
     304             :             }
     305       57351 :             else if(f_node->get_string() == "exclude")
     306             :             {
     307       49158 :                 if(include_exclude == 1)
     308             :                 {
     309        8193 :                     Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INVALID_IMPORT, f_lexer->get_input()->get_position());
     310        8193 :                     msg << "include and exclude are mutually exclusive.";
     311        8193 :                     include_exclude = 3;
     312             :                 }
     313       40965 :                 else if(include_exclude == 0)
     314             :                 {
     315       32772 :                     include_exclude = 2;
     316             :                 }
     317       49158 :                 get_token();
     318             :                 // read the list of exclusion (an expression)
     319       49158 :                 Node::pointer_t expr;
     320       49158 :                 conditional_expression(expr, false);
     321       98316 :                 Node::pointer_t exclude(f_lexer->get_new_node(Node::node_t::NODE_EXCLUDE));
     322       49158 :                 exclude->append_child(expr);
     323       98316 :                 node->append_child(exclude);
     324             :             }
     325             :             else
     326             :             {
     327        8193 :                 Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INVALID_IMPORT, f_lexer->get_input()->get_position());
     328       90123 :                 msg << "namespace, include or exclude was expected after the comma.";
     329             :             }
     330             :         }
     331       16386 :         else if(f_node->get_type() == Node::node_t::NODE_COMMA)
     332             :         {
     333        8193 :             Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INVALID_IMPORT, f_lexer->get_input()->get_position());
     334        8193 :             msg << "two commas in a row is not allowed while describing an import.";
     335             :         }
     336             :     }
     337      163860 : }
     338             : 
     339             : 
     340             : 
     341             : 
     342             : 
     343             : /**********************************************************************/
     344             : /**********************************************************************/
     345             : /***  PARSER NAMESPACE  ***********************************************/
     346             : /**********************************************************************/
     347             : /**********************************************************************/
     348             : 
     349       16386 : void Parser::use_namespace(Node::pointer_t& node)
     350             : {
     351       16386 :     Node::pointer_t expr;
     352       16386 :     expression(expr);
     353       16386 :     node = f_lexer->get_new_node(Node::node_t::NODE_USE /*namespace*/);
     354       16386 :     node->append_child(expr);
     355       16386 : }
     356             : 
     357             : 
     358             : 
     359       40965 : void Parser::namespace_block(Node::pointer_t& node, Node::pointer_t& attr_list)
     360             : {
     361       40965 :     node = f_lexer->get_new_node(Node::node_t::NODE_NAMESPACE);
     362             : 
     363       40965 :     if(f_node->get_type() == Node::node_t::NODE_IDENTIFIER)
     364             :     {
     365             :         // save the name of the namespace
     366       16386 :         node->set_string(f_node->get_string());
     367       16386 :         get_token();
     368             :     }
     369             :     else
     370             :     {
     371       24579 :         bool has_private(false);
     372       24579 :         if(!attr_list)
     373             :         {
     374        8193 :             attr_list = f_lexer->get_new_node(Node::node_t::NODE_ATTRIBUTES);
     375             :         }
     376             :         else
     377             :         {
     378       16386 :             size_t const max_attrs(attr_list->get_children_size());
     379       40965 :             for(size_t idx(0); idx < max_attrs; ++idx)
     380             :             {
     381       32772 :                 if(attr_list->get_child(idx)->get_type() == Node::node_t::NODE_PRIVATE)
     382             :                 {
     383             :                     // already set, so we do not need to add another private attribute
     384        8193 :                     has_private = true;
     385        8193 :                     break;
     386             :                 }
     387             :             }
     388             :         }
     389       24579 :         if(!has_private)
     390             :         {
     391       16386 :             Node::pointer_t private_node(f_lexer->get_new_node(Node::node_t::NODE_PRIVATE));
     392       16386 :             attr_list->append_child(private_node);
     393             :         }
     394             :     }
     395             : 
     396       40965 :     if(f_node->get_type() != Node::node_t::NODE_OPEN_CURVLY_BRACKET)
     397             :     {
     398        8193 :         Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INVALID_NAMESPACE, f_lexer->get_input()->get_position());
     399        8193 :         msg << "'{' missing after the name of this namespace.";
     400             :         // TODO: write code to search for the next ';'?
     401             :     }
     402             :     else
     403             :     {
     404       32772 :         Node::pointer_t directives;
     405       32772 :         directive_list(directives);
     406       32772 :         node->append_child(directives);
     407             :     }
     408       40965 : }
     409             : 
     410             : 
     411             : 
     412          20 : }
     413             : // namespace as2js
     414             : 
     415             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.9