LCOV - code coverage report
Current view: top level - lib - compiler_attributes.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 41 183 22.4 %
Date: 2014-11-22 Functions: 4 7 57.1 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* compiler_attributes.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/message.h"
      39             : 
      40             : 
      41             : namespace as2js
      42             : {
      43             : 
      44             : 
      45             : 
      46           0 : void Compiler::variable_to_attrs(Node::pointer_t node, Node::pointer_t var_node)
      47             : {
      48           0 :     if(var_node->get_type() != Node::node_t::NODE_SET)
      49             :     {
      50           0 :         Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INVALID_VARIABLE, var_node->get_position());
      51           0 :         msg << "an attribute variable has to be given a value.";
      52           0 :         return;
      53             :     }
      54             : 
      55           0 :     Node::pointer_t a(var_node->get_child(0));
      56           0 :     switch(a->get_type())
      57             :     {
      58             :     case Node::node_t::NODE_FALSE:
      59             :     case Node::node_t::NODE_IDENTIFIER:
      60             :     case Node::node_t::NODE_INLINE:
      61             :     case Node::node_t::NODE_PRIVATE:
      62             :     case Node::node_t::NODE_PROTECTED:
      63             :     case Node::node_t::NODE_PUBLIC:
      64             :     case Node::node_t::NODE_TRUE:
      65           0 :         node_to_attrs(node, a);
      66           0 :         return;
      67             : 
      68             :     default:
      69             :         // expect a full boolean expression in this case
      70           0 :         break;
      71             : 
      72             :     }
      73             : 
      74             :     // compute the expression
      75           0 :     expression(a);
      76           0 :     Optimizer::optimize(a);
      77             : 
      78           0 :     switch(a->get_type())
      79             :     {
      80             :     case Node::node_t::NODE_TRUE:
      81             :     case Node::node_t::NODE_FALSE:
      82           0 :         node_to_attrs(node, a);
      83           0 :         return;
      84             : 
      85             :     default:
      86           0 :         break;
      87             : 
      88             :     }
      89             : 
      90           0 :     Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_INVALID_EXPRESSION, var_node->get_position());
      91           0 :     msg << "an attribute which is an expression needs to result in a boolean value (true or false).";
      92             : }
      93             : 
      94             : 
      95           0 : void Compiler::identifier_to_attrs(Node::pointer_t node, Node::pointer_t a)
      96             : {
      97             :     // an identifier can't be an empty string
      98           0 :     String const identifier(a->get_string());
      99           0 :     switch(identifier[0])
     100             :     {
     101             :     case 'a':
     102           0 :         if(identifier == "array")
     103             :         {
     104           0 :             node->set_attribute(Node::attribute_t::NODE_ATTR_ARRAY, true);
     105           0 :             return;
     106             :         }
     107           0 :         if(identifier == "autobreak")
     108             :         {
     109           0 :             node->set_attribute(Node::attribute_t::NODE_ATTR_AUTOBREAK, true);
     110           0 :             return;
     111             :         }
     112           0 :         break;
     113             : 
     114             :     case 'c':
     115           0 :         if(identifier == "constructor")
     116             :         {
     117           0 :             node->set_attribute(Node::attribute_t::NODE_ATTR_CONSTRUCTOR, true);
     118           0 :             return;
     119             :         }
     120           0 :         break;
     121             : 
     122             :     case 'd':
     123           0 :         if(identifier == "dynamic")
     124             :         {
     125           0 :             node->set_attribute(Node::attribute_t::NODE_ATTR_DYNAMIC, true);
     126           0 :             return;
     127             :         }
     128           0 :         if(identifier == "deprecated")
     129             :         {
     130           0 :             node->set_attribute(Node::attribute_t::NODE_ATTR_DEPRECATED, true);
     131           0 :             return;
     132             :         }
     133           0 :         break;
     134             : 
     135             :     case 'e':
     136           0 :         if(identifier == "enumerable")
     137             :         {
     138           0 :             node->set_attribute(Node::attribute_t::NODE_ATTR_ENUMERABLE, true);
     139           0 :             return;
     140             :         }
     141           0 :         break;
     142             : 
     143             :     case 'f':
     144           0 :         if(identifier == "foreach")
     145             :         {
     146           0 :             node->set_attribute(Node::attribute_t::NODE_ATTR_FOREACH, true);
     147           0 :             return;
     148             :         }
     149           0 :         break;
     150             : 
     151             :     case 'i':
     152           0 :         if(identifier == "internal")
     153             :         {
     154           0 :             node->set_attribute(Node::attribute_t::NODE_ATTR_INTERNAL, true);
     155           0 :             return;
     156             :         }
     157           0 :         break;
     158             : 
     159             :     case 'n':
     160           0 :         if(identifier == "nobreak")
     161             :         {
     162           0 :             node->set_attribute(Node::attribute_t::NODE_ATTR_NOBREAK, true);
     163           0 :             return;
     164             :         }
     165           0 :         break;
     166             : 
     167             :     case 'u':
     168           0 :         if(identifier == "unsafe")
     169             :         {
     170           0 :             node->set_attribute(Node::attribute_t::NODE_ATTR_UNSAFE, true);
     171           0 :             return;
     172             :         }
     173           0 :         if(identifier == "unused")
     174             :         {
     175           0 :             node->set_attribute(Node::attribute_t::NODE_ATTR_UNUSED, true);
     176           0 :             return;
     177             :         }
     178           0 :         break;
     179             : 
     180             :     case 'v':
     181           0 :         if(identifier == "virtual")
     182             :         {
     183           0 :             node->set_attribute(Node::attribute_t::NODE_ATTR_VIRTUAL, true);
     184           0 :             return;
     185             :         }
     186           0 :         break;
     187             : 
     188             :     }
     189             : 
     190             :     // it could be a user defined variable list of attributes
     191           0 :     Node::pointer_t resolution;
     192           0 :     if(!resolve_name(node, a, resolution, Node::pointer_t(), SEARCH_FLAG_NO_PARSING))
     193             :     {
     194           0 :         Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_NOT_FOUND, a->get_position());
     195           0 :         msg << "cannot find a variable named '" << a->get_string() << "'.";
     196           0 :         return;
     197             :     }
     198           0 :     if(!resolution)
     199             :     {
     200             :         // TODO: do we expect an error here?
     201           0 :         return;
     202             :     }
     203           0 :     if(resolution->get_type() != Node::node_t::NODE_VARIABLE
     204           0 :     && resolution->get_type() != Node::node_t::NODE_VAR_ATTRIBUTES)
     205             :     {
     206           0 :         Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_DYNAMIC, a->get_position());
     207           0 :         msg << "a dynamic attribute name can only reference a variable and '" << a->get_string() << "' is not one.";
     208           0 :         return;
     209             :     }
     210             : 
     211             :     // it is a variable, go through the list and call ourselves recursively
     212             :     // with each identifiers; but make sure we do not loop forever
     213           0 :     if(resolution->get_flag(Node::flag_t::NODE_VARIABLE_FLAG_ATTRS))
     214             :     {
     215           0 :         Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_LOOPING_REFERENCE, a->get_position());
     216           0 :         msg << "the dynamic attribute variable '" << a->get_string() << "' is used circularly (it loops).";
     217           0 :         return;
     218             :     }
     219             : 
     220           0 :     resolution->set_flag(Node::flag_t::NODE_VARIABLE_FLAG_ATTRS, true); // to avoid infinite loop
     221           0 :     resolution->set_flag(Node::flag_t::NODE_VARIABLE_FLAG_ATTRIBUTES, true);
     222           0 :     NodeLock ln(resolution);
     223           0 :     size_t const max_children(resolution->get_children_size());
     224           0 :     for(size_t idx(0); idx < max_children; ++idx)
     225             :     {
     226           0 :         Node::pointer_t child(resolution->get_child(idx));
     227           0 :         variable_to_attrs(node, child);
     228           0 :     }
     229           0 :     resolution->set_flag(Node::flag_t::NODE_VARIABLE_FLAG_ATTRS, false);
     230             : }
     231             : 
     232             : 
     233           0 : void Compiler::node_to_attrs(Node::pointer_t node, Node::pointer_t a)
     234             : {
     235           0 :     switch(a->get_type())
     236             :     {
     237             :     case Node::node_t::NODE_ABSTRACT:
     238           0 :         node->set_attribute(Node::attribute_t::NODE_ATTR_ABSTRACT, true);
     239           0 :         break;
     240             : 
     241             :     case Node::node_t::NODE_FALSE:
     242           0 :         node->set_attribute(Node::attribute_t::NODE_ATTR_FALSE, true);
     243           0 :         break;
     244             : 
     245             :     case Node::node_t::NODE_FINAL:
     246           0 :         node->set_attribute(Node::attribute_t::NODE_ATTR_FINAL, true);
     247           0 :         break;
     248             : 
     249             :     case Node::node_t::NODE_IDENTIFIER:
     250           0 :         identifier_to_attrs(node, a);
     251           0 :         break;
     252             : 
     253             :     case Node::node_t::NODE_INLINE:
     254           0 :         node->set_attribute(Node::attribute_t::NODE_ATTR_INLINE, true);
     255           0 :         break;
     256             : 
     257             :     case Node::node_t::NODE_NATIVE: // Note: I called this one INTRINSIC before
     258           0 :         node->set_attribute(Node::attribute_t::NODE_ATTR_NATIVE, true);
     259           0 :         break;
     260             : 
     261             :     case Node::node_t::NODE_PRIVATE:
     262           0 :         node->set_attribute(Node::attribute_t::NODE_ATTR_PRIVATE, true);
     263           0 :         break;
     264             : 
     265             :     case Node::node_t::NODE_PROTECTED:
     266           0 :         node->set_attribute(Node::attribute_t::NODE_ATTR_PROTECTED, true);
     267           0 :         break;
     268             : 
     269             :     case Node::node_t::NODE_PUBLIC:
     270           0 :         node->set_attribute(Node::attribute_t::NODE_ATTR_PUBLIC, true);
     271           0 :         break;
     272             : 
     273             :     case Node::node_t::NODE_STATIC:
     274           0 :         node->set_attribute(Node::attribute_t::NODE_ATTR_STATIC, true);
     275           0 :         break;
     276             : 
     277             :     case Node::node_t::NODE_TRANSIENT:
     278           0 :         node->set_attribute(Node::attribute_t::NODE_ATTR_TRANSIENT, true);
     279           0 :         break;
     280             : 
     281             :     case Node::node_t::NODE_TRUE:
     282           0 :         node->set_attribute(Node::attribute_t::NODE_ATTR_TRUE, true);
     283           0 :         break;
     284             : 
     285             :     case Node::node_t::NODE_VOLATILE:
     286           0 :         node->set_attribute(Node::attribute_t::NODE_ATTR_VOLATILE, true);
     287           0 :         break;
     288             : 
     289             :     default:
     290             :         // TODO: this is a scope (user defined name)
     291             :         // ERROR: unknown attribute type
     292             :         // Note that will happen whenever someone references a
     293             :         // variable which is an expression which does not resolve
     294             :         // to a valid attribute and thus we need a user error here
     295           0 :         Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_NOT_SUPPORTED, a->get_position());
     296           0 :         msg << "unsupported attribute data type, dynamic expressions for attributes need to be resolved as constants.";
     297           0 :         break;
     298             : 
     299             :     }
     300           0 : }
     301             : 
     302             : 
     303       24648 : void Compiler::prepare_attributes(Node::pointer_t node)
     304             : {
     305             :     // done here?
     306       24648 :     if(node->get_attribute(Node::attribute_t::NODE_ATTR_DEFINED))
     307             :     {
     308       16470 :         return;
     309             :     }
     310             : 
     311             :     // mark ourselves as done even if errors occur
     312       16413 :     node->set_attribute(Node::attribute_t::NODE_ATTR_DEFINED, true);
     313             : 
     314       16413 :     if(node->get_type() == Node::node_t::NODE_PROGRAM)
     315             :     {
     316             :         // programs do not get any specific attributes
     317             :         // (optimization)
     318           0 :         return;
     319             :     }
     320             : 
     321       16413 :     Node::pointer_t attr(node->get_link(Node::link_t::LINK_ATTRIBUTES));
     322       16413 :     if(attr)
     323             :     {
     324           0 :         NodeLock ln(attr);
     325           0 :         size_t const max_attr(attr->get_children_size());
     326           0 :         for(size_t idx(0); idx < max_attr; ++idx)
     327             :         {
     328           0 :             node_to_attrs(node, attr->get_child(idx));
     329           0 :         }
     330             :     }
     331             : 
     332             :     // check whether intrinsic is already set
     333             :     // (in which case it is probably an error)
     334       16413 :     bool const has_direct_native(node->get_attribute(Node::attribute_t::NODE_ATTR_NATIVE));
     335             : 
     336             :     // Note: we already returned if it is equal
     337             :     //       to program; here it is just documentation
     338       32826 :     if(node->get_type() != Node::node_t::NODE_PACKAGE
     339       16413 :     && node->get_type() != Node::node_t::NODE_PROGRAM)
     340             :     {
     341       16413 :         Node::pointer_t parent(node->get_parent());
     342       16413 :         if(parent
     343       32826 :         && parent->get_type() != Node::node_t::NODE_PACKAGE
     344       32815 :         && parent->get_type() != Node::node_t::NODE_PROGRAM)
     345             :         {
     346             :             // recurse against all parents as required
     347        8210 :             prepare_attributes(parent);
     348             : 
     349             :             // child can redefine (ignore parent if any defined)
     350             :             // [TODO: should this be an error if conflicting?]
     351       16420 :             if(!node->get_attribute(Node::attribute_t::NODE_ATTR_PUBLIC)
     352        8210 :             && !node->get_attribute(Node::attribute_t::NODE_ATTR_PRIVATE)
     353       16420 :             && !node->get_attribute(Node::attribute_t::NODE_ATTR_PROTECTED))
     354             :             {
     355        8210 :                 node->set_attribute(Node::attribute_t::NODE_ATTR_PUBLIC,    parent->get_attribute(Node::attribute_t::NODE_ATTR_PUBLIC));
     356        8210 :                 node->set_attribute(Node::attribute_t::NODE_ATTR_PRIVATE,   parent->get_attribute(Node::attribute_t::NODE_ATTR_PRIVATE));
     357        8210 :                 node->set_attribute(Node::attribute_t::NODE_ATTR_PROTECTED, parent->get_attribute(Node::attribute_t::NODE_ATTR_PROTECTED));
     358             :             }
     359             : 
     360             :             // child can redefine (ignore parent if defined)
     361       16420 :             if(!node->get_attribute(Node::attribute_t::NODE_ATTR_STATIC)
     362        8210 :             && !node->get_attribute(Node::attribute_t::NODE_ATTR_ABSTRACT)
     363       16420 :             && !node->get_attribute(Node::attribute_t::NODE_ATTR_VIRTUAL))
     364             :             {
     365        8210 :                 node->set_attribute(Node::attribute_t::NODE_ATTR_STATIC,   parent->get_attribute(Node::attribute_t::NODE_ATTR_STATIC));
     366        8210 :                 node->set_attribute(Node::attribute_t::NODE_ATTR_ABSTRACT, parent->get_attribute(Node::attribute_t::NODE_ATTR_ABSTRACT));
     367        8210 :                 node->set_attribute(Node::attribute_t::NODE_ATTR_VIRTUAL,  parent->get_attribute(Node::attribute_t::NODE_ATTR_VIRTUAL));
     368             :             }
     369             : 
     370             :             // inherit
     371        8210 :             node->set_attribute(Node::attribute_t::NODE_ATTR_NATIVE,     parent->get_attribute(Node::attribute_t::NODE_ATTR_NATIVE));
     372        8210 :             node->set_attribute(Node::attribute_t::NODE_ATTR_ENUMERABLE, parent->get_attribute(Node::attribute_t::NODE_ATTR_ENUMERABLE));
     373             : 
     374             :             // false has priority
     375        8210 :             if(parent->get_attribute(Node::attribute_t::NODE_ATTR_FALSE))
     376             :             {
     377           0 :                 node->set_attribute(Node::attribute_t::NODE_ATTR_TRUE, false);
     378           0 :                 node->set_attribute(Node::attribute_t::NODE_ATTR_FALSE, true);
     379             :             }
     380             : 
     381        8210 :             if(parent->get_type() != Node::node_t::NODE_CLASS)
     382             :             {
     383        8210 :                 node->set_attribute(Node::attribute_t::NODE_ATTR_DYNAMIC, parent->get_attribute(Node::attribute_t::NODE_ATTR_DYNAMIC));
     384        8210 :                 node->set_attribute(Node::attribute_t::NODE_ATTR_FINAL,   parent->get_attribute(Node::attribute_t::NODE_ATTR_FINAL));
     385             :             }
     386       16413 :         }
     387             :     }
     388             : 
     389             :     // a function which has a body cannot be intrinsic
     390       32826 :     if(node->get_attribute(Node::attribute_t::NODE_ATTR_NATIVE)
     391       16413 :     && node->get_type() == Node::node_t::NODE_FUNCTION)
     392             :     {
     393           0 :         NodeLock ln(node);
     394           0 :         size_t const max(node->get_children_size());
     395           0 :         for(size_t idx(0); idx < max; ++idx)
     396             :         {
     397           0 :             Node::pointer_t list(node->get_child(idx));
     398           0 :             if(list->get_type() == Node::node_t::NODE_DIRECTIVE_LIST)
     399             :             {
     400             :                 // it is an error if the user defined
     401             :                 // it directly on the function; it is
     402             :                 // fine if it comes from the parent
     403           0 :                 if(has_direct_native)
     404             :                 {
     405           0 :                     Message msg(message_level_t::MESSAGE_LEVEL_ERROR, err_code_t::AS_ERR_NATIVE, node->get_position());
     406           0 :                     msg << "'native' is not permitted on a function with a body.";
     407             :                 }
     408           0 :                 node->set_attribute(Node::attribute_t::NODE_ATTR_NATIVE, false);
     409           0 :                 break;
     410             :             }
     411           0 :         }
     412       16413 :     }
     413             : }
     414             : 
     415             : 
     416       16438 : bool Compiler::get_attribute(Node::pointer_t node, Node::attribute_t const a)
     417             : {
     418       16438 :     prepare_attributes(node);
     419       16438 :     return node->get_attribute(a);
     420             : }
     421             : 
     422             : 
     423             : 
     424             : 
     425             : 
     426             : 
     427             : 
     428             : 
     429          63 : }
     430             : // namespace as2js
     431             : 
     432             : // vim: ts=4 sw=4 et

Generated by: LCOV version 1.10