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

          Line data    Source code
       1             : /* parser_function.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 FUNCTION  ************************************************/
      47             : /**********************************************************************/
      48             : /**********************************************************************/
      49             : 
      50      868644 : void Parser::parameter_list(Node::pointer_t& node, bool& has_out)
      51             : {
      52             :     // accept function stuff(void) { ... } as in C/C++
      53             :     // Note that we also accept Void (void is a keyword, Void is a type)
      54     1737288 :     if(f_node->get_type() == Node::node_t::NODE_VOID
      55      868644 :     || (f_node->get_type() == Node::node_t::NODE_IDENTIFIER && f_node->get_string() == "Void"))
      56             :     {
      57       24612 :         get_token();
      58       24612 :         return;
      59             :     }
      60             : 
      61      844032 :     node = f_lexer->get_new_node(Node::node_t::NODE_PARAMETERS);
      62             : 
      63             :     // special case which explicitly says that a function definition
      64             :     // is not prototyped (vs. an empty list of parameters which is
      65             :     // equivalent to a (void)); this means the function accepts
      66             :     // parameters, their type & number are just not defined
      67     1688064 :     if(f_node->get_type() == Node::node_t::NODE_IDENTIFIER
      68      844032 :     && f_node->get_string() == "unprototyped")
      69             :     {
      70        8192 :         Node::pointer_t param(f_lexer->get_new_node(Node::node_t::NODE_PARAM));
      71        8192 :         param->set_flag(Node::flag_t::NODE_PARAM_FLAG_UNPROTOTYPED, true);
      72        8192 :         node->append_child(param);
      73        8192 :         get_token();
      74        8192 :         return;
      75             :     }
      76             : 
      77      835840 :     bool invalid(false);
      78             :     for(;;)
      79             :     {
      80     1048921 :         Node::pointer_t param(f_lexer->get_new_node(Node::node_t::NODE_PARAM));
      81             : 
      82             :         // get all the attributes for the parameters
      83             :         // (var, const, in, out, named, unchecked, ...)
      84     1048921 :         bool more(true);
      85     1048921 :         bool param_has_out(false);
      86     1655827 :         do
      87             :         {
      88             :             // TODO: it seems that any one flag should only be accepted
      89             :             //       once, 'var' first, and '...' last.
      90     1655827 :             switch(f_node->get_type())
      91             :             {
      92             :             case Node::node_t::NODE_REST:
      93       40972 :                 param->set_flag(Node::flag_t::NODE_PARAM_FLAG_REST, true);
      94       40972 :                 invalid = false;
      95       40972 :                 get_token();
      96       40972 :                 break;
      97             : 
      98             :             case Node::node_t::NODE_CONST:
      99      139264 :                 param->set_flag(Node::flag_t::NODE_PARAM_FLAG_CONST, true);
     100      139264 :                 invalid = false;
     101      139264 :                 get_token();
     102      139264 :                 break;
     103             : 
     104             :             case Node::node_t::NODE_IN:
     105      147799 :                 param->set_flag(Node::flag_t::NODE_PARAM_FLAG_IN, true);
     106      147799 :                 invalid = false;
     107      147799 :                 get_token();
     108      147799 :                 break;
     109             : 
     110             :             case Node::node_t::NODE_VAR:
     111             :                 // TBD: should this be forced first?
     112      188759 :                 invalid = false;
     113      188759 :                 get_token();
     114      188759 :                 break;
     115             : 
     116             :             case Node::node_t::NODE_IDENTIFIER:
     117     1098073 :                 if(f_node->get_string() == "out")
     118             :                 {
     119       65536 :                     param->set_flag(Node::flag_t::NODE_PARAM_FLAG_OUT, true);
     120       65536 :                     invalid = false;
     121       65536 :                     get_token();
     122       65536 :                     has_out = true; // for caller to know
     123       65536 :                     param_has_out = true;
     124       65536 :                     break;
     125             :                 }
     126     1032537 :                 if(f_node->get_string() == "named")
     127             :                 {
     128       16384 :                     param->set_flag(Node::flag_t::NODE_PARAM_FLAG_NAMED, true);
     129       16384 :                     invalid = false;
     130       16384 :                     get_token();
     131       16384 :                     break;
     132             :                 }
     133     1016153 :                 if(f_node->get_string() == "unchecked")
     134             :                 {
     135        8192 :                     param->set_flag(Node::flag_t::NODE_PARAM_FLAG_UNCHECKED, true);
     136        8192 :                     invalid = false;
     137        8192 :                     get_token();
     138        8192 :                     break;
     139             :                 }
     140             :                 /*FALLTHROUGH*/
     141             :             default:
     142     1048921 :                 more = false;
     143     1048921 :                 break;
     144             : 
     145             :             }
     146             :         }
     147             :         while(more); 
     148             : 
     149     1048921 :         if(param_has_out)
     150             :         {
     151       65536 :             if(param->get_flag(Node::flag_t::NODE_PARAM_FLAG_REST))
     152             :             {
     153        8192 :                 Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INVALID_PARAMETERS, f_lexer->get_input()->get_position());
     154        8192 :                 msg << "you cannot use the function parameter attribute 'out' with '...'.";
     155             :             }
     156       65536 :             if(param->get_flag(Node::flag_t::NODE_PARAM_FLAG_CONST))
     157             :             {
     158        8192 :                 Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INVALID_PARAMETERS, f_lexer->get_input()->get_position());
     159        8192 :                 msg << "you cannot use the function attributes 'out' and 'const' together.";
     160             :             }
     161             :         }
     162             : 
     163     1048921 :         if(f_node->get_type() == Node::node_t::NODE_IDENTIFIER)
     164             :         {
     165     1007961 :             param->set_string(f_node->get_string());
     166     1007961 :             node->append_child(param);
     167     1007961 :             invalid = false;
     168     1007961 :             get_token();
     169     1007961 :             if(f_node->get_type() == Node::node_t::NODE_COLON)
     170             :             {
     171             :                 // TBD: what about REST? does this mean all
     172             :                 //      the following parameters need to be
     173             :                 //      of that type?
     174      393558 :                 get_token();
     175      393558 :                 Node::pointer_t expr;
     176      393558 :                 conditional_expression(expr, false);
     177      787116 :                 Node::pointer_t type(f_lexer->get_new_node(Node::node_t::NODE_TYPE));
     178      393558 :                 type->append_child(expr);
     179      787116 :                 param->append_child(type);
     180             :             }
     181     1007961 :             if(f_node->get_type() == Node::node_t::NODE_ASSIGNMENT)
     182             :             {
     183             :                 // cannot accept when REST is set
     184       41017 :                 if(param->get_flag(Node::flag_t::NODE_PARAM_FLAG_REST))
     185             :                 {
     186        8192 :                     Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INVALID_PARAMETERS, f_lexer->get_input()->get_position());
     187        8192 :                     msg << "you cannot assign a default value to '...'.";
     188             :                     // we still parse the initializer so we get to the right
     189             :                     // place; but since we had an error anyway, the compiler
     190             :                     // won't kick in so we are fine
     191             :                 }
     192             : 
     193             :                 // initializer
     194       41017 :                 get_token();
     195       41017 :                 Node::pointer_t initializer(f_lexer->get_new_node(Node::node_t::NODE_SET));
     196       82034 :                 Node::pointer_t expr;
     197       41017 :                 conditional_expression(expr, false);
     198       41017 :                 initializer->append_child(expr);
     199       82034 :                 param->append_child(initializer);
     200             :             }
     201             :         }
     202       40960 :         else if(param->get_flag(Node::flag_t::NODE_PARAM_FLAG_REST))
     203             :         {
     204       24576 :             node->append_child(param);
     205             :         }
     206             : 
     207             :         // reached the end of the list?
     208     2097842 :         if(f_node->get_type() == Node::node_t::NODE_CLOSE_PARENTHESIS
     209     1048921 :         || f_node->get_type() == Node::node_t::NODE_IF) // special case for catch(e if e instanceof RangeError) ...
     210             :         {
     211      819456 :             return;
     212             :         }
     213             : 
     214      229465 :         if(f_node->get_type() != Node::node_t::NODE_COMMA)
     215             :         {
     216       49152 :             if(!invalid)
     217             :             {
     218       32768 :                 Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INVALID_PARAMETERS, f_lexer->get_input()->get_position());
     219       32768 :                 msg << "expected ')' or ',' after a parameter declaration (not token " << f_node->get_type_name() << ").";
     220             :             }
     221       49152 :             switch(f_node->get_type())
     222             :             {
     223             :             case Node::node_t::NODE_EOF:
     224             :             case Node::node_t::NODE_SEMICOLON:
     225             :             case Node::node_t::NODE_OPEN_CURVLY_BRACKET:
     226             :             case Node::node_t::NODE_CLOSE_CURVLY_BRACKET:
     227             :                 // we are probably past the end of the list
     228       16384 :                 return;
     229             : 
     230             :             default:
     231             :                 // continue, just ignore that token
     232       32768 :                 break;
     233             : 
     234             :             }
     235       32768 :             if(invalid)
     236             :             {
     237       16384 :                 get_token();
     238             :             }
     239       32768 :             invalid = true;
     240             :         }
     241             :         else
     242             :         {
     243      180313 :             if(param->get_flag(Node::flag_t::NODE_PARAM_FLAG_REST))
     244             :             {
     245        8192 :                 Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INVALID_PARAMETERS, f_lexer->get_input()->get_position());
     246        8192 :                 msg << "no other parameters expected after '...'.";
     247             :             }
     248      180313 :             get_token();
     249             :         }
     250      213081 :     }
     251             : }
     252             : 
     253             : 
     254             : 
     255      950596 : void Parser::function(Node::pointer_t& node, bool const expression_function)
     256             : {
     257      950596 :     node = f_lexer->get_new_node(Node::node_t::NODE_FUNCTION);
     258             : 
     259      950596 :     switch(f_node->get_type())
     260             :     {
     261             :     case Node::node_t::NODE_IDENTIFIER:
     262             :     {
     263      409773 :         String etter;
     264      409773 :         if(f_node->get_string() == "get")
     265             :         {
     266             :             // *** GETTER ***
     267       57344 :             node->set_flag(Node::flag_t::NODE_FUNCTION_FLAG_GETTER, true);
     268       57344 :             etter = "->";
     269             :         }
     270      352429 :         else if(f_node->get_string() == "set")
     271             :         {
     272             :             // *** SETTER ***
     273       40960 :             node->set_flag(Node::flag_t::NODE_FUNCTION_FLAG_SETTER, true);
     274       40960 :             etter = "<-";
     275             :         }
     276      409773 :         if(!etter.empty())
     277             :         {
     278             :             // *** one of GETTER/SETTER ***
     279       98304 :             get_token();
     280       98304 :             if(f_node->get_type() == Node::node_t::NODE_IDENTIFIER)
     281             :             {
     282       40960 :                 node->set_string(String(etter + f_node->get_string()));
     283       40960 :                 get_token();
     284             :             }
     285       57344 :             else if(f_node->get_type() == Node::node_t::NODE_STRING)
     286             :             {
     287             :                 // this is an extension, you can't have
     288             :                 // a getter or setter which is also an
     289             :                 // operator overload though...
     290       32768 :                 node->set_string(etter + f_node->get_string());
     291       32768 :                 if(Node::string_to_operator(f_node->get_string()) != Node::node_t::NODE_UNKNOWN)
     292             :                 {
     293       16384 :                     Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INVALID_FUNCTION, f_lexer->get_input()->get_position());
     294       16384 :                     msg << "operator override cannot be marked as a getter nor a setter function.";
     295             :                 }
     296       32768 :                 get_token();
     297             :             }
     298       24576 :             else if(f_node->get_type() == Node::node_t::NODE_OPEN_PARENTHESIS)
     299             :             {
     300             :                 // not a getter or setter when only get() or set()
     301       16384 :                 if(node->get_flag(Node::flag_t::NODE_FUNCTION_FLAG_GETTER))
     302             :                 {
     303        8192 :                     node->set_string("get");
     304             :                 }
     305             :                 else
     306             :                 {
     307        8192 :                     node->set_string("set");
     308             :                 }
     309       16384 :                 node->set_flag(Node::flag_t::NODE_FUNCTION_FLAG_GETTER, false);
     310       16384 :                 node->set_flag(Node::flag_t::NODE_FUNCTION_FLAG_SETTER, false);
     311       16384 :                 etter = "";
     312             :             }
     313        8192 :             else if(!expression_function)
     314             :             {
     315        8192 :                 Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INVALID_FUNCTION, f_lexer->get_input()->get_position());
     316        8192 :                 msg << "getter and setter functions require a name.";
     317             :             }
     318       98304 :             if(expression_function && !etter.empty())
     319             :             {
     320       16384 :                 Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INVALID_FUNCTION, f_lexer->get_input()->get_position());
     321       16384 :                 msg << "expression functions cannot be getter nor setter functions.";
     322             :             }
     323             :         }
     324             :         else
     325             :         {
     326             :             // *** STANDARD ***
     327      311469 :             node->set_string(f_node->get_string());
     328      311469 :             get_token();
     329      311469 :             if(f_node->get_type() == Node::node_t::NODE_IDENTIFIER)
     330             :             {
     331             :                 // Ooops? this could be that the user misspelled get or set
     332        8192 :                 Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INVALID_FUNCTION, f_lexer->get_input()->get_position());
     333        8192 :                 msg << "only one name is expected for a function (misspelled get or set? missing '(' before a parameter?)";
     334        8192 :                 get_token(); // <- TBD: is that really a good idea?
     335             :             }
     336      409773 :         }
     337             :     }
     338      409773 :         break;
     339             : 
     340             :     case Node::node_t::NODE_STRING:
     341             :     {
     342             :         // *** OPERATOR OVERLOAD ***
     343             :         // (though we just accept any string at this time)
     344        8192 :         node->set_string(f_node->get_string());
     345        8192 :         if(Node::string_to_operator(node->get_string()) != Node::node_t::NODE_UNKNOWN)
     346             :         {
     347        8192 :             node->set_flag(Node::flag_t::NODE_FUNCTION_FLAG_OPERATOR, true);
     348             :         }
     349        8192 :         get_token();
     350             :     }
     351        8192 :         break;
     352             : 
     353             :     // all the operators which can be overloaded as is
     354             :     case Node::node_t::NODE_ASSIGNMENT_MAXIMUM:
     355             :     case Node::node_t::NODE_ASSIGNMENT_MINIMUM:
     356             :     case Node::node_t::NODE_ASSIGNMENT_POWER:
     357             :     case Node::node_t::NODE_ASSIGNMENT_ROTATE_LEFT:
     358             :     case Node::node_t::NODE_ASSIGNMENT_ROTATE_RIGHT:
     359             :     case Node::node_t::NODE_COMPARE:
     360             :     case Node::node_t::NODE_LOGICAL_XOR:
     361             :     case Node::node_t::NODE_MATCH:
     362             :     case Node::node_t::NODE_MAXIMUM:
     363             :     case Node::node_t::NODE_MINIMUM:
     364             :     case Node::node_t::NODE_NOT_MATCH:
     365             :     case Node::node_t::NODE_POWER:
     366             :     case Node::node_t::NODE_ROTATE_LEFT:
     367             :     case Node::node_t::NODE_ROTATE_RIGHT:
     368             :     case Node::node_t::NODE_SMART_MATCH:
     369      122917 :         if(!has_option_set(Options::option_t::OPTION_EXTENDED_OPERATORS))
     370             :         {
     371       30720 :             Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_NOT_ALLOWED, f_lexer->get_input()->get_position());
     372       30720 :             msg << "the '" << f_node->get_type_name() << "' operator is only available when extended operators are authorized (use extended_operators;).";
     373             :         }
     374             :     case Node::node_t::NODE_ADD:
     375             :     case Node::node_t::NODE_ASSIGNMENT:
     376             :     case Node::node_t::NODE_ASSIGNMENT_ADD:
     377             :     case Node::node_t::NODE_ASSIGNMENT_BITWISE_AND:
     378             :     case Node::node_t::NODE_ASSIGNMENT_BITWISE_OR:
     379             :     case Node::node_t::NODE_ASSIGNMENT_BITWISE_XOR:
     380             :     case Node::node_t::NODE_ASSIGNMENT_DIVIDE:
     381             :     case Node::node_t::NODE_ASSIGNMENT_LOGICAL_AND:
     382             :     case Node::node_t::NODE_ASSIGNMENT_LOGICAL_OR:
     383             :     case Node::node_t::NODE_ASSIGNMENT_LOGICAL_XOR:
     384             :     case Node::node_t::NODE_ASSIGNMENT_MODULO:
     385             :     case Node::node_t::NODE_ASSIGNMENT_MULTIPLY:
     386             :     case Node::node_t::NODE_ASSIGNMENT_SHIFT_LEFT:
     387             :     case Node::node_t::NODE_ASSIGNMENT_SHIFT_RIGHT:
     388             :     case Node::node_t::NODE_ASSIGNMENT_SHIFT_RIGHT_UNSIGNED:
     389             :     case Node::node_t::NODE_ASSIGNMENT_SUBTRACT:
     390             :     case Node::node_t::NODE_BITWISE_AND:
     391             :     case Node::node_t::NODE_BITWISE_XOR:
     392             :     case Node::node_t::NODE_BITWISE_OR:
     393             :     case Node::node_t::NODE_BITWISE_NOT:
     394             :     case Node::node_t::NODE_DECREMENT:
     395             :     case Node::node_t::NODE_DIVIDE:
     396             :     case Node::node_t::NODE_EQUAL:
     397             :     case Node::node_t::NODE_GREATER:
     398             :     case Node::node_t::NODE_GREATER_EQUAL:
     399             :     case Node::node_t::NODE_INCREMENT:
     400             :     case Node::node_t::NODE_LESS:
     401             :     case Node::node_t::NODE_LESS_EQUAL:
     402             :     case Node::node_t::NODE_LOGICAL_AND:
     403             :     case Node::node_t::NODE_LOGICAL_NOT:
     404             :     case Node::node_t::NODE_LOGICAL_OR:
     405             :     case Node::node_t::NODE_MODULO:
     406             :     case Node::node_t::NODE_MULTIPLY:
     407             :     case Node::node_t::NODE_NOT_EQUAL:
     408             :     case Node::node_t::NODE_POST_DECREMENT:
     409             :     case Node::node_t::NODE_POST_INCREMENT:
     410             :     case Node::node_t::NODE_SHIFT_LEFT:
     411             :     case Node::node_t::NODE_SHIFT_RIGHT:
     412             :     case Node::node_t::NODE_SHIFT_RIGHT_UNSIGNED:
     413             :     case Node::node_t::NODE_STRICTLY_EQUAL:
     414             :     case Node::node_t::NODE_STRICTLY_NOT_EQUAL:
     415             :     case Node::node_t::NODE_SUBTRACT:
     416             :     {
     417             :         // save the operator type in the node to be able
     418             :         // to get the string
     419      491660 :         node->set_string(Node::operator_to_string(f_node->get_type()));
     420      491660 :         node->set_flag(Node::flag_t::NODE_FUNCTION_FLAG_OPERATOR, true);
     421      491660 :         get_token();
     422             :     }
     423      491660 :         break;
     424             : 
     425             :     // this is a complicated one because () can
     426             :     // be used as the "()" operator or for the parameters
     427             :     case Node::node_t::NODE_OPEN_PARENTHESIS:
     428             :     {
     429       40971 :         Node::pointer_t restore(f_node);
     430       40971 :         get_token();
     431       40971 :         if(f_node->get_type() == Node::node_t::NODE_CLOSE_PARENTHESIS)
     432             :         {
     433       32768 :             Node::pointer_t save(f_node);
     434       32768 :             get_token();
     435       32768 :             if(f_node->get_type() == Node::node_t::NODE_OPEN_PARENTHESIS)
     436             :             {
     437             :                 // at this point...
     438             :                 // this is taken as the "()" operator!
     439       16384 :                 node->set_string("()");
     440       16384 :                 node->set_flag(Node::flag_t::NODE_FUNCTION_FLAG_OPERATOR, true);
     441       16384 :                 break;
     442             :             }
     443             :             else
     444             :             {
     445       16384 :                 unget_token(f_node);
     446       16384 :                 unget_token(save);
     447       16384 :                 f_node = restore;
     448       16384 :             }
     449             :         }
     450             :         else
     451             :         {
     452        8203 :             unget_token(f_node);
     453        8203 :             f_node = restore;
     454       24587 :         }
     455             :     }
     456             :         /*FALLTHROUGH*/
     457             :     default:
     458       24587 :         if(!expression_function)
     459             :         {
     460        8192 :             Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INVALID_FUNCTION, f_lexer->get_input()->get_position());
     461        8192 :             msg << "function declarations are required to be named.";
     462             :         }
     463       24587 :         break;
     464             : 
     465             :     }
     466             : 
     467      950596 :     if(f_node->get_type() == Node::node_t::NODE_OPEN_PARENTHESIS)
     468             :     {
     469      942404 :         get_token();
     470      942404 :         if(f_node->get_type() != Node::node_t::NODE_CLOSE_PARENTHESIS)
     471             :         {
     472             :             // read params
     473      794916 :             Node::pointer_t params;
     474      794916 :             bool has_out(false);
     475      794916 :             parameter_list(params, has_out);
     476      794916 :             if(has_out)
     477             :             {
     478       57344 :                 node->set_flag(Node::flag_t::NODE_FUNCTION_FLAG_OUT, true);
     479             :             }
     480      794916 :             if(params)
     481             :             {
     482      778496 :                 node->append_child(params);
     483             :             }
     484             :             else
     485             :             {
     486       16420 :                 node->set_flag(Node::flag_t::NODE_FUNCTION_FLAG_NOPARAMS, true);
     487             :             }
     488      794916 :             if(f_node->get_type() != Node::node_t::NODE_CLOSE_PARENTHESIS)
     489             :             {
     490        8192 :                 Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_PARENTHESIS_EXPECTED, f_lexer->get_input()->get_position());
     491        8192 :                 msg << "')' expected to close the list of parameters of this function.";
     492             :             }
     493             :             else
     494             :             {
     495      786724 :                 get_token();
     496      794916 :             }
     497             :         }
     498             :         else
     499             :         {
     500      147488 :             get_token();
     501             :         }
     502             :     }
     503             : 
     504             :     // return type specified?
     505      950596 :     if(f_node->get_type() == Node::node_t::NODE_COLON)
     506             :     {
     507      188740 :         get_token();
     508      377480 :         if(f_node->get_type() == Node::node_t::NODE_VOID
     509      188740 :         || (f_node->get_type() == Node::node_t::NODE_IDENTIFIER && f_node->get_string() == "Void"))
     510             :         {
     511             :             // special case of a procedure instead of a function
     512       73731 :             node->set_flag(Node::flag_t::NODE_FUNCTION_FLAG_VOID, true);
     513       73731 :             get_token();
     514             :         }
     515      115009 :         else if(f_node->get_type() == Node::node_t::NODE_IDENTIFIER && f_node->get_string() == "Never")
     516             :         {
     517             :             // function is not expected to return
     518        8192 :             node->set_flag(Node::flag_t::NODE_FUNCTION_FLAG_NEVER, true);
     519        8192 :             get_token();
     520             :         }
     521             :         else
     522             :         {
     523             :             // normal type definition
     524      106817 :             Node::pointer_t expr;
     525      106817 :             conditional_expression(expr, false);
     526      213634 :             Node::pointer_t type(f_lexer->get_new_node(Node::node_t::NODE_TYPE));
     527      106817 :             type->append_child(expr);
     528      213634 :             node->append_child(type);
     529             :         }
     530             :     }
     531             : 
     532             :     // throws exceptions?
     533      950596 :     if(f_node->get_type() == Node::node_t::NODE_THROWS)
     534             :     {
     535             :         // skip the THROWS keyword
     536       16384 :         get_token();
     537       16384 :         Node::pointer_t throws(f_lexer->get_new_node(Node::node_t::NODE_THROWS));
     538       16384 :         node->append_child(throws);
     539             : 
     540             :         // exceptions are types
     541             :         for(;;)
     542             :         {
     543       24576 :             Node::pointer_t expr;
     544       24576 :             conditional_expression(expr, false);
     545       24576 :             throws->append_child(expr);
     546       24576 :             if(f_node->get_type() != Node::node_t::NODE_COMMA)
     547             :             {
     548       16384 :                 break;
     549             :             }
     550             :             // skip the comma
     551        8192 :             get_token();
     552        8192 :         }
     553             :     }
     554             : 
     555             :     // any requirement?
     556      950596 :     if(f_node->get_type() == Node::node_t::NODE_REQUIRE)
     557             :     {
     558             :         // skip the REQUIRE keyword
     559       16384 :         get_token();
     560       16384 :         bool const has_else(f_node->get_type() == Node::node_t::NODE_ELSE);
     561       16384 :         if(has_else)
     562             :         {
     563             :             // require else ... is an "or" (i.e. parent function require
     564             :             // may be negative, then this require comes to the rescue)
     565             :             // without the else, it is not valid to redeclare a require
     566             :             //
     567             :             // skip the ELSE keyword
     568        8192 :             get_token();
     569             :         }
     570       16384 :         Node::pointer_t require;
     571       16384 :         contract_declaration(require, Node::node_t::NODE_REQUIRE);
     572       16384 :         if(has_else)
     573             :         {
     574        8192 :             require->set_attribute(Node::attribute_t::NODE_ATTR_REQUIRE_ELSE, true);
     575             :         }
     576       16384 :         node->append_child(require);
     577             :     }
     578             : 
     579             :     // any insurance?
     580      950596 :     if(f_node->get_type() == Node::node_t::NODE_ENSURE)
     581             :     {
     582             :         // skip the ENSURE keyword
     583       16384 :         get_token();
     584       16384 :         bool const has_then(f_node->get_type() == Node::node_t::NODE_THEN);
     585       16384 :         if(has_then)
     586             :         {
     587             :             // ensure then ... is an "and" (i.e. it is additional to
     588             :             // the parent function ensure to be valid)
     589             :             // without the then, it is not valid to redeclare an ensure
     590             :             // skip the THEN keyword
     591        8192 :             get_token();
     592             :         }
     593       16384 :         Node::pointer_t ensure;
     594       16384 :         contract_declaration(ensure, Node::node_t::NODE_ENSURE);
     595       16384 :         if(has_then)
     596             :         {
     597        8192 :             ensure->set_attribute(Node::attribute_t::NODE_ATTR_ENSURE_THEN, true);
     598             :         }
     599       16384 :         node->append_child(ensure);
     600             :     }
     601             : 
     602      950596 :     if(f_node->get_type() == Node::node_t::NODE_OPEN_CURVLY_BRACKET)
     603             :     {
     604      278528 :         get_token();
     605      278528 :         if(f_node->get_type() != Node::node_t::NODE_CLOSE_CURVLY_BRACKET)
     606             :         {
     607      278528 :             Node::pointer_t statements;
     608      278528 :             directive_list(statements);
     609      278528 :             node->append_child(statements);
     610             :         }
     611             :         // else ... nothing?!
     612             :         // NOTE: by not inserting anything when we have
     613             :         //       an empty definition, it looks like an abstract
     614             :         //       definition... we may want to change that at a
     615             :         //       later time.
     616      278528 :         if(f_node->get_type() != Node::node_t::NODE_CLOSE_CURVLY_BRACKET)
     617             :         {
     618        8192 :             Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_CURVLY_BRACKETS_EXPECTED, f_lexer->get_input()->get_position());
     619        8192 :             msg << "'}' expected to close the 'function' block.";
     620             :         }
     621             :         else
     622             :         {
     623      270336 :             get_token();
     624             :         }
     625             :     }
     626             :     // empty function (a.k.a abstract or function as a type)
     627             :     // such functions are permitted in interfaces!
     628      950596 : }
     629             : 
     630             : 
     631             : 
     632          63 : }
     633             : // namespace as2js
     634             : 
     635             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.10