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

          Line data    Source code
       1             : /* compiler_statement.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           0 : void Compiler::with(Node::pointer_t& with_node)
      48             : {
      49           0 :     size_t const max_children(with_node->get_children_size());
      50           0 :     if(max_children != 2)
      51             :     {
      52             :         // invalid, ignore
      53           0 :         return;
      54             :     }
      55           0 :     NodeLock ln(with_node);
      56             : 
      57             :     // object name defined in an expression
      58             :     // (used to resolve identifiers as members in the following
      59             :     // expressions until it gets popped)
      60           0 :     Node::pointer_t object(with_node->get_child(0));
      61             : 
      62           0 :     if(object->get_type() == Node::node_t::NODE_THIS)
      63             :     {
      64             :         // TODO: could we avoid erring here?!
      65           0 :         Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INVALID_EXPRESSION, object->get_position());
      66           0 :         msg << "'with' cannot use 'this' as an object.";
      67             :     }
      68             : 
      69             : //fprintf(stderr, "Resolving WITH object...\n");
      70             : 
      71           0 :     expression(object);
      72             : 
      73             :     // we create two nodes; one so we know we have a WITH instruction
      74             :     // and a child of that node which is the object itself; these are
      75             :     // deleted once we return from this function
      76             :     //NodePtr t;
      77             :     //t.CreateNode();
      78             :     //t.SetData(object.GetData());
      79             :     //NodePtr w;
      80             :     //w.CreateNode(NODE_WITH);
      81             :     //w.AddChild(t);
      82             :     //int p = f_scope.GetChildCount();
      83             :     //f_scope.AddChild(w);
      84             : 
      85           0 :     Node::pointer_t sub_directives(with_node->get_child(1));
      86           0 :     directive_list(sub_directives);
      87             : 
      88             :     // the effect of this with() ends with the end of its
      89             :     // list of directives
      90             :     //f_scope.DeleteChild(p);
      91             : }
      92             : 
      93             : 
      94             : 
      95             : /** \brief Compile the goto directive.
      96             :  *
      97             :  * Note that JavaScript in browsers do not support the goto instruction.
      98             :  * They have a similar behavior when using while() loop and either a
      99             :  * continue (goto at the start) or the break (goto after the while()
     100             :  * loop.).
     101             :  *
     102             :  * This function is kept here, although we are very unlikely to implement
     103             :  * the instruction in your browser, it may end up being useful in case
     104             :  * we again work on ActionScript.
     105             :  *
     106             :  * \param[in] goto_node  The node representing the goto statement.
     107             :  */
     108           0 : void Compiler::goto_directive(Node::pointer_t& goto_node)
     109             : {
     110           0 :     Node::vector_of_pointers_t parents;
     111           0 :     Node::pointer_t label;
     112           0 :     Node::pointer_t parent(goto_node);
     113           0 :     do
     114             :     {
     115           0 :         parent = parent->get_parent();
     116           0 :         if(!parent)
     117             :         {
     118           0 :             Message msg(message_level_t::MESSAGE_LEVEL_FATAL, err_code_t::AS_ERR_INTERNAL_ERROR, goto_node->get_position());
     119           0 :             msg << "Compiler::goto(): out of parents before we find function, program or package parent?!";
     120           0 :             throw exception_exit(1, "Compiler::goto(): out of parents before we find function, program or package parent?!");
     121             :         }
     122             : 
     123           0 :         switch(parent->get_type())
     124             :         {
     125             :         case Node::node_t::NODE_CLASS:
     126             :         case Node::node_t::NODE_INTERFACE:
     127             :             {
     128           0 :                 Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_IMPROPER_STATEMENT, goto_node->get_position());
     129           0 :                 msg << "cannot have a GOTO instruction in a 'class' or 'interface'.";
     130             :             }
     131           0 :             return;
     132             : 
     133             :         case Node::node_t::NODE_FUNCTION:
     134             :         case Node::node_t::NODE_PACKAGE:
     135             :         case Node::node_t::NODE_PROGRAM:
     136           0 :             label = parent->find_label(goto_node->get_string());
     137           0 :             if(!label)
     138             :             {
     139           0 :                 Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_LABEL_NOT_FOUND, goto_node->get_position());
     140           0 :                 msg << "label '" << goto_node->get_string() << "' for goto instruction not found.";
     141           0 :                 return;
     142             :             }
     143           0 :             break;
     144             : 
     145             :         // We most certainly want to test those with some user
     146             :         // options to know whether we should accept or refuse
     147             :         // inter-frame gotos
     148             :         //case Node::node_t::NODE_WITH:
     149             :         //case Node::node_t::NODE_TRY:
     150             :         //case Node::node_t::NODE_CATCH:
     151             :         //case Node::node_t::NODE_FINALLY:
     152             : 
     153             :         default:
     154           0 :             break;
     155             : 
     156             :         }
     157           0 :         parents.push_back(parent);
     158             :     }
     159           0 :     while(!label);
     160           0 :     goto_node->set_link(Node::link_t::LINK_GOTO_ENTER, label);
     161             : 
     162             :     // Now we have to do the hardest part:
     163             :     //    find the common parent frame where both, the goto
     164             :     //    and the label can be found
     165             :     //    for this purpose we created an array with all the
     166             :     //    frames (parents) and then we search that array with each
     167             :     //    parent of the label
     168             : 
     169           0 :     parent = label;
     170             :     for(;;)
     171             :     {
     172           0 :         parent = parent->get_parent();
     173           0 :         if(!parent)
     174             :         {
     175             :             // never found a common parent?!
     176           0 :             Message msg(message_level_t::MESSAGE_LEVEL_FATAL, err_code_t::AS_ERR_INTERNAL_ERROR, goto_node->get_position());
     177           0 :             msg << "Compiler::goto(): out of parent before we find the common node?!";
     178           0 :             throw exception_exit(1, "Compiler::goto(): out of parent before we find the common node?!");
     179             :         }
     180           0 :         for(size_t idx(0); idx < parents.size(); ++idx)
     181             :         {
     182           0 :             if(parents[idx] == parent)
     183             :             {
     184             :                 // found the first common parent
     185           0 :                 goto_node->set_link(Node::link_t::LINK_GOTO_EXIT, parent);
     186           0 :                 return;
     187             :             }
     188             :         }
     189           0 :     }
     190             : }
     191             : 
     192             : 
     193             : 
     194           0 : void Compiler::for_directive(Node::pointer_t& for_node)
     195             : {
     196             :     // support for the two forms: for(foo in blah) ... and for(a;b;c) ...
     197             :     // (Note: first case we have 3 children: foo, blah, directives
     198             :     //        second case we have 4 children: a, b, c, directives
     199           0 :     size_t max(for_node->get_children_size());
     200           0 :     if(max < 3)
     201             :     {
     202           0 :         return;
     203             :     }
     204           0 :     NodeLock ln(for_node);
     205             : 
     206           0 :     for(size_t idx(0); idx < max; ++idx)
     207             :     {
     208           0 :         Node::pointer_t child(for_node->get_child(idx));
     209           0 :         switch(child->get_type())
     210             :         {
     211             :         case Node::node_t::NODE_EMPTY:
     212             :             // do nothing
     213           0 :             break;
     214             : 
     215             :         case Node::node_t::NODE_DIRECTIVE_LIST:
     216           0 :             directive_list(child);
     217           0 :             break;
     218             : 
     219             :         case Node::node_t::NODE_VAR:
     220           0 :             var(child);
     221           0 :             break;
     222             : 
     223             :         default:    // expression
     224           0 :             expression(child);
     225           0 :             break;
     226             : 
     227             :         }
     228           0 :     }
     229             : }
     230             : 
     231             : 
     232           0 : void Compiler::switch_directive(Node::pointer_t& switch_node)
     233             : {
     234           0 :     size_t const max_children(switch_node->get_children_size());
     235           0 :     if(max_children != 2)
     236             :     {
     237           0 :         return;
     238             :     }
     239             : 
     240           0 :     NodeLock ln_sn(switch_node);
     241           0 :     expression(switch_node->get_child(0));
     242             : 
     243             :     // make sure that the list of directive starts
     244             :     // with a label [this is a requirement which
     245             :     // really makes sense but the parser does not
     246             :     // enforce it]
     247           0 :     Node::pointer_t directive_list_node(switch_node->get_child(1));
     248           0 :     size_t const max_directives(directive_list_node->get_children_size());
     249           0 :     if(max_directives > 0)
     250             :     {
     251           0 :         Node::pointer_t child(directive_list_node->get_child(0));
     252           0 :         if(child->get_type() != Node::node_t::NODE_CASE
     253           0 :         && child->get_type() != Node::node_t::NODE_DEFAULT)
     254             :         {
     255           0 :             Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INACCESSIBLE_STATEMENT, switch_node->get_position());
     256           0 :             msg << "the list of instructions of a 'switch()' statement must start with a 'case' or 'default' label.";
     257           0 :         }
     258             :     }
     259             :     // else -- should we warn when empty?
     260             : 
     261           0 :     directive_list(directive_list_node);
     262             : 
     263             :     // reset the DEFAULT flag just in case we get compiled a second
     264             :     // time (which happens when testing for missing return statements)
     265           0 :     switch_node->set_flag(Node::flag_t::NODE_SWITCH_FLAG_DEFAULT, false);
     266             : 
     267             :     // TODO: If EQUAL or STRICTLY EQUAL we may
     268             :     //       want to check for duplicates.
     269             :     //       (But cases can be dynamic so it
     270             :     //       does not really make sense, does it?!)
     271             : }
     272             : 
     273             : 
     274           0 : void Compiler::case_directive(Node::pointer_t& case_node)
     275             : {
     276             :     // make sure it was used inside a switch statement
     277             :     // (the parser doesn't enforce it)
     278           0 :     Node::pointer_t parent(case_node->get_parent());
     279           0 :     if(!parent)
     280             :     {
     281             :         // ?!?
     282           0 :         return;
     283             :     }
     284           0 :     parent = parent->get_parent();
     285           0 :     if(!parent)
     286             :     {
     287             :         // ?!?
     288           0 :         return;
     289             :     }
     290           0 :     if(parent->get_type() != Node::node_t::NODE_SWITCH)
     291             :     {
     292           0 :         Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_IMPROPER_STATEMENT, case_node->get_position());
     293           0 :         msg << "a 'case' statement can only be used within a 'switch()' block.";
     294           0 :         return;
     295             :     }
     296             : 
     297           0 :     size_t const max_children(case_node->get_children_size());
     298           0 :     if(max_children > 0)
     299             :     {
     300           0 :         expression(case_node->get_child(0));
     301           0 :         if(max_children > 1)
     302             :         {
     303           0 :             switch(parent->get_switch_operator())
     304             :             {
     305             :             case Node::node_t::NODE_UNKNOWN:
     306             :             case Node::node_t::NODE_IN:
     307           0 :                 break;
     308             : 
     309             :             default:
     310             :                 {
     311           0 :                     Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INVALID_EXPRESSION, case_node->get_position());
     312           0 :                     msg << "a range on a 'case' statement can only be used with the 'in' and 'default' switch() operators.";
     313             :                 }
     314           0 :                 break;
     315             : 
     316             :             }
     317           0 :             expression(case_node->get_child(1));
     318             :         }
     319           0 :     }
     320             : }
     321             : 
     322             : 
     323           0 : void Compiler::default_directive(Node::pointer_t& default_node)
     324             : {
     325             :     // make sure it was used inside a switch statement
     326             :     // (the parser doesn't enforce it)
     327           0 :     Node::pointer_t parent(default_node->get_parent());
     328           0 :     if(!parent) {
     329             :         // ?!?
     330           0 :         return;
     331             :     }
     332           0 :     parent = parent->get_parent();
     333           0 :     if(!parent) {
     334             :         // ?!?
     335           0 :         return;
     336             :     }
     337           0 :     if(parent->get_type() != Node::node_t::NODE_SWITCH)
     338             :     {
     339           0 :         Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INACCESSIBLE_STATEMENT, default_node->get_position());
     340           0 :         msg << "a 'default' statement can only be used within a 'switch()' block.";
     341           0 :         return;
     342             :     }
     343             : 
     344           0 :     if(parent->get_flag(Node::flag_t::NODE_SWITCH_FLAG_DEFAULT))
     345             :     {
     346           0 :         Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_IMPROPER_STATEMENT, default_node->get_position());
     347           0 :         msg << "only one 'default' statement can be used within one 'switch()'.";
     348             :     }
     349             :     else
     350             :     {
     351           0 :         parent->set_flag(Node::flag_t::NODE_SWITCH_FLAG_DEFAULT, true);
     352           0 :     }
     353             : }
     354             : 
     355             : 
     356           0 : void Compiler::if_directive(Node::pointer_t& if_node)
     357             : {
     358           0 :     size_t const max_children(if_node->get_children_size());
     359           0 :     if(max_children < 2)
     360             :     {
     361           0 :         return;
     362             :     }
     363           0 :     NodeLock ln(if_node);
     364             : 
     365             :     // TBD: check whether the first expression
     366             :     //      is a valid boolean? (for strict mode
     367             :     //      maybe, but JavaScript is very lax on
     368             :     //      just like C/C++)
     369           0 :     expression(if_node->get_child(0));
     370           0 :     directive_list(if_node->get_child(1));
     371           0 :     if(max_children == 3)
     372             :     {
     373             :         // else part
     374           0 :         directive_list(if_node->get_child(2));
     375           0 :     }
     376             : }
     377             : 
     378             : 
     379           0 : void Compiler::while_directive(Node::pointer_t& while_node)
     380             : {
     381           0 :     size_t const max_children(while_node->get_children_size());
     382           0 :     if(max_children != 2)
     383             :     {
     384           0 :         return;
     385             :     }
     386           0 :     NodeLock ln(while_node);
     387             : 
     388             :     // If the first expression is a constant boolean,
     389             :     // the optimizer will replace the while()
     390             :     // loop in a loop forever; or remove it entirely.
     391           0 :     expression(while_node->get_child(0));
     392           0 :     directive_list(while_node->get_child(1));
     393             : }
     394             : 
     395             : 
     396           0 : void Compiler::do_directive(Node::pointer_t& do_node)
     397             : {
     398           0 :     size_t const max_children(do_node->get_children_size());
     399           0 :     if(max_children != 2)
     400             :     {
     401           0 :         return;
     402             :     }
     403           0 :     NodeLock ln(do_node);
     404             : 
     405             :     // If the second expression is a constant boolean,
     406             :     // the optimizer will replace the do/while()
     407             :     // loop in a loop forever; or execute the first
     408             :     // list of directives once.
     409           0 :     directive_list(do_node->get_child(0));
     410           0 :     expression(do_node->get_child(1));
     411             : }
     412             : 
     413             : 
     414           0 : void Compiler::break_continue(Node::pointer_t& break_node)
     415             : {
     416           0 :     bool const no_label(break_node->get_string().empty());
     417           0 :     bool const accept_switch(!no_label || break_node->get_type() == Node::node_t::NODE_BREAK);
     418           0 :     bool found_switch(false);
     419           0 :     Node::pointer_t parent(break_node);
     420             :     for(;;)
     421             :     {
     422           0 :         parent = parent->get_parent();
     423           0 :         if(parent->get_type() == Node::node_t::NODE_SWITCH)
     424             :         {
     425           0 :             found_switch = true;
     426             :         }
     427           0 :         if((parent->get_type() == Node::node_t::NODE_SWITCH && accept_switch)
     428           0 :         || parent->get_type() == Node::node_t::NODE_FOR
     429           0 :         || parent->get_type() == Node::node_t::NODE_DO
     430           0 :         || parent->get_type() == Node::node_t::NODE_WHILE)
     431             :         {
     432           0 :             if(no_label)
     433             :             {
     434             :                 // just break the current 'switch', 'for',
     435             :                 // 'while', 'do' when there is no name.
     436           0 :                 break;
     437             :             }
     438             :             // check whether this statement has a label
     439             :             // and whether it matches the requested name
     440           0 :             int32_t const offset(parent->get_offset());
     441           0 :             if(offset > 0)
     442             :             {
     443           0 :                 Node::pointer_t p(parent->get_parent());
     444           0 :                 Node::pointer_t previous(p->get_child(offset - 1));
     445           0 :                 if(previous->get_type() == Node::node_t::NODE_LABEL
     446           0 :                 && previous->get_string() == break_node->get_string())
     447             :                 {
     448             :                     // found a match
     449           0 :                     break;
     450           0 :                 }
     451             :             }
     452             :         }
     453           0 :         if(parent->get_type() == Node::node_t::NODE_FUNCTION
     454           0 :         || parent->get_type() == Node::node_t::NODE_PROGRAM
     455           0 :         || parent->get_type() == Node::node_t::NODE_CLASS       // ?!
     456           0 :         || parent->get_type() == Node::node_t::NODE_INTERFACE   // ?!
     457           0 :         || parent->get_type() == Node::node_t::NODE_PACKAGE)
     458             :         {
     459             :             // not found?! a break/continue outside a loop or
     460             :             // switch?! or the label was not found
     461           0 :             if(no_label)
     462             :             {
     463           0 :                 if(found_switch)
     464             :                 {
     465           0 :                     Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_IMPROPER_STATEMENT, break_node->get_position());
     466           0 :                     msg << "you cannot use a continue statement outside a loop (and you need a label to make it work with a switch statement).";
     467             :                 }
     468             :                 else
     469             :                 {
     470           0 :                     Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_IMPROPER_STATEMENT, break_node->get_position());
     471           0 :                     msg << "you cannot use a break or continue instruction outside a loop or switch statement.";
     472             :                 }
     473             :             }
     474             :             else
     475             :             {
     476           0 :                 Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_LABEL_NOT_FOUND, break_node->get_position());
     477           0 :                 msg << "could not find a loop or switch statement labelled '" << break_node->get_string() << "' for this break or continue.";
     478             :             }
     479           0 :             return;
     480             :         }
     481           0 :     }
     482             : 
     483             :     // We just specify which node needs to be reached
     484             :     // on this break/continue.
     485             :     //
     486             :     // We do not replace these with a simple goto instruction
     487             :     // because that way the person using the tree later can
     488             :     // program the break and/or continue the way they feel
     489             :     // (using a variable, a special set of instructions,
     490             :     // etc. so as to be able to unwind all the necessary
     491             :     // data in a way specific to the break/continue).
     492             :     //
     493             :     // Also in browsers, JavaScript does not offer a goto.
     494           0 :     break_node->set_link(Node::link_t::LINK_GOTO_EXIT, parent);
     495             : }
     496             : 
     497             : 
     498             : 
     499           0 : void Compiler::throw_directive(Node::pointer_t& throw_node)
     500             : {
     501           0 :     if(throw_node->get_children_size() != 1)
     502             :     {
     503           0 :         return;
     504             :     }
     505             : 
     506           0 :     expression(throw_node->get_child(0));
     507             : }
     508             : 
     509             : 
     510           0 : void Compiler::try_directive(Node::pointer_t& try_node)
     511             : {
     512           0 :     if(try_node->get_children_size() != 1)
     513             :     {
     514           0 :         return;
     515             :     }
     516             : 
     517             :     // we want to make sure that we are followed
     518             :     // by a catch or a finally
     519           0 :     Node::pointer_t parent(try_node->get_parent());
     520           0 :     bool correct(false);
     521           0 :     size_t const max_parent_children(parent->get_children_size());
     522           0 :     size_t const offset(static_cast<size_t>(try_node->get_offset()) + 1);
     523           0 :     if(offset < max_parent_children)
     524             :     {
     525           0 :         Node::pointer_t next(parent->get_child(offset));
     526           0 :         if(next->get_type() == Node::node_t::NODE_CATCH
     527           0 :         || next->get_type() == Node::node_t::NODE_FINALLY)
     528             :         {
     529           0 :             correct = true;
     530           0 :         }
     531             :     }
     532           0 :     if(!correct)
     533             :     {
     534           0 :         Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INVALID_TRY, try_node->get_position());
     535           0 :         msg << "a 'try' statement needs to be followed by at least one of 'catch' or 'finally'.";
     536             :     }
     537             : 
     538           0 :     directive_list(try_node->get_child(0));
     539             : }
     540             : 
     541             : 
     542           0 : void Compiler::catch_directive(Node::pointer_t& catch_node)
     543             : {
     544           0 :     if(catch_node->get_children_size() != 2)
     545             :     {
     546           0 :         return;
     547             :     }
     548             : 
     549             :     // we want to make sure that we are preceded by a try
     550           0 :     Node::pointer_t parent(catch_node->get_parent());
     551           0 :     bool correct(false);
     552           0 :     int32_t const offset(catch_node->get_offset());
     553           0 :     if(offset > 0)
     554             :     {
     555           0 :         Node::pointer_t prev(parent->get_child(offset - 1));
     556           0 :         if(prev->get_type() == Node::node_t::NODE_TRY)
     557             :         {
     558           0 :             correct = true;
     559             :         }
     560           0 :         else if(prev->get_type() == Node::node_t::NODE_CATCH)
     561             :         {
     562           0 :             correct = true;
     563             : 
     564             :             // correct syntactically, however, the previous catch
     565             :             // must clearly be typed
     566           0 :             if(!prev->get_flag(Node::flag_t::NODE_CATCH_FLAG_TYPED))
     567             :             {
     568           0 :                 Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INVALID_TYPE, catch_node->get_position());
     569           0 :                 msg << "only the last 'catch' statement can have a parameter without a valid type.";
     570             :             }
     571           0 :         }
     572             :     }
     573           0 :     if(!correct)
     574             :     {
     575           0 :         Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_IMPROPER_STATEMENT, catch_node->get_position());
     576           0 :         msg << "a 'catch' statement needs to be preceded by a 'try' or another typed 'catch' statement.";
     577             :     }
     578             : 
     579           0 :     Node::pointer_t parameters_node(catch_node->get_child(0));
     580           0 :     parameters(parameters_node);
     581           0 :     if(parameters_node->get_children_size() > 0)
     582             :     {
     583           0 :         Node::pointer_t param(parameters_node->get_child(0));
     584           0 :         param->set_flag(Node::flag_t::NODE_PARAM_FLAG_CATCH, true);
     585             :     }
     586             : 
     587           0 :     directive_list(catch_node->get_child(1));
     588             : }
     589             : 
     590             : 
     591           0 : void Compiler::finally(Node::pointer_t& finally_node)
     592             : {
     593           0 :     if(finally_node->get_children_size() != 1)
     594             :     {
     595           0 :         return;
     596             :     }
     597             : 
     598             :     // we want to make sure that we are preceded by a try or a catch
     599           0 :     Node::pointer_t parent(finally_node->get_parent());
     600           0 :     bool correct(false);
     601           0 :     int32_t const offset(finally_node->get_offset());
     602           0 :     if(offset > 0)
     603             :     {
     604           0 :         Node::pointer_t prev(parent->get_child(offset - 1));
     605           0 :         if(prev->get_type() == Node::node_t::NODE_TRY
     606           0 :         || prev->get_type() == Node::node_t::NODE_CATCH)
     607             :         {
     608           0 :             correct = true;
     609           0 :         }
     610             :     }
     611           0 :     if(!correct)
     612             :     {
     613           0 :         Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_IMPROPER_STATEMENT, finally_node->get_position());
     614           0 :         msg << "a 'finally' statement needs to be preceded by a 'try' or 'catch' statement.";
     615             :     }
     616             : 
     617           0 :     directive_list(finally_node->get_child(0));
     618             : }
     619             : 
     620             : 
     621             : 
     622           0 : Node::pointer_t Compiler::return_directive(Node::pointer_t return_node)
     623             : {
     624             :     // 1. a return is only valid in a function (procedure)
     625             :     // 2. a return must return a value in a function
     626             :     // 3. a return can't return anything in a procedure
     627             :     // 4. you must assume that the function is returning
     628             :     //    Void when the function is a constructor and
     629             :     //    thus return can't have an expression in this case
     630             : 
     631             :     bool more;
     632           0 :     bool bad(false);
     633           0 :     Node::pointer_t function_node;
     634           0 :     Node::pointer_t parent(return_node);
     635           0 :     do
     636             :     {
     637           0 :         more = false;
     638           0 :         parent = parent->get_parent();
     639           0 :         if(!parent)
     640             :         {
     641           0 :             bad = true;
     642           0 :             break;
     643             :         }
     644           0 :         switch(parent->get_type())
     645             :         {
     646             :         case Node::node_t::NODE_FUNCTION:
     647           0 :             function_node = parent;
     648           0 :             break;
     649             : 
     650             :         case Node::node_t::NODE_CLASS:
     651             :         case Node::node_t::NODE_INTERFACE:
     652             :         case Node::node_t::NODE_PACKAGE:
     653             :         case Node::node_t::NODE_PROGRAM:
     654             :         case Node::node_t::NODE_ROOT:
     655           0 :             bad = true;
     656           0 :             break;
     657             : 
     658             :         default:
     659           0 :             more = true;
     660           0 :             break;
     661             : 
     662             :         }
     663             :     }
     664             :     while(more);
     665           0 :     if(bad)
     666             :     {
     667           0 :         Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_IMPROPER_STATEMENT, return_node->get_position());
     668           0 :         msg << "'return' can only be used inside a function.";
     669             :     }
     670             :     else
     671             :     {
     672           0 :         if(function_node->get_flag(Node::flag_t::NODE_FUNCTION_FLAG_NEVER))
     673             :         {
     674           0 :             Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_IMPROPER_STATEMENT, return_node->get_position());
     675           0 :             msg << "'return' was used inside '" << function_node->get_string() << "', a function Never returning.";
     676             :         }
     677             : 
     678           0 :         size_t const max_children(return_node->get_children_size());
     679           0 :         if(max_children == 1)
     680             :         {
     681           0 :             if(function_node->get_flag(Node::flag_t::NODE_FUNCTION_FLAG_VOID)
     682           0 :             || is_constructor(function_node))
     683             :             {
     684           0 :                 Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_IMPROPER_STATEMENT, return_node->get_position());
     685           0 :                 msg << "'return' was used with an expression inside '" << function_node->get_string() << "', a function returning Void.";
     686             :             }
     687           0 :             expression(return_node->get_child(0));
     688             :         }
     689             :         else
     690             :         {
     691             :             // NOTE:
     692             :             // This actually needs to be transformed to
     693             :             // returning 'undefined' in the execution
     694             :             // environment... maybe we will add this
     695             :             // here at some point.
     696           0 :             if(!function_node->get_flag(Node::flag_t::NODE_FUNCTION_FLAG_VOID)
     697           0 :             && !is_constructor(function_node))
     698             :             {
     699           0 :                 Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_IMPROPER_STATEMENT, return_node->get_position());
     700           0 :                 msg << "'return' was used without an expression inside '" << function_node->get_string() << "', a function which expected a value to be returned.";
     701             :             }
     702             :         }
     703             :     }
     704             : 
     705           0 :     return parent;
     706             : }
     707             : 
     708             : 
     709           0 : void Compiler::use_namespace(Node::pointer_t& use_namespace_node)
     710             : {
     711           0 :     if(use_namespace_node->get_children_size() != 1)
     712             :     {
     713           0 :         return;
     714             :     }
     715           0 :     NodeLock ln(use_namespace_node);
     716             : 
     717             :     // type/scope name defined in an expression
     718             :     // (needs to be resolved in an identifiers, members composed of
     719             :     // identifiers or a string representing a valid type name)
     720           0 :     Node::pointer_t qualifier(use_namespace_node->get_child(0));
     721           0 :     expression(qualifier);
     722             : 
     723             :     // TODO: I'm not too sure what the qualifier can end up being at this
     724             :     //       point, but if it is a whole tree of node, we do not know
     725             :     //       how to copy it... (because using qualifier directly instead
     726             :     //       of using q as defined below would completely break the
     727             :     //       existing namespace...)
     728           0 :     if(qualifier->get_type() != Node::node_t::NODE_STRING)
     729             :     {
     730           0 :         throw exception_internal_error("type qualifier is not just a string, we cannot duplicate it at this point");
     731             :     }
     732             : 
     733             :     // we create two nodes; one so we know we have a NAMESPACE instruction
     734             :     // and a child of that node which is the type itself; these are
     735             :     // deleted once we return from the directive_list() function and not
     736             :     // this function
     737           0 :     Node::pointer_t q(qualifier->create_replacement(qualifier->get_type()));
     738           0 :     q->set_string(qualifier->get_string());
     739           0 :     Node::pointer_t n(qualifier->create_replacement(Node::node_t::NODE_NAMESPACE));
     740           0 :     n->append_child(q);
     741           0 :     f_scope->append_child(n);
     742             : }
     743             : 
     744             : 
     745             : 
     746             : 
     747             : 
     748             : 
     749             : 
     750             : 
     751             : 
     752             : 
     753             : 
     754             : 
     755             : 
     756             : 
     757             : 
     758             : 
     759             : 
     760             : 
     761             : 
     762             : 
     763             : 
     764             : 
     765             : 
     766             : 
     767          63 : }
     768             : // namespace as2js
     769             : 
     770             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.10