LCOV - code coverage report
Current view: top level - lib - compiler_function.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1 629 0.2 %
Date: 2014-11-22 Functions: 2 18 11.1 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* compiler_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/compiler.h"
      37             : 
      38             : #include    "as2js/exceptions.h"
      39             : #include    "as2js/message.h"
      40             : 
      41             : 
      42             : namespace as2js
      43             : {
      44             : 
      45             : 
      46             : /**********************************************************************/
      47             : /**********************************************************************/
      48             : /***  FUNCTION  *******************************************************/
      49             : /**********************************************************************/
      50             : /**********************************************************************/
      51             : 
      52             : 
      53           0 : void Compiler::parameters(Node::pointer_t parameters_node)
      54             : {
      55           0 :     NodeLock ln(parameters_node);
      56           0 :     size_t max_children(parameters_node->get_children_size());
      57             : 
      58             :     // clear the reference flags
      59           0 :     for(size_t idx(0); idx < max_children; ++idx)
      60             :     {
      61           0 :         Node::pointer_t param(parameters_node->get_child(idx));
      62           0 :         param->set_flag(Node::flag_t::NODE_PARAM_FLAG_REFERENCED, false);
      63           0 :         param->set_flag(Node::flag_t::NODE_PARAM_FLAG_PARAMREF, false);
      64           0 :     }
      65             : 
      66             :     // verify unicity and compute the NODE_SET and parameter type
      67           0 :     for(size_t idx(0); idx < max_children; ++idx)
      68             :     {
      69           0 :         Node::pointer_t param(parameters_node->get_child(idx));
      70             : 
      71             :         // verify whether it is defined twice or more
      72           0 :         for(size_t k(0); k < idx; ++k)
      73             :         {
      74           0 :             Node::pointer_t prev(parameters_node->get_child(k));
      75           0 :             if(prev->get_string() == param->get_string())
      76             :             {
      77           0 :                 Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_DUPLICATES, parameters_node->get_position());
      78           0 :                 msg << "parameter '" << param->get_string() << "' is defined two or more times in the same list of parameters.";
      79           0 :                 break;
      80             :             }
      81           0 :         }
      82             : 
      83             : //param.Display(stderr);
      84             : 
      85           0 :         NodeLock ln_param(param);
      86           0 :         size_t const jmax(param->get_children_size());
      87           0 :         for(size_t j(0); j < jmax; ++j)
      88             :         {
      89           0 :             Node::pointer_t child(param->get_child(j));
      90           0 :             if(child->get_type() == Node::node_t::NODE_SET)
      91             :             {
      92           0 :                 expression(child->get_child(0));
      93             :             }
      94             :             else
      95             :             {
      96           0 :                 expression(child);
      97           0 :                 Node::pointer_t type(child->get_link(Node::link_t::LINK_INSTANCE));
      98           0 :                 if(type)
      99             :                 {
     100           0 :                     Node::pointer_t existing_type(param->get_link(Node::link_t::LINK_TYPE));
     101           0 :                     if(!existing_type)
     102             :                     {
     103           0 :                         param->set_link(Node::link_t::LINK_TYPE, type);
     104             :                     }
     105           0 :                     else if(existing_type != type)
     106             :                     {
     107           0 :                         Message msg(message_level_t::MESSAGE_LEVEL_FATAL, err_code_t::AS_ERR_INVALID_TYPE, param->get_position());
     108           0 :                         msg << "Existing type is:\n" << existing_type << "\nNew type would be:\n" << type;
     109           0 :                     }
     110           0 :                 }
     111             :             }
     112           0 :         }
     113           0 :     }
     114             : 
     115             :     // if some parameter was referenced by another, mark it as such
     116           0 :     for(size_t idx(0); idx < max_children; ++idx)
     117             :     {
     118           0 :         Node::pointer_t param(parameters_node->get_child(idx));
     119           0 :         if(param->get_flag(Node::flag_t::NODE_PARAM_FLAG_REFERENCED))
     120             :         {
     121             :             // if referenced, we want to keep it so mark it as necessary
     122           0 :             param->set_flag(Node::flag_t::NODE_PARAM_FLAG_PARAMREF, true);
     123             :         }
     124           0 :     }
     125           0 : }
     126             : 
     127             : 
     128           0 : void Compiler::function(Node::pointer_t function_node)
     129             : {
     130           0 :     if(get_attribute(function_node, Node::attribute_t::NODE_ATTR_UNUSED)
     131           0 :     || get_attribute(function_node, Node::attribute_t::NODE_ATTR_FALSE))
     132             :     {
     133           0 :         return;
     134             :     }
     135             : 
     136             :     // Here we search for a parent for this function.
     137             :     // The parent can be a class, an interface or a package in which
     138             :     // case the function is viewed as a member. Otherwise it is
     139             :     // just a local or global definition. Different attributes are
     140             :     // only valid on members and some attributes have specific
     141             :     // effects which need to be tested here (i.e. a function marked
     142             :     // final in a class can't be overwritten)
     143             : 
     144           0 :     Node::pointer_t parent(function_node);
     145           0 :     Node::pointer_t list;
     146           0 :     bool more(true);
     147           0 :     bool member(false);
     148           0 :     bool package(false);
     149           0 :     do
     150             :     {
     151           0 :         parent = parent->get_parent();
     152           0 :         if(!parent)
     153             :         {
     154             :             // more = false; -- not required here
     155           0 :             break;
     156             :         }
     157           0 :         switch(parent->get_type())
     158             :         {
     159             :         case Node::node_t::NODE_CLASS:
     160             :         case Node::node_t::NODE_INTERFACE:
     161           0 :             more = false;
     162           0 :             member = true;
     163           0 :             break;
     164             : 
     165             :         case Node::node_t::NODE_PACKAGE:
     166           0 :             more = false;
     167           0 :             package = true;
     168           0 :             break;
     169             : 
     170             :         case Node::node_t::NODE_CATCH:
     171             :         case Node::node_t::NODE_DO:
     172             :         case Node::node_t::NODE_ELSE:
     173             :         case Node::node_t::NODE_FINALLY:
     174             :         case Node::node_t::NODE_FOR:
     175             :         case Node::node_t::NODE_FUNCTION:
     176             :         case Node::node_t::NODE_IF:
     177             :         case Node::node_t::NODE_PROGRAM:
     178             :         case Node::node_t::NODE_ROOT:
     179             :         case Node::node_t::NODE_SWITCH:
     180             :         case Node::node_t::NODE_TRY:
     181             :         case Node::node_t::NODE_WHILE:
     182             :         case Node::node_t::NODE_WITH:
     183           0 :             more = false;
     184           0 :             break;
     185             : 
     186             :         case Node::node_t::NODE_DIRECTIVE_LIST:
     187           0 :             if(!list)
     188             :             {
     189           0 :                 list = parent;
     190             :             }
     191           0 :             break;
     192             : 
     193             :         default:
     194           0 :             break;
     195             : 
     196             :         }
     197             :     }
     198             :     while(more);
     199             : 
     200             :     // any one of the following flags implies that the function is
     201             :     // defined in a class; check to make sure!
     202           0 :     if(get_attribute(function_node, Node::attribute_t::NODE_ATTR_ABSTRACT)
     203           0 :     || get_attribute(function_node, Node::attribute_t::NODE_ATTR_STATIC)
     204           0 :     || get_attribute(function_node, Node::attribute_t::NODE_ATTR_PROTECTED)
     205           0 :     || get_attribute(function_node, Node::attribute_t::NODE_ATTR_VIRTUAL)
     206           0 :     || get_attribute(function_node, Node::attribute_t::NODE_ATTR_CONSTRUCTOR)
     207           0 :     || get_attribute(function_node, Node::attribute_t::NODE_ATTR_FINAL))
     208             :     {
     209           0 :         if(!member)
     210             :         {
     211           0 :             Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INVALID_ATTRIBUTES, function_node->get_position());
     212           0 :             msg << "function \"" << function_node->get_string() << "\" was defined with an attribute which can only be used with a function member inside a class definition.";
     213             :         }
     214             :     }
     215           0 :     if(function_node->get_flag(Node::flag_t::NODE_FUNCTION_FLAG_OPERATOR))
     216             :     {
     217           0 :         if(!member)
     218             :         {
     219           0 :             Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INVALID_OPERATOR, function_node->get_position());
     220           0 :             msg << "operator \"" << function_node->get_string() << "\" can only be defined inside a class definition.";
     221             :         }
     222             :     }
     223             : 
     224             :     // any one of the following flags implies that the function is
     225             :     // defined in a class or a package; check to make sure!
     226           0 :     if(get_attribute(function_node, Node::attribute_t::NODE_ATTR_PRIVATE))
     227             :     {
     228           0 :         if(!package && !member)
     229             :         {
     230           0 :             Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INVALID_ATTRIBUTES, function_node->get_position());
     231           0 :             msg << "function \"" << function_node->get_string() << "\" was defined with an attribute which can only be used inside a class or package definition.";
     232             :         }
     233             :     }
     234             : 
     235             :     // member functions need to not be defined in a super class
     236             :     // as final since that means you cannot overwrite these functions
     237           0 :     if(member)
     238             :     {
     239           0 :         if(check_final_functions(function_node, parent))
     240             :         {
     241           0 :             Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_CANNOT_OVERLOAD, function_node->get_position());
     242           0 :             msg << "function \"" << function_node->get_string() << "\" was marked as final in a super class and thus it cannot be defined in class \"" << parent->get_string() << "\".";
     243             :         }
     244           0 :         check_unique_functions(function_node, parent, true);
     245             :     }
     246             :     else
     247             :     {
     248           0 :         check_unique_functions(function_node, list, false);
     249             :     }
     250             : 
     251             :     // define_function_type() may be recursive so we make sure that it
     252             :     // is called before we lock function_node
     253           0 :     if(!define_function_type(function_node))
     254             :     {
     255           0 :         return;
     256             :     }
     257             : 
     258           0 :     Node::pointer_t end_list, directive_list_node;
     259           0 :     NodeLock ln(function_node);
     260           0 :     size_t const max_children(function_node->get_children_size());
     261           0 :     for(size_t idx(0); idx < max_children; ++idx)
     262             :     {
     263           0 :         Node::pointer_t child = function_node->get_child(idx);
     264           0 :         switch(child->get_type())
     265             :         {
     266             :         case Node::node_t::NODE_PARAMETERS:
     267             :             // parse the parameters which have a default value
     268           0 :             parameters(child);
     269           0 :             break;
     270             : 
     271             :         case Node::node_t::NODE_DIRECTIVE_LIST:
     272           0 :             if(get_attribute(function_node, Node::attribute_t::NODE_ATTR_ABSTRACT))
     273             :             {
     274           0 :                 Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_IMPROPER_STATEMENT, function_node->get_position());
     275           0 :                 msg << "the function \"" << function_node->get_string() << "\" is marked abstract and cannot have a body.";
     276             :             }
     277             :             // find all the labels of this function
     278           0 :             find_labels(function_node, child);
     279             :             // parse the function body
     280           0 :             end_list = directive_list(child);
     281           0 :             directive_list_node = child;
     282           0 :             break;
     283             : 
     284             :         default:
     285             :             // the expression represents the function return type
     286           0 :             expression(child);
     287             :             // constructors only support Void (or should
     288             :             // it be the same name as the class?)
     289           0 :             if(is_constructor(function_node))
     290             :             {
     291           0 :                 Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INVALID_RETURN_TYPE, function_node->get_position());
     292           0 :                 msg << "a constructor must return \"void\" and nothing else, \"" << function_node->get_string() << "\" is invalid.";
     293             :             }
     294           0 :             break;
     295             : 
     296             :         }
     297           0 :     }
     298             : 
     299           0 :     if(function_node->get_flag(Node::flag_t::NODE_FUNCTION_FLAG_NEVER) && is_constructor(function_node))
     300             :     {
     301           0 :         Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INVALID_RETURN_TYPE, function_node->get_position());
     302           0 :         msg << "a constructor must return (it cannot be marked Never).";
     303             :     }
     304             : 
     305             :     // test for a return whenever necessary
     306           0 :     if(!end_list
     307           0 :     && directive_list_node
     308           0 :     && (get_attribute(function_node, Node::attribute_t::NODE_ATTR_ABSTRACT) || get_attribute(function_node, Node::attribute_t::NODE_ATTR_NATIVE))
     309           0 :     && (function_node->get_flag(Node::flag_t::NODE_FUNCTION_FLAG_VOID) || function_node->get_flag(Node::flag_t::NODE_FUNCTION_FLAG_NEVER)))
     310             :     {
     311           0 :         Optimizer::optimize(directive_list_node);
     312           0 :         find_labels(function_node, directive_list_node);
     313             : //fprintf(stderr, "ARGH! 2nd call...\n");
     314           0 :         end_list = directive_list(directive_list_node);
     315           0 :         if(!end_list)
     316             :         {
     317             :             // TODO: we need a much better control flow to make
     318             :             // sure that this isn't a spurious error (i.e. you
     319             :             // don't need to have a return after a loop which
     320             :             // never exits)
     321             : // This could become annoying...
     322             : //fprintf(stderr, "WARNING: function not returning Void nor Never seems to terminate with a 'return' statement.\n");
     323             :             // It should be an error
     324             :             //f_error_stream->ErrMsg(, , );
     325             :         }
     326           0 :     }
     327             : }
     328             : 
     329             : 
     330           0 : bool Compiler::define_function_type(Node::pointer_t function_node)
     331             : {
     332             :     // define the type of the function when not available yet
     333           0 :     if(function_node->get_link(Node::link_t::LINK_TYPE))
     334             :     {
     335           0 :         return true;
     336             :     }
     337             : 
     338           0 :     size_t idx(0);
     339           0 :     size_t const max_children(function_node->get_children_size());
     340           0 :     if(max_children < 1)
     341             :     {
     342             :         // Should we put the default of Object if not VOID?
     343             :         // (see at the bottom of the function)
     344           0 :         return function_node->get_flag(Node::flag_t::NODE_FUNCTION_FLAG_VOID);
     345             :     }
     346             : 
     347             :     {
     348           0 :         NodeLock ln(function_node);
     349             : 
     350           0 :         for(; idx < max_children; ++idx)
     351             :         {
     352           0 :             Node::pointer_t type(function_node->get_child(idx));
     353           0 :             if(type->get_type() != Node::node_t::NODE_PARAMETERS
     354           0 :             && type->get_type() != Node::node_t::NODE_DIRECTIVE_LIST)
     355             :             {
     356             :                 // then this is the type definition
     357           0 :                 expression(type);
     358           0 :                 Node::pointer_t resolution;
     359           0 :                 if(resolve_name(type, type, resolution, Node::pointer_t(), 0))
     360             :                 {
     361             : #if 0
     362             :                     // we may want to have that in
     363             :                     // different places for when we
     364             :                     // specifically look for a type
     365             :                     if(resolution->get_type() == Node::node_t::NODE_FUNCTION)
     366             :                     {
     367             :                         Node::pointer_t parent(resolution);
     368             :                         for(;;)
     369             :                         {
     370             :                             parent = parent->get_parent();
     371             :                             if(!parent)
     372             :                             {
     373             :                                 break;
     374             :                             }
     375             :                             if(parent->get_type() == Node::node_t::NODE_CLASS)
     376             :                             {
     377             :                                 if(parent->get_string() == resolution->get_string())
     378             :                                 {
     379             :                                     // ha! we hit the constructor of a class, use the class instead!
     380             :                                     resolution = parent;
     381             :                                 }
     382             :                                 break;
     383             :                             }
     384             :                             if(parent->get_type() == Node::node_t::NODE_INTERFACE
     385             :                             || parent->get_type() == Node::node_t::NODE_PACKAGE
     386             :                             || parent->get_type() == Node::node_t::NODE_ROOT)
     387             :                             {
     388             :                                 break;
     389             :                             }
     390             :                         }
     391             :                     }
     392             : #endif
     393             : 
     394             : //fprintf(stderr, "  final function type is:\n");
     395             : //resolution.Display(stderr);
     396             : 
     397           0 :                     function_node->set_link(Node::link_t::LINK_TYPE, resolution);
     398             :                 }
     399           0 :                 break;
     400             :             }
     401           0 :         }
     402             :     }
     403             : 
     404           0 :     if(idx == max_children)
     405             :     {
     406             :         // if no type defined, put a default of Object
     407           0 :         Node::pointer_t object;
     408           0 :         resolve_internal_type(function_node, "Object", object);
     409           0 :         function_node->set_link(Node::link_t::LINK_TYPE, object);
     410             :     }
     411             : 
     412           0 :     return true;
     413             : }
     414             : 
     415             : 
     416             : /** \brief Check wether type t1 matches type t2.
     417             :  *
     418             :  * This function checks whether the type defined as t1 matches the
     419             :  * type defined as t2.
     420             :  *
     421             :  * t1 or t2 may be a null pointer, in which case it never matches.
     422             :  *
     423             :  * If t1 is not directly equal to t2, then all t1's ancestors are
     424             :  * checked too. The ancestors are found as extends or implements
     425             :  * of the t1 class.
     426             :  *
     427             :  * It is expected that t2 will be a NODE_PARAM in which case
     428             :  * we accept an empty node or a node without a type definition
     429             :  * as a 'match any' special type.
     430             :  *
     431             :  * Otherwise we make sure we transform the type expression in
     432             :  * a usable type and compare it with t1 and its ancestors.
     433             :  *
     434             :  * The function returns the depth at which the match occurs.
     435             :  * If a match occurs because t2 is some form of 'match any'
     436             :  * then LOWEST_DEPTH (INT_MAX / 2) is return as the depth.
     437             :  * This means it has the lowest possible priority.
     438             :  *
     439             :  * The function returns MATCH_HIGHEST_DEPTH (1) if t1 matches t2
     440             :  * directly. This is the highest possible priority so if no other
     441             :  * function matches with that depth, this is the one which is
     442             :  * going to be used.
     443             :  *
     444             :  * The function returns MATCH_NOT_FOUND (0) if it cannot find a
     445             :  * match between t1 and t2. That means no function was found here.
     446             :  *
     447             :  * \param[in] t1  A type to match against.
     448             :  * \param[in] t2  A type that has to match t1.
     449             :  *
     450             :  * \return The depth at which the type matched.
     451             :  */
     452           0 : Node::depth_t Compiler::match_type(Node::pointer_t t1, Node::pointer_t t2)
     453             : {
     454             :     // Some invalid input?
     455           0 :     if(!t1 || !t2)
     456             :     {
     457           0 :         return Node::MATCH_NOT_FOUND;
     458             :     }
     459             : 
     460             :     // special case for function parameters
     461           0 :     if(t2->get_type() == Node::node_t::NODE_PARAM)
     462             :     {
     463           0 :         if(t2->get_flag(Node::flag_t::NODE_PARAM_FLAG_OUT))
     464             :         {
     465             :             // t1 MUST be an identifier which references
     466             :             // a variable which we can set on exit
     467           0 :             if(t1->get_type() != Node::node_t::NODE_IDENTIFIER)
     468             :             {
     469             :                 // NOTE: we can't generate an error here
     470             :                 //     because there could be another
     471             :                 //     valid function somewhere else...
     472           0 :                 Message msg(message_level_t::MESSAGE_LEVEL_WARNING, err_code_t::AS_ERR_MISSSING_VARIABLE_NAME, t1->get_position());
     473           0 :                 msg << "a variable name is expected for a function parameter flagged as an OUT parameter.";
     474           0 :                 return Node::MATCH_NOT_FOUND;
     475             :             }
     476             :         }
     477           0 :         if(t2->get_children_size() == 0)
     478             :         {
     479           0 :             return Node::MATCH_LOWEST_DEPTH;
     480             :         }
     481           0 :         Node::pointer_t id(t2->get_child(0));
     482             :         // make sure we have a type definition, if it is
     483             :         // only a default set, then it is equal anyway
     484           0 :         if(id->get_type() == Node::node_t::NODE_SET)
     485             :         {
     486           0 :             return Node::MATCH_LOWEST_DEPTH;
     487             :         }
     488           0 :         Node::pointer_t resolution(id->get_link(Node::link_t::LINK_TYPE));
     489           0 :         if(!resolution)
     490             :         {
     491           0 :             if(!resolve_name(t2, id, resolution, Node::pointer_t(), 0))
     492             :             {
     493           0 :                 return Node::MATCH_NOT_FOUND;
     494             :             }
     495             : //fprintf(stderr, "   ---> ");
     496             : //resolution.DisplayPtr(stderr);
     497             : //fprintf(stderr, "\n");
     498           0 :             id->set_link(Node::link_t::LINK_TYPE, resolution);
     499             :         }
     500           0 :         t2 = id;
     501             :     }
     502             : 
     503           0 :     Node::pointer_t tp1(t1->get_link(Node::link_t::LINK_TYPE));
     504           0 :     Node::pointer_t tp2(t2->get_link(Node::link_t::LINK_TYPE));
     505             : 
     506           0 :     if(!tp1)
     507             :     {
     508           0 :         type_expr(t1);
     509           0 :         tp1 = t1->get_link(Node::link_t::LINK_TYPE);
     510           0 :         if(!tp1)
     511             :         {
     512             : //fprintf(stderr, "WARNING: cannot determine the type of the input parameter.\n");
     513           0 :             return Node::MATCH_HIGHEST_DEPTH;
     514             :         }
     515             :     }
     516             : 
     517             : // The exact same type?
     518           0 :     if(tp1 == tp2)
     519             :     {
     520           0 :         return Node::MATCH_HIGHEST_DEPTH;
     521             :     }
     522             :     // TODO: if we keep the class <id>; definition, then we need
     523             :     //       to also check for a full definition
     524             : 
     525             : // if one of the types is Object, then that's a match
     526           0 :     Node::pointer_t object;
     527           0 :     resolve_internal_type(t1, "Object", object);
     528           0 :     if(tp1 == object)
     529             :     {
     530             :         // whatever tp2, we match (bad user practice of
     531             :         // untyped variables...)
     532           0 :         return Node::MATCH_HIGHEST_DEPTH;
     533             :     }
     534           0 :     if(tp2 == object)
     535             :     {
     536             :         // this is a "bad" match -- anything else will be better
     537           0 :         return Node::MATCH_LOWEST_DEPTH;
     538             :     }
     539             :     // TODO: if we find a [class Object;] definition
     540             :     //       instead of a complete definition
     541             : 
     542             :     // Okay, still not equal, check ancestors of tp1 if
     543             :     // permitted (and if tp1 is a class).
     544           0 :     if(tp1->get_type() != Node::node_t::NODE_CLASS)
     545             :     {
     546           0 :         return Node::MATCH_NOT_FOUND;
     547             :     }
     548             : 
     549           0 :     return find_class(tp1, tp2, 2);
     550             : }
     551             : 
     552             : 
     553           0 : bool Compiler::check_function(Node::pointer_t function_node, Node::pointer_t& resolution, String const& name, Node::pointer_t params, int const search_flags)
     554             : {
     555             :     // The fact that a function is marked UNUSED should
     556             :     // be an error, but overloading prevents us from
     557             :     // generating an error here...
     558           0 :     if(get_attribute(function_node, Node::attribute_t::NODE_ATTR_UNUSED))
     559             :     {
     560           0 :         return false;
     561             :     }
     562             : 
     563           0 :     if(function_node->get_flag(Node::flag_t::NODE_FUNCTION_FLAG_GETTER)
     564           0 :     && (search_flags & SEARCH_FLAG_GETTER) != 0)
     565             :     {
     566           0 :         String getter("->");
     567           0 :         getter += name;
     568           0 :         if(function_node->get_string() != getter)
     569             :         {
     570           0 :             return false;
     571           0 :         }
     572             :     }
     573           0 :     else if(function_node->get_flag(Node::flag_t::NODE_FUNCTION_FLAG_SETTER)
     574           0 :          && (search_flags & SEARCH_FLAG_SETTER) != 0)
     575             :     {
     576           0 :         String setter("<-");
     577           0 :         setter += name;
     578           0 :         if(function_node->get_string() != setter)
     579             :         {
     580           0 :             return false;
     581           0 :         }
     582             :     }
     583           0 :     else if(function_node->get_string() != name)
     584             :     {
     585           0 :         return false;
     586             :     }
     587             : 
     588             :     // That's a function!
     589             :     // Find the perfect match (testing prototypes)
     590             : 
     591             : #if 0
     592             : fprintf(stderr, "***\n*** FUNCTION %p [%.*S] at line %d in %.*S\n***\n",
     593             :         params, name.GetLength(), name.Get(), func.GetLine(),
     594             :         func.GetFilename().GetLength(), func.GetFilename().Get());
     595             : func.Display(stderr);
     596             : #endif
     597             : 
     598           0 :     if(!params)
     599             :     {
     600             :         // getters and setters do not have parameters
     601           0 :         if(function_node->get_flag(Node::flag_t::NODE_FUNCTION_FLAG_GETTER)
     602           0 :         || function_node->get_flag(Node::flag_t::NODE_FUNCTION_FLAG_SETTER))
     603             :         {
     604             :             // warning: we have to check whether we hit a constructor
     605             :             //          before to generate an error
     606           0 :             if(!is_constructor(function_node))
     607             :             {
     608           0 :                 Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_MISMATCH_FUNC_VAR, function_node->get_position());
     609           0 :                 msg << "a variable name was expected, we found the function '" << function_node->get_string() << "' instead.";
     610             :             }
     611           0 :             return false;
     612             :         }
     613           0 :         define_function_type(function_node);
     614             :     }
     615             : 
     616           0 :     resolution = function_node;
     617             : 
     618           0 :     return true;
     619             : }
     620             : 
     621             : 
     622             : // check whether the list of input parameters matches the function
     623             : // prototype; note that if the function is marked as "no prototype"
     624             : // then it matches automatically, but it gets a really low score.
     625           0 : int Compiler::check_function_with_params(Node::pointer_t function_node, Node::pointer_t params)
     626             : {
     627             :     // At this time, I am not too sure what I can do if params is
     628             :     // null. Maybe that is when you try to do var a = <funcname>;?
     629           0 :     if(!params)
     630             :     {
     631           0 :         return 0;
     632             :     }
     633             : 
     634           0 :     Node::pointer_t match(function_node->create_replacement(Node::node_t::NODE_PARAM_MATCH));
     635           0 :     match->set_link(Node::link_t::LINK_INSTANCE, function_node);
     636             : 
     637             :     // define the type of the function when not available yet
     638           0 :     if(!define_function_type(function_node))
     639             :     {
     640             :         // error: this function definition is no good
     641             :         //        (don't report that, we should have had an error in
     642             :         //        the parser already)
     643           0 :         return -1;
     644             :     }
     645             : 
     646           0 :     size_t const count(params->get_children_size());
     647           0 :     size_t const max_children(function_node->get_children_size());
     648             : //fprintf(stderr, "Check %d params versus %d inputs.\n", count, max_children);
     649             : //params->Display(stderr);
     650           0 :     if(max_children == 0)
     651             :     {
     652             :         // no parameters; check whether the user specifically
     653             :         // used void or Void as the list of parameters
     654           0 :         if(!function_node->get_flag(Node::flag_t::NODE_FUNCTION_FLAG_NOPARAMS))
     655             :         {
     656             :             // TODO:
     657             :             // this function accepts whatever
     658             :             // however, the function wasn't marked as such and
     659             :             // therefore we could warn about this...
     660           0 :             match->set_flag(Node::flag_t::NODE_PARAM_MATCH_FLAG_UNPROTOTYPED, true);
     661           0 :             params->append_child(match);
     662           0 :             return 0;
     663             :         }
     664           0 :         if(count == 0)
     665             :         {
     666           0 :             params->append_child(match);
     667           0 :             return 0;
     668             :         }
     669             :         // caller has one or more parameters, but function
     670             :         // only accepts 0 (i.e. Void)
     671           0 :         return 0;
     672             :     }
     673             : 
     674           0 :     NodeLock ln_function(function_node);
     675           0 :     Node::pointer_t parameters_node(function_node->get_child(0));
     676           0 :     if(parameters_node->get_type() != Node::node_t::NODE_PARAMETERS)
     677             :     {
     678           0 :         match->set_flag(Node::flag_t::NODE_PARAM_MATCH_FLAG_UNPROTOTYPED, true);
     679           0 :         params->append_child(match);
     680           0 :         return 0;
     681             :     }
     682             : 
     683             :     // params doesn't get locked, we expect to add to that list
     684           0 :     NodeLock ln_parameters(parameters_node);
     685           0 :     size_t const max_parameters(parameters_node->get_children_size());
     686           0 :     if(max_parameters == 0)
     687             :     {
     688             :         // this function accepts 0 parameters
     689           0 :         if(count > 0)
     690             :         {
     691             :             // error: cannot accept any parameter
     692           0 :             return -1;
     693             :         }
     694           0 :         params->append_child(match);
     695           0 :         return 0;
     696             :     }
     697             : 
     698             :     // check whether the user marked the function as unprototyped;
     699             :     // if so, then we are done
     700           0 :     Node::pointer_t unproto(parameters_node->get_child(0));
     701           0 :     if(unproto->get_flag(Node::flag_t::NODE_PARAM_FLAG_UNPROTOTYPED))
     702             :     {
     703             :         // this function is marked to accept whatever
     704           0 :         match->set_flag(Node::flag_t::NODE_PARAM_MATCH_FLAG_UNPROTOTYPED, true);
     705           0 :         params->append_child(match);
     706           0 :         return 0;
     707             :     }
     708             : 
     709             :     // we can't choose which list to use because the user
     710             :     // parameters can be named and thus we want to search
     711             :     // the caller parameters in the function parameter list
     712             :     // and not the opposite
     713             : 
     714             : #if 0
     715             : fprintf(stderr, "NOTE: looking for ~%d params in %d inputs in function proto (Node:", count, max_parameters);
     716             : function_node.DisplayPtr(stderr);
     717             : fprintf(stderr, ")\n");
     718             : #endif
     719             : 
     720           0 :     size_t size(max_parameters > count ? max_parameters : count);
     721             : 
     722           0 :     match->set_param_size(size);
     723             : 
     724           0 :     size_t min(0);
     725           0 :     size_t rest(max_parameters);
     726             :     size_t idx;
     727             :     size_t j;
     728           0 :     for(idx = 0; idx < count; ++idx)
     729             :     {
     730           0 :         Node::pointer_t p(params->get_child(idx));
     731           0 :         if(p->get_type() == Node::node_t::NODE_PARAM_MATCH)
     732             :         {
     733             :             // skip NODE_PARAM_MATCH etnries
     734             : //fprintf(stderr, "Skipping entry %d since it is a PARAM MATCH\n", idx);
     735           0 :             continue;
     736             :         }
     737             : 
     738           0 :         size_t cm(p->get_children_size());
     739           0 :         String name;
     740           0 :         for(size_t c(0); c < cm; ++c)
     741             :         {
     742           0 :             Node::pointer_t child(p->get_child(c));
     743           0 :             if(child->get_type() == Node::node_t::NODE_NAME)
     744             :             {
     745             :                 // the parameter name is specified
     746           0 :                 if(child->get_children_size() != 1)
     747             :                 {
     748             :                     // an error in the parser?
     749           0 :                     Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INTERNAL_ERROR, function_node->get_position());
     750           0 :                     msg << "found a NODE_NAME without children.";
     751           0 :                     return -1;
     752             :                 }
     753           0 :                 Node::pointer_t name_node(child->get_child(0));
     754           0 :                 if(name_node->get_type() != Node::node_t::NODE_IDENTIFIER)
     755             :                 {
     756           0 :                     Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INTERNAL_ERROR, function_node->get_position());
     757           0 :                     msg << "the name of a parameter needs to be an identifier.";
     758           0 :                     return -1;
     759             :                 }
     760           0 :                 name = name_node->get_string();
     761           0 :                 break;
     762             :             }
     763           0 :         }
     764             :         // search for the parameter (fp == found parameter)
     765             :         // NOTE: because the children aren't deleted, keep a
     766             :         //     bare pointer is fine here.
     767           0 :         Node::pointer_t fp;
     768           0 :         if(!name.empty())
     769             :         {
     770             :             // search for a parameter with that name
     771           0 :             for(j = 0; j < max_parameters; ++j)
     772             :             {
     773           0 :                 Node::pointer_t pm(parameters_node->get_child(j));
     774           0 :                 if(pm->get_string() == name)
     775             :                 {
     776           0 :                     fp = pm;
     777           0 :                     break;
     778             :                 }
     779           0 :             }
     780           0 :             if(!fp)
     781             :             {
     782             :                 // cannot find a parameter with that name...
     783           0 :                 Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INVALID_FIELD_NAME, function_node->get_position());
     784           0 :                 msg << "no parameter named '" << name << "' was found in this function declaration.";
     785           0 :                 return -1;
     786             :             }
     787             :             // if already used, make sure it is a REST node
     788           0 :             if(match->get_param_depth(j) != Node::MATCH_NOT_FOUND)
     789             :             {
     790           0 :                 if(fp->get_flag(Node::flag_t::NODE_PARAM_FLAG_REST))
     791             :                 {
     792           0 :                     Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INVALID_FIELD_NAME, function_node->get_position());
     793           0 :                     msg << "function parameter name '" << name << "' already used & not a 'rest' (...).";
     794           0 :                     return -1;
     795             :                 }
     796             :             }
     797             : #if 0
     798             :  {
     799             : std::cerr << "Found by name [" << name << "] at position " << j << "\n";
     800             :  }
     801             : #endif
     802             :         }
     803             :         else
     804             :         {
     805             :             // search for the first parameter
     806             :             // which wasn't used yet
     807           0 :             for(j = min; j < max_parameters; ++j)
     808             :             {
     809           0 :                 if(match->get_param_depth(j) == Node::MATCH_NOT_FOUND)
     810             :                 {
     811           0 :                     fp = parameters_node->get_child(j);
     812           0 :                     break;
     813             :                 }
     814             :             }
     815           0 :             min = j;
     816           0 :             if(j == max_parameters)
     817             :             {
     818             :                 // all parameters are already taken
     819             :                 // check whether the last parameter
     820             :                 // is of type REST
     821           0 :                 fp = parameters_node->get_child(max_parameters - 1);
     822           0 :                 if(fp->get_flag(Node::flag_t::NODE_PARAM_FLAG_REST))
     823             :                 {
     824             :                     // parameters in the function list
     825             :                     // of params are all used up!
     826             :                     //
     827             :                     // TODO: we cannot err here yet; we need to do it only if none of the
     828             :                     //       entries are valid!
     829             :                     //fprintf(stderr, "WARNING: all the function parameters are already assigned and the last one isn't a rest (...)\n");
     830           0 :                     return -1;
     831             :                 }
     832             :                 // ha! we accept this one!
     833           0 :                 j = rest;
     834           0 :                 ++rest;
     835             :             }
     836             : #if 0
     837             : fprintf(stderr, "Found space at default position %d\n", j);
     838             : #endif
     839             :         }
     840             :         // We reach here only if we find a parameter
     841             :         // now we need to check the type to make sure
     842             :         // it really is valid
     843           0 :         Node::depth_t const depth(match_type(p, fp));
     844           0 :         if(depth == Node::MATCH_NOT_FOUND)
     845             :         {
     846             :             // type does not match
     847             : #if 0
     848             : function_node.Display(stderr);
     849             : if(params)
     850             : params->Display(stderr);
     851             : #endif
     852             : //fprintf(stderr, "++++ Invalid type?!\n");
     853           0 :             return -1;
     854             :         }
     855             : //fprintf(stderr, "++++ Got it?!?!?! (depth: 0x%08X at %d)\n", depth, j);
     856           0 :         match->set_param_depth(j, depth);
     857           0 :         match->set_param_index(idx, j);
     858           0 :     }
     859             : 
     860             :     // if some parameters are not defined, then we need to
     861             :     // either have a default value (initializer) or they
     862             :     // need to be marked as optional (unchecked)
     863             :     // a rest is viewed as an optional parameter
     864           0 :     for(j = min; j < max_parameters; ++j)
     865             :     {
     866           0 :         if(match->get_param_depth(j) == Node::MATCH_NOT_FOUND)
     867             :         {
     868             : //fprintf(stderr, "Auto-Setting %d?\n", idx + size);
     869           0 :             match->set_param_index(idx, j);
     870           0 :             idx++;
     871           0 :             Node::pointer_t param(parameters_node->get_child(j));
     872           0 :             if(param->get_flag(Node::flag_t::NODE_PARAM_FLAG_UNCHECKED)
     873           0 :             || param->get_flag(Node::flag_t::NODE_PARAM_FLAG_REST))
     874             :             {
     875           0 :                 Node::pointer_t set;
     876           0 :                 size_t cnt(param->get_children_size());
     877           0 :                 for(size_t k(0); k < cnt; ++k)
     878             :                 {
     879           0 :                     Node::pointer_t child(param->get_child(k));
     880           0 :                     if(child->get_type() == Node::node_t::NODE_SET)
     881             :                     {
     882           0 :                         set = child;
     883           0 :                         break;
     884             :                     }
     885           0 :                 }
     886           0 :                 if(!set)
     887             :                 {
     888             :                     // TODO: we cannot warn here, instead we need to register this function
     889             :                     //     as a possible candidate for that call in case no function does
     890             :                     //     match (and even so, in ECMAScript, we cannot really know until
     891             :                     //     run time...)
     892             :                     //std::cerr << "WARNING: missing parameters to call function.\n";
     893           0 :                     return -1;
     894           0 :                 }
     895           0 :             }
     896             :         }
     897             :     }
     898             : 
     899             : //fprintf(stderr, "Child added to params\n");
     900           0 :     params->append_child(match);
     901             : 
     902           0 :     return 0;
     903             : }
     904             : 
     905             : 
     906           0 : bool Compiler::best_param_match_derived_from(Node::pointer_t& best, Node::pointer_t match)
     907             : {
     908           0 :     Node::pointer_t the_super_class;
     909             : 
     910             : //fprintf(stderr, "NOTE: checking best <- match.\n");
     911           0 :     if(are_objects_derived_from_one_another(best, match, the_super_class))
     912             :     {
     913             :         // if best is in a class derived from
     914             :         // the class where we found match, then
     915             :         // this is not an error, we just keep best
     916             : //fprintf(stderr, "RESULT! checking best <- match is true.\n");
     917           0 :         return true;
     918             :     }
     919             : 
     920             : //fprintf(stderr, "NOTE: checking match <- best.\n");
     921           0 :     if(are_objects_derived_from_one_another(match, best, the_super_class))
     922             :     {
     923             :         // if match is in a class derived from
     924             :         // the class where we found best, then
     925             :         // this isn't an error, we just keep match
     926           0 :         best = match;
     927             : //fprintf(stderr, "RESULT! checking match <- best is true.\n");
     928           0 :         return true;
     929             :     }
     930             : 
     931           0 :     Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_DUPLICATES, best->get_position());
     932           0 :     msg << "found two functions named '" << best->get_string() << "' and both have the same prototype. Cannot determine which one to use.";
     933             : 
     934           0 :     return false;
     935             : }
     936             : 
     937             : 
     938           0 : bool Compiler::best_param_match(Node::pointer_t& best, Node::pointer_t match)
     939             : {
     940             :     // unprototyped?
     941           0 :     size_t const b_sz(best->get_param_size());
     942           0 :     size_t const m_sz(match->get_param_size());
     943           0 :     if(b_sz == 0)
     944             :     {
     945           0 :         if(m_sz == 0)
     946             :         {
     947           0 :             return best_param_match_derived_from(best, match);
     948             :         }
     949             :         // best had no prototype, but match has one, so we keep match
     950           0 :         best = match;
     951           0 :         return true;
     952             :     }
     953             : 
     954           0 :     if(m_sz == 0)
     955             :     {
     956             :         // we keep best in this case since it has a prototype
     957             :         // and not match
     958           0 :         return true;
     959             :     }
     960             : 
     961           0 :     size_t b_more(0);
     962           0 :     size_t m_more(0);
     963           0 :     for(size_t idx(0); idx < b_sz && idx < m_sz; ++idx)
     964             :     {
     965             :         // TODO: We must verify that "idx" is correct for those calls.
     966             :         //       At this point, it seems to me that it needs to be
     967             :         //       changed to 'j' as in:
     968             :         //
     969             :         //           j = best.get_param_index(idx);
     970             :         //           depth = best.get_param_depth(j);
     971             :         //
     972             :         //       But it was like this (wrong?) in the original.
     973             :         //
     974           0 :         int const r(best->get_param_depth(idx) - match->get_param_depth(idx));
     975           0 :         if(r < 0)
     976             :         {
     977           0 :             b_more++;
     978             :         }
     979           0 :         else if(r > 0)
     980             :         {
     981           0 :             m_more++;
     982             :         }
     983             :     }
     984             : 
     985             :     // if both are 0 or both not 0 then we cannot decide
     986           0 :     if((b_more != 0) ^ (m_more == 0))
     987             :     {
     988           0 :         return best_param_match_derived_from(best, match);
     989             :     }
     990             : 
     991             :     // "match" is better!
     992           0 :     if(m_more != 0)
     993             :     {
     994           0 :         best = match;
     995             :     }
     996             : 
     997           0 :     return true;
     998             : }
     999             : 
    1000             : 
    1001             : /** \brief One or more function was found, select the best one.
    1002             :  *
    1003             :  * This function checks all the functions we found and selects the best
    1004             :  * match according to the parameter types and count.
    1005             :  *
    1006             :  * \param[in] params  The parameters of the function.
    1007             :  * \param[out] resolution  The function we consider to be the best.
    1008             :  *
    1009             :  * \return true if a best function was found and resolution set to that node.
    1010             :  */
    1011           0 : bool Compiler::select_best_func(Node::pointer_t params, Node::pointer_t& resolution)
    1012             : {
    1013           0 :     if(!params)
    1014             :     {
    1015           0 :         throw exception_internal_error("params cannot be a null pointer in select_best_func()");
    1016             :     }
    1017             : 
    1018           0 :     bool found(true);
    1019             : 
    1020             :     // search for the best match
    1021             :     //NodeLock ln(directive_list); -- we're managing this list here
    1022           0 :     size_t max_children(params->get_children_size());
    1023           0 :     Node::pointer_t best;
    1024           0 :     size_t idx = 0, prev = -1;
    1025           0 :     while(idx < max_children)
    1026             :     {
    1027           0 :         Node::pointer_t match(params->get_child(idx));
    1028           0 :         if(match->get_type() == Node::node_t::NODE_PARAM_MATCH)
    1029             :         {
    1030           0 :             if(best)
    1031             :             {
    1032             :                 // compare best & match
    1033           0 :                 if(!best_param_match(best, match))
    1034             :                 {
    1035           0 :                     found = false;
    1036             :                 }
    1037           0 :                 if(best == match)
    1038             :                 {
    1039           0 :                     params->delete_child(prev);
    1040           0 :                     prev = idx;
    1041             :                 }
    1042             :                 else
    1043             :                 {
    1044           0 :                     params->delete_child(idx);
    1045             :                 }
    1046             :                 // TODO: see whether we should set to unknown instead of deleting
    1047           0 :                 --max_children;
    1048             :             }
    1049             :             else
    1050             :             {
    1051           0 :                 prev = idx;
    1052           0 :                 best = match;
    1053           0 :                 ++idx;
    1054             :             }
    1055             :         }
    1056             :         else
    1057             :         {
    1058           0 :             ++idx;
    1059             :         }
    1060           0 :     }
    1061             : 
    1062             :     // we should always have a best node
    1063           0 :     if(!best)
    1064             :     {
    1065           0 :         throw exception_internal_error("did not find at least one best function, even though we cannot have an empty list of choices when called");
    1066             :     }
    1067             : 
    1068           0 :     if(found)
    1069             :     {
    1070             :         // we found a better one! and no error occured
    1071           0 :         resolution = best->get_link(Node::link_t::LINK_INSTANCE);
    1072             :     }
    1073             : 
    1074           0 :     return found;
    1075             : }
    1076             : 
    1077             : 
    1078           0 : bool Compiler::funcs_name(int& funcs, Node::pointer_t resolution, bool const increment)
    1079             : {
    1080           0 :     if(!resolution)
    1081             :     {
    1082           0 :         return true;
    1083             :     }
    1084             : 
    1085           0 :     if(resolution->get_type() != Node::node_t::NODE_FUNCTION)
    1086             :     {
    1087             :         // TODO: do we really ignore those?!
    1088           0 :         return funcs == 0;
    1089             :     }
    1090           0 :     if(resolution->get_flag(Node::flag_t::NODE_FUNCTION_FLAG_GETTER)
    1091           0 :     || resolution->get_flag(Node::flag_t::NODE_FUNCTION_FLAG_SETTER))
    1092             :     {
    1093             :         // this is viewed as a variable; also, there is no
    1094             :         // parameters to a getter and thus no way to overload
    1095             :         // these; the setter has a parameter though but you
    1096             :         // cannot decide what it is going to be
    1097           0 :         return funcs == 0;
    1098             :     }
    1099             : 
    1100           0 :     if(increment)
    1101             :     {
    1102           0 :         funcs++;
    1103             :     }
    1104             : 
    1105           0 :     return false;
    1106             : }
    1107             : 
    1108             : 
    1109           0 : void Compiler::call_add_missing_params(Node::pointer_t call, Node::pointer_t params)
    1110             : {
    1111             :     // any children?
    1112           0 :     size_t idx(params->get_children_size());
    1113           0 :     if(idx == 0)
    1114             :     {
    1115           0 :         return;
    1116             :     }
    1117             : 
    1118             :     // if we have a parameter match, it has to be at the end
    1119           0 :     --idx;
    1120           0 :     Node::pointer_t match(params->get_child(idx));
    1121           0 :     if(match->get_type() != Node::node_t::NODE_PARAM_MATCH)
    1122             :     {
    1123             :         // Not a param match with a valid best match?!
    1124           0 :         throw exception_internal_error("call_add_missing_params() called when the list of parameters do not include a NODE_PARAM_MATCH");
    1125             :     }
    1126             : 
    1127             :     // found it
    1128             :     //
    1129             :     // TODO: "now we want to copy the array of indices to the
    1130             :     //       call instruction" -- old comment; we were copying
    1131             :     //       the array pointer to the call, but I think that
    1132             :     //       was only so we could delete the match node right
    1133             :     //       away... maybe I am wrong now and it would be
    1134             :     //       necessary to have that array in the call?
    1135             :     //
    1136           0 :     params->delete_child(idx);
    1137             : 
    1138             : #if 0
    1139             : fprintf(stderr, "         FIRST ON DATA:\n");
    1140             : call.Display(stderr);
    1141             : fprintf(stderr, "\n\n");
    1142             : #endif
    1143             : 
    1144           0 :     size_t size(match->get_param_size());
    1145           0 :     if(idx < size)
    1146             :     {
    1147             :         // get the list of parameters of the function
    1148           0 :         Node::pointer_t function_node(call->get_link(Node::link_t::LINK_INSTANCE));
    1149           0 :         if(!function_node)
    1150             :         {
    1151             :             // should never happen
    1152           0 :             return;
    1153             :         }
    1154           0 :         Node::pointer_t parameters_node(function_node->find_first_child(Node::node_t::NODE_PARAMETERS));
    1155           0 :         if(!parameters_node)
    1156             :         {
    1157             :             // should never happen
    1158           0 :             return;
    1159             :         }
    1160             : 
    1161             :         // Functions with no parameters just have no parameters node
    1162           0 :         size_t max_children(parameters_node->get_children_size());
    1163           0 :         while(idx < size)
    1164             :         {
    1165           0 :             size_t j(match->get_param_index(idx));
    1166           0 :             if(j >= max_children)
    1167             :             {
    1168           0 :                 throw exception_internal_error("somehow a parameter index is larger than the maximum number of children available");
    1169             :             }
    1170           0 :             Node::pointer_t param(parameters_node->get_child(j));
    1171           0 :             bool has_set = false;
    1172           0 :             size_t const cnt(param->get_children_size());
    1173           0 :             for(size_t k(0); k < cnt; ++k)
    1174             :             {
    1175           0 :                 Node::pointer_t set(param->get_child(k));
    1176           0 :                 if(set->get_type() == Node::node_t::NODE_SET
    1177           0 :                 && set->get_children_size() > 0)
    1178             :                 {
    1179           0 :                     has_set = true;
    1180           0 :                     Node::pointer_t auto_param(call->create_replacement(Node::node_t::NODE_AUTO));
    1181           0 :                     auto_param->set_link(Node::link_t::LINK_INSTANCE, set->get_child(0));
    1182           0 :                     params->append_child(auto_param);
    1183           0 :                     break;
    1184             :                 }
    1185           0 :             }
    1186           0 :             if(!has_set)
    1187             :             {
    1188             :                 // although it should be automatic we actually force
    1189             :                 // the undefined value here (we can optimize it out on
    1190             :                 // output later)
    1191           0 :                 Node::pointer_t undefined(call->create_replacement(Node::node_t::NODE_UNDEFINED));
    1192           0 :                 params->append_child(undefined);
    1193             :             }
    1194           0 :             idx++;
    1195           0 :         }
    1196           0 :     }
    1197             : }
    1198             : 
    1199             : 
    1200           0 : bool Compiler::resolve_call(Node::pointer_t call)
    1201             : {
    1202           0 :     size_t max_children(call->get_children_size());
    1203           0 :     if(max_children != 2)
    1204             :     {
    1205           0 :         return false;
    1206             :     }
    1207             : 
    1208           0 :     NodeLock ln(call);
    1209             : 
    1210             :     // resolve all the parameters' expressions first
    1211             :     // the parameters are always in a NODE_LIST
    1212             :     // and no parameters is equivalent to an empty NODE_LIST
    1213             :     // and that is an expression, but we don't want to type
    1214             :     // that expression since it isn't necessary so we go
    1215             :     // through the list here instead
    1216           0 :     Node::pointer_t params(call->get_child(1));
    1217           0 :     size_t count(params->get_children_size());
    1218             : //fprintf(stderr, "ResolveCall() with %d expressions\n", count);
    1219             : //call.Display(stderr);
    1220           0 :     for(size_t idx(0); idx < count; ++idx)
    1221             :     {
    1222           0 :         Node::pointer_t child(params->get_child(idx));
    1223           0 :         expression(child);
    1224           0 :     }
    1225             : 
    1226             :     // check the name expression
    1227           0 :     Node::pointer_t id(call->get_child(0));
    1228             : 
    1229             :     // if possible, resolve the function name
    1230           0 :     if(id->get_type() != Node::node_t::NODE_IDENTIFIER)
    1231             :     {
    1232             :         // a dynamic expression cannot always be
    1233             :         // resolved at compile time
    1234           0 :         Node::pointer_t expr_params;
    1235           0 :         expression(id, expr_params);
    1236             : 
    1237             :         // remove the NODE_PARAMT_MATCH if there is one
    1238           0 :         size_t const params_count(expr_params->get_children_size());
    1239           0 :         if(params_count > 0)
    1240             :         {
    1241           0 :             Node::pointer_t last(expr_params->get_child(params_count - 1));
    1242           0 :             if(last->get_type() == Node::node_t::NODE_PARAM_MATCH)
    1243             :             {
    1244           0 :                 expr_params->delete_child(params_count - 1);
    1245           0 :             }
    1246             :         }
    1247             : 
    1248           0 :         Node::pointer_t type(id->get_link(Node::link_t::LINK_TYPE));
    1249           0 :         call->set_link(Node::link_t::LINK_TYPE, type);
    1250             : 
    1251           0 :         return false;
    1252             :     }
    1253             : 
    1254           0 :     int const errcnt(Message::error_count());
    1255             : 
    1256             :     // straight identifiers can be resolved at compile time;
    1257             :     // these need to be function names
    1258           0 :     Node::pointer_t resolution;
    1259             : 
    1260           0 :     if(resolve_name(id, id, resolution, params, SEARCH_FLAG_GETTER))
    1261             :     {
    1262             : //fprintf(stderr, "Cool! identifier found [%s]\n", name.f_str.GetUTF8());
    1263           0 :         if(resolution->get_type() == Node::node_t::NODE_CLASS
    1264           0 :         || resolution->get_type() == Node::node_t::NODE_INTERFACE)
    1265             :         {
    1266             :             // this looks like a cast, but if the parent is
    1267             :             // the NEW operator, then it is really a call!
    1268             :             // yet that is caught in expression_new()
    1269             : //fprintf(stderr, "This is not a call, it is a cast instead! [%s]\n", name.f_str.GetUTF8());
    1270           0 :             ln.unlock();
    1271           0 :             Node::pointer_t type(call->get_child(0));
    1272           0 :             Node::pointer_t expr(call->get_child(1));
    1273           0 :             call->delete_child(0);
    1274           0 :             call->delete_child(0);    // 1 is now 0
    1275           0 :             call->append_child(expr);
    1276           0 :             call->append_child(type);
    1277           0 :             type->set_link(Node::link_t::LINK_INSTANCE, resolution);
    1278           0 :             call->to_as();
    1279           0 :             return true;
    1280             :         }
    1281           0 :         else if(resolution->get_type() == Node::node_t::NODE_VARIABLE)
    1282             :         {
    1283             :             // if it is a variable, we need to test
    1284             :             // the type for a "()" operator
    1285             : //fprintf(stderr, "Looking for a '()' operator\n");
    1286           0 :             Node::pointer_t var_class(resolution->get_link(Node::link_t::LINK_TYPE));
    1287           0 :             if(var_class)
    1288             :             {
    1289           0 :                 id->set_link(Node::link_t::LINK_INSTANCE, var_class);
    1290             :                 // search for a function named "()"
    1291             :                 //NodePtr l;
    1292             :                 //l.CreateNode(NODE_IDENTIFIER);
    1293             :                 //Data& lname = l.GetData();
    1294             :                 //lname.f_str = "left";
    1295           0 :                 ln.unlock();
    1296           0 :                 Node::pointer_t all_params(call->get_child(1));
    1297           0 :                 call->delete_child(1);
    1298             :                 //NodePtr op_params;
    1299             :                 //op_params.CreateNode(NODE_LIST);
    1300             :                 //op_params.AddChild(l);
    1301           0 :                 Node::pointer_t op(call->create_replacement(Node::node_t::NODE_IDENTIFIER));
    1302           0 :                 op->set_string("()");
    1303           0 :                 op->append_child(all_params);
    1304           0 :                 Node::pointer_t func;
    1305           0 :                 size_t del(call->get_children_size());
    1306           0 :                 call->append_child(op);
    1307           0 :                 int funcs(0);
    1308             : //fprintf(stderr, "Find the field now... for a '()' operator\n");
    1309           0 :                 bool const result(find_field(var_class, op, funcs, func, params, 0));
    1310           0 :                 call->delete_child(del);
    1311           0 :                 if(result)
    1312             :                 {
    1313           0 :                     resolution = func;
    1314           0 :                     Node::pointer_t identifier(id);
    1315           0 :                     Node::pointer_t member(call->create_replacement(Node::node_t::NODE_MEMBER));
    1316           0 :                     call->set_child(0, member);
    1317           0 :                     op->delete_child(0);
    1318           0 :                     if(call->get_children_size() > 1)
    1319             :                     {
    1320           0 :                         call->set_child(1, all_params);
    1321             :                     }
    1322             :                     else
    1323             :                     {
    1324           0 :                         call->append_child(all_params);
    1325             :                     }
    1326           0 :                     member->append_child(identifier);
    1327           0 :                     member->append_child(op);
    1328             :                 }
    1329             :                 else
    1330             :                 {
    1331           0 :                     Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_UNKNOWN_OPERATOR, call->get_position());
    1332           0 :                     msg << "no '()' operators found in '" << var_class->get_string() << "'.";
    1333           0 :                     return false;
    1334           0 :                 }
    1335             :             }
    1336             :             else
    1337             :             {
    1338           0 :                 Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INTERNAL_ERROR, resolution->get_position());
    1339           0 :                 msg << "getters and setters not supported yet (what is that error message saying?!).";
    1340           0 :             }
    1341             :         }
    1342           0 :         else if(resolution->get_type() != Node::node_t::NODE_FUNCTION)
    1343             :         {
    1344           0 :             Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INVALID_TYPE, id->get_position());
    1345           0 :             msg << "'" << id->get_string() << "' was expected to be a type, a variable or a function.";
    1346           0 :             return false;
    1347             :         }
    1348             :         //
    1349             :         // If the resolution is in a class that means it is in 'this'
    1350             :         // class and thus we want to change the call to a member call:
    1351             :         //
    1352             :         //    this.<name>(params);
    1353             :         //
    1354             :         // This is important for at least Flash 7 which doesn't get it
    1355             :         // otherwise, I don't think it would be required otherwise (i.e Flash
    1356             :         // 7.x searches for a global function on that name!)
    1357             :         //
    1358           0 :         Node::pointer_t res_class(class_of_member(resolution));
    1359           0 :         if(res_class)
    1360             :         {
    1361           0 :             ln.unlock();
    1362           0 :             Node::pointer_t identifier(id);
    1363           0 :             Node::pointer_t member(call->create_replacement(Node::node_t::NODE_MEMBER));
    1364           0 :             call->set_child(0, member);
    1365           0 :             Node::pointer_t this_expr(call->create_replacement(Node::node_t::NODE_THIS));
    1366           0 :             member->append_child(this_expr);
    1367           0 :             member->append_child(identifier);
    1368             :         }
    1369           0 :         call->set_link(Node::link_t::LINK_INSTANCE, resolution);
    1370           0 :         Node::pointer_t type(resolution->get_link(Node::link_t::LINK_TYPE));
    1371           0 :         if(type)
    1372             :         {
    1373           0 :             call->set_link(Node::link_t::LINK_TYPE, type);
    1374             :         }
    1375           0 :         call_add_missing_params(call, params);
    1376           0 :         return true;
    1377             :     }
    1378             : 
    1379           0 :     if(errcnt == Message::error_count())
    1380             :     {
    1381           0 :         Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_NOT_FOUND, id->get_position());
    1382           0 :         msg << "function named '" << id->get_string() << "' not found.";
    1383             :     }
    1384             : 
    1385           0 :     return false;
    1386             : }
    1387             : 
    1388             : 
    1389             : /** \brief Check whether that function was not marked as final before.
    1390             :  *
    1391             :  * \return true if the function is marked as final in a super definition.
    1392             :  */
    1393           0 : bool Compiler::find_final_functions(Node::pointer_t& function_node, Node::pointer_t& super)
    1394             : {
    1395           0 :     size_t const max_children(super->get_children_size());
    1396           0 :     for(size_t idx(0); idx < max_children; ++idx)
    1397             :     {
    1398           0 :         Node::pointer_t child(super->get_child(idx));
    1399           0 :         switch(child->get_type())
    1400             :         {
    1401             :         case Node::node_t::NODE_EXTENDS:
    1402             :         {
    1403           0 :             Node::pointer_t next_super(child->get_link(Node::link_t::LINK_INSTANCE));
    1404           0 :             if(next_super)
    1405             :             {
    1406           0 :                 if(find_final_functions(function_node, next_super)) // recursive
    1407             :                 {
    1408           0 :                     return true;
    1409             :                 }
    1410           0 :             }
    1411             :         }
    1412           0 :             break;
    1413             : 
    1414             :         case Node::node_t::NODE_DIRECTIVE_LIST:
    1415           0 :             if(find_final_functions(function_node, child)) // recursive
    1416             :             {
    1417           0 :                 return true;
    1418             :             }
    1419           0 :             break;
    1420             : 
    1421             :         case Node::node_t::NODE_FUNCTION:
    1422             :             // TBD: are we not also expected to check the number of
    1423             :             //      parameter to know that it is the same function?
    1424             :             //      (see compare_parameters() below)
    1425           0 :             if(function_node->get_string() == child->get_string())
    1426             :             {
    1427             :                 // we found a function of the same name
    1428           0 :                 if(get_attribute(child, Node::attribute_t::NODE_ATTR_FINAL))
    1429             :                 {
    1430             :                     // Ooops! it was final...
    1431           0 :                     return true;
    1432             :                 }
    1433             :             }
    1434           0 :             break;
    1435             : 
    1436             :         default:
    1437           0 :             break;
    1438             : 
    1439             :         }
    1440           0 :     }
    1441             : 
    1442           0 :     return false;
    1443             : }
    1444             : 
    1445             : 
    1446             : /** \brief Check whether that function was not marked as final before.
    1447             :  *
    1448             :  * \return true if the function is marked as final in a super definition.
    1449             :  */
    1450           0 : bool Compiler::check_final_functions(Node::pointer_t& function_node, Node::pointer_t& class_node)
    1451             : {
    1452           0 :     size_t const max_children(class_node->get_children_size());
    1453           0 :     for(size_t idx(0); idx < max_children; ++idx)
    1454             :     {
    1455           0 :         Node::pointer_t child(class_node->get_child(idx));
    1456             : 
    1457             :         // NOTE: there can be only one 'extends'
    1458             :         //
    1459             :         // TODO: we most certainly can support more than one extend in
    1460             :         //       JavaScript, although it is not 100% clean, but we can
    1461             :         //       make it work so we will have to enhance this test
    1462           0 :         if(child->get_type() == Node::node_t::NODE_EXTENDS
    1463           0 :         && child->get_children_size() > 0)
    1464             :         {
    1465             :             // this points to another class which may define
    1466             :             // the same function as final
    1467           0 :             Node::pointer_t name(child->get_child(0));
    1468           0 :             Node::pointer_t super(name->get_link(Node::link_t::LINK_INSTANCE));
    1469           0 :             if(super)
    1470             :             {
    1471           0 :                 return find_final_functions(function_node, super);
    1472             :             }
    1473           0 :             break;
    1474             :         }
    1475           0 :     }
    1476             : 
    1477           0 :     return false;
    1478             : }
    1479             : 
    1480             : 
    1481           0 : bool Compiler::compare_parameters(Node::pointer_t& lfunction, Node::pointer_t& rfunction)
    1482             : {
    1483             :     // search for the list of parameters in each function
    1484           0 :     Node::pointer_t lparams(lfunction->find_first_child(Node::node_t::NODE_PARAMETERS));
    1485           0 :     Node::pointer_t rparams(rfunction->find_first_child(Node::node_t::NODE_PARAMETERS));
    1486             : 
    1487             :     // get the number of parameters in each list
    1488           0 :     size_t const lmax(lparams ? lparams->get_children_size() : 0);
    1489           0 :     size_t const rmax(rparams ? rparams->get_children_size() : 0);
    1490             : 
    1491             :     // if we do not have the same number of parameters, already, we know it
    1492             :     // is not the same, even if one has just a rest in addition
    1493           0 :     if(lmax != rmax)
    1494             :     {
    1495           0 :         return false;
    1496             :     }
    1497             : 
    1498             :     // same number, compare the types
    1499           0 :     for(size_t idx(0); idx < lmax; ++idx)
    1500             :     {
    1501             :         // Get the PARAM
    1502           0 :         Node::pointer_t lp(lparams->get_child(idx));
    1503           0 :         Node::pointer_t rp(rparams->get_child(idx));
    1504             :         // Get the type of each PARAM
    1505             :         // TODO: test that lp and rp have at least one child?
    1506           0 :         Node::pointer_t l(lp->get_child(0));
    1507           0 :         Node::pointer_t r(rp->get_child(0));
    1508             :         // We can directly compare strings and identifiers
    1509             :         // Anything else fails meaning that we consider them equal
    1510           0 :         if((l->get_type() != Node::node_t::NODE_IDENTIFIER && l->get_type() != Node::node_t::NODE_STRING)
    1511           0 :         || (r->get_type() != Node::node_t::NODE_IDENTIFIER && r->get_type() != Node::node_t::NODE_STRING))
    1512             :         {
    1513             :             // if we cannot compare at compile time,
    1514             :             // we consider the types as equal... (i.e. match!)
    1515           0 :             continue;
    1516             :         }
    1517           0 :         if(l->get_string() != r->get_string())
    1518             :         {
    1519           0 :             return false;
    1520             :         }
    1521           0 :     }
    1522             : 
    1523           0 :     return true;
    1524             : }
    1525             : 
    1526             : 
    1527             : 
    1528           0 : bool Compiler::check_unique_functions(Node::pointer_t function_node, Node::pointer_t class_node, bool const all_levels)
    1529             : {
    1530           0 :     size_t const max(class_node->get_children_size());
    1531           0 :     for(size_t idx(0); idx < max; ++idx)
    1532             :     {
    1533           0 :         Node::pointer_t child(class_node->get_child(idx));
    1534           0 :         switch(child->get_type())
    1535             :         {
    1536             :         case Node::node_t::NODE_DIRECTIVE_LIST:
    1537           0 :             if(all_levels)
    1538             :             {
    1539           0 :                 if(check_unique_functions(function_node, child, true)) // recursive
    1540             :                 {
    1541           0 :                     return true;
    1542             :                 }
    1543             :             }
    1544           0 :             break;
    1545             : 
    1546             :         case Node::node_t::NODE_FUNCTION:
    1547             :             // TODO: stop recursion properly
    1548             :             //
    1549             :             // this condition is not enough to stop this
    1550             :             // recursive process; but I think it is good
    1551             :             // enough for most cases; the only problem is
    1552             :             // anyway that we will eventually get the same
    1553             :             // error multiple times...
    1554           0 :             if(child == function_node)
    1555             :             {
    1556           0 :                 return false;
    1557             :             }
    1558             : 
    1559           0 :             if(function_node->get_string() == child->get_string())
    1560             :             {
    1561           0 :                 if(compare_parameters(function_node, child))
    1562             :                 {
    1563           0 :                     Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_DUPLICATES, function_node->get_position());
    1564           0 :                     msg << "you cannot define two functions with the same name (" << function_node->get_string()
    1565           0 :                                 << ") and prototype in the same scope, class or interface.";
    1566           0 :                     return true;
    1567             :                 }
    1568             :             }
    1569           0 :             break;
    1570             : 
    1571             :         case Node::node_t::NODE_VAR:
    1572             :         {
    1573           0 :             size_t const cnt(child->get_children_size());
    1574           0 :             for(size_t j(0); j < cnt; ++j)
    1575             :             {
    1576           0 :                 Node::pointer_t variable_node(child->get_child(j));
    1577           0 :                 if(function_node->get_string() == variable_node->get_string())
    1578             :                 {
    1579           0 :                     Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_DUPLICATES, function_node->get_position());
    1580           0 :                     msg << "you cannot define a function and a variable (found at line #"
    1581           0 :                             << variable_node->get_position().get_line()
    1582           0 :                             << ") with the same name ("
    1583           0 :                             << function_node->get_string()
    1584           0 :                             << ") in the same scope, class or interface.";
    1585           0 :                     return true;
    1586             :                 }
    1587           0 :             }
    1588             :         }
    1589           0 :             break;
    1590             : 
    1591             :         default:
    1592           0 :             break;
    1593             : 
    1594             :         }
    1595           0 :     }
    1596             : 
    1597           0 :     return false;
    1598             : }
    1599             : 
    1600             : 
    1601             : 
    1602          63 : }
    1603             : // namespace as2js
    1604             : 
    1605             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.10