LCOV - code coverage report
Current view: top level - asar - asar_math.cpp (source / functions) Coverage Total Hit
Test: asar.info Lines: 91.1 % 461 420
Test Date: 2024-01-15 16:32:53 Functions: 73.9 % 92 68
Branches: 60.6 % 432 262

             Branch data     Line data    Source code
       1                 :             : //Don't try using this in your own project, it's got a lot of Asar-specific tweaks. Use mathlib.cpp instead.
       2                 :             : #include "platform/file-helpers.h"
       3                 :             : #include "std-includes.h"
       4                 :             : #include "autoarray.h"
       5                 :             : #include "assocarr.h"
       6                 :             : #include "libstr.h"
       7                 :             : #include "libsmw.h"
       8                 :             : #include "asar.h"
       9                 :             : #include "virtualfile.h"
      10                 :             : #include "assembleblock.h"
      11                 :             : #include "macro.h"
      12                 :             : #include "asar_math.h"
      13                 :             : #include "warnings.h"
      14                 :             : #include <math.h>
      15                 :             : #include <functional>
      16                 :             : #include <algorithm>
      17                 :             : 
      18                 :             : bool math_pri=true;
      19                 :             : bool math_round=false;
      20                 :             : extern bool suppress_all_warnings;
      21                 :             : 
      22                 :             : static const char * str;
      23                 :             : //save before calling eval if needed after
      24                 :             : static const char * current_user_function_name;
      25                 :             : 
      26                 :             : static double getnumcore();
      27                 :             : static double getnum();
      28                 :             : static double eval(int depth);
      29                 :             : 
      30                 :             : //label (bool foundLabel) (bool forwardLabel)
      31                 :             : //userfunction
      32                 :             : 
      33                 :             : bool foundlabel;
      34                 :             : bool foundlabel_static;
      35                 :             : bool forwardlabel;
      36                 :             : 
      37                 :             : struct cachedfile {
      38                 :             :         string filename;
      39                 :             :         virtual_file_handle filehandle;
      40                 :             :         size_t filesize;
      41                 :             :         bool used;
      42                 :             : };
      43                 :             : 
      44                 :             : #define numcachedfiles 16
      45                 :             : 
      46                 :             : static cachedfile cachedfiles[numcachedfiles];
      47                 :             : static int cachedfileindex = 0;
      48                 :             : 
      49                 :             : // Opens a file, trying to open it from cache first
      50                 :             : 
      51                 :          42 : static cachedfile * opencachedfile(string fname, bool should_error)
      52                 :             : {
      53                 :             :         cachedfile * cachedfilehandle = nullptr;
      54                 :             : 
      55                 :             :         // RPG Hacker: Only using a combined path here because that should
      56                 :             :         // hopefully result in a unique string for every file, whereas
      57                 :             :         // fname could be a relative path, which isn't guaranteed to be unique.
      58                 :             :         // Note that this does not affect how we open the file - this is
      59                 :             :         // handled by the filesystem and uses our include paths etc.
      60                 :          42 :         string combinedname = filesystem->create_absolute_path(dir(thisfilename), fname);
      61                 :             : 
      62         [ +  + ]:         280 :         for (int i = 0; i < numcachedfiles; i++)
      63                 :             :         {
      64   [ +  +  +  + ]:         266 :                 if (cachedfiles[i].used && cachedfiles[i].filename == combinedname)
      65                 :             :                 {
      66                 :          28 :                         cachedfilehandle = &cachedfiles[i];
      67                 :             :                         break;
      68                 :             :                 }
      69                 :             :         }
      70                 :             : 
      71                 :             :         if (cachedfilehandle == nullptr)
      72                 :             :         {
      73                 :             : 
      74         [ -  + ]:          14 :                 if (cachedfiles[cachedfileindex].used)
      75                 :             :                 {
      76                 :           0 :                         filesystem->close_file(cachedfiles[cachedfileindex].filehandle);
      77                 :           0 :                         cachedfiles[cachedfileindex].filehandle = INVALID_VIRTUAL_FILE_HANDLE;
      78                 :           0 :                         cachedfiles[cachedfileindex].used = false;
      79                 :             :                 }
      80                 :             : 
      81                 :          14 :                 cachedfilehandle = &cachedfiles[cachedfileindex];
      82                 :             :         }
      83                 :             : 
      84                 :             :         if (cachedfilehandle != nullptr)
      85                 :             :         {
      86         [ +  + ]:          42 :                 if (!cachedfilehandle->used)
      87                 :             :                 {
      88                 :          14 :                         cachedfilehandle->filehandle = filesystem->open_file(fname, thisfilename);
      89         [ +  + ]:          14 :                         if (cachedfilehandle->filehandle != INVALID_VIRTUAL_FILE_HANDLE)
      90                 :             :                         {
      91                 :           4 :                                 cachedfilehandle->used = true;
      92                 :           4 :                                 cachedfilehandle->filename = combinedname;
      93                 :           4 :                                 cachedfilehandle->filesize = filesystem->get_file_size(cachedfilehandle->filehandle);
      94                 :           4 :                                 cachedfileindex++;
      95                 :             :                                 // randomdude999: when we run out of cached files, just start overwriting ones from the start
      96         [ -  + ]:           4 :                                 if (cachedfileindex >= numcachedfiles) cachedfileindex = 0;
      97                 :             :                         }
      98                 :             :                 }
      99                 :             :         }
     100                 :             : 
     101   [ +  +  -  + ]:          42 :         if ((cachedfilehandle == nullptr || cachedfilehandle->filehandle == INVALID_VIRTUAL_FILE_HANDLE) && should_error)
     102                 :             :         {
     103                 :           0 :                 asar_throw_error(2, error_type_block, vfile_error_to_error_id(asar_get_last_io_error()), fname.data());
     104                 :             :         }
     105                 :             : 
     106                 :          42 :         return cachedfilehandle;
     107                 :          42 : }
     108                 :             : 
     109                 :             : 
     110                 :         188 : void closecachedfiles()
     111                 :             : {
     112         [ +  + ]:        3196 :         for (int i = 0; i < numcachedfiles; i++)
     113                 :             :         {
     114         [ +  + ]:        3008 :                 if (cachedfiles[i].used)
     115                 :             :                 {
     116         [ +  - ]:           4 :                         if (cachedfiles[i].filehandle != INVALID_VIRTUAL_FILE_HANDLE)
     117                 :             :                         {
     118                 :           4 :                                 filesystem->close_file(cachedfiles[i].filehandle);
     119                 :           4 :                                 cachedfiles[i].filehandle = INVALID_VIRTUAL_FILE_HANDLE;
     120                 :             :                         }
     121                 :             : 
     122                 :           4 :                         cachedfiles[i].used = false;
     123                 :             :                 }
     124                 :             :         }
     125                 :             : 
     126                 :         188 :         cachedfileindex = 0;
     127                 :         188 : }
     128                 :             : 
     129                 :             : 
     130                 :           8 : static int struct_size(const char *name)
     131                 :             : {
     132   [ +  -  -  + ]:           8 :        if(pass && !structs.exists(name)) asar_throw_error(2, error_type_block, error_id_struct_not_found, name);
     133         [ +  - ]:           8 :        else if(!structs.exists(name)) return 0;
     134                 :           8 :        return structs.find(name).struct_size;
     135                 :             : }
     136                 :             : 
     137                 :          38 : static int object_size(const char *name)
     138                 :             : {
     139   [ +  +  -  + ]:          38 :        if(pass && !structs.exists(name)) asar_throw_error(2, error_type_block, error_id_struct_not_found, name);
     140         [ +  - ]:          38 :        else if(!structs.exists(name)) return 0;
     141                 :          38 :        return structs.find(name).object_size;
     142                 :             : }
     143                 :             : 
     144                 :          10 : static int data_size(const char *name)
     145                 :             : {
     146                 :             :         unsigned int label;
     147                 :          10 :         unsigned int next_label = 0xFFFFFF;
     148         [ -  + ]:          10 :         if(!labels.exists(name)) asar_throw_error(2, error_type_block, error_id_label_not_found, name);
     149                 :          10 :         foundlabel = true;
     150                 :          10 :         snes_label label_data = labels.find(name);
     151                 :          10 :         foundlabel_static &= label_data.is_static;
     152                 :          10 :         label = label_data.pos & 0xFFFFFF;
     153                 :          10 :         labels.each([&next_label, label](const char *key, snes_label current_label){
     154                 :          30 :                 current_label.pos &= 0xFFFFFF;
     155   [ +  +  +  + ]:          30 :                 if(label < current_label.pos && current_label.pos < next_label){
     156                 :           6 :                         next_label = current_label.pos;
     157                 :             :                 }
     158                 :          30 :         });
     159         [ +  + ]:          10 :         if(next_label == 0xFFFFFF) asar_throw_warning(2, warning_id_datasize_last_label, name);
     160         [ +  + ]:          10 :         if(next_label-label > 0xFFFF) asar_throw_warning(2, warning_id_datasize_exceeds_size, name);
     161                 :          10 :         return next_label-label;
     162                 :             : }
     163                 :             : 
     164                 :             : 
     165                 :         148 : string get_string_argument()
     166                 :             : {
     167         [ -  + ]:         148 :         while (*str==' ') str++;
     168         [ +  - ]:         148 :         if (*str=='"')
     169                 :             :         {
     170                 :             :                 const char * strpos = str;
     171                 :         148 :                 str++;
     172   [ +  +  +  - ]:        2042 :                 while (*str!='"' && *str!='\0' && *str!='\n') str++;
     173         [ +  - ]:         148 :                 if (*str == '"')
     174                 :             :                 {
     175                 :         148 :                         string tempname(strpos, (int)(str - strpos + 1));
     176                 :         148 :                         str++;
     177         [ -  + ]:         148 :                         while (*str==' ') str++;        //eat space
     178                 :         148 :                         return string(safedequote(tempname.temp_raw()));
     179                 :         148 :                 }
     180                 :             :                 // RPG Hacker: AFAIK, this is never actually triggered, since unmatched quotes are already detected earlier,
     181                 :             :                 // but since it does no harm here, I'll keep it in, just to be safe
     182                 :           0 :                 else asar_throw_error(2, error_type_block, error_id_string_literal_not_terminated);
     183                 :             :         }//make this error a better one later
     184                 :             :         
     185                 :           0 :         asar_throw_error(2, error_type_block, error_id_string_literal_not_terminated);
     186                 :           0 :         return ""; //never actually called, but I don't feel like figuring out __attribute__ ((noreturn)) on MSVC
     187                 :             : }
     188                 :             : 
     189                 :             : //only returns alphanumeric (and _) starting with alpha or _
     190                 :         128 : string get_symbol_argument()
     191                 :             : {
     192         [ -  + ]:         128 :         while (*str==' ') str++;        //is this proper?  Dunno yet.
     193                 :             :         const char * strpos = str;
     194                 :             :         // hack: for backwards compat, allow strings as symbols
     195         [ +  + ]:         128 :         if(*str=='"') {
     196                 :           4 :                 asar_throw_warning(2, warning_id_feature_deprecated, "quoted symbolic arguments", "Remove the quotations");
     197                 :           4 :                 string arg = get_string_argument();
     198                 :             :                 int i = 0;
     199   [ -  +  -  - ]:           4 :                 if(is_alpha(arg[i]) || arg[i] == '_') i++;
     200   [ +  +  +  -  :          28 :                 while(is_alnum(arg[i]) || arg[i] == '_' || arg[i] == '.') i++;
                   +  + ]
     201   [ -  +  -  - ]:           4 :                 if(arg[i] != '\0') asar_throw_error(2, error_type_block, error_id_invalid_label_name);
     202                 :           4 :                 return arg;
     203                 :           4 :         }
     204   [ +  +  -  + ]:         124 :         if(is_alpha(*str) || *str == '_') str++;
     205   [ +  +  +  +  :         588 :         while (is_alnum(*str) || *str == '_' || *str == '.') str++;
                   +  + ]
     206         [ -  + ]:         124 :         if(strpos == str){
     207                 :             :                 //error nothing was read, this is a placeholder error
     208                 :           0 :                 asar_throw_error(2, error_type_block, error_id_string_literal_not_terminated);
     209                 :             :         }
     210                 :             :         
     211                 :         124 :         string symbol = string(strpos, (int)(str - strpos));
     212         [ -  + ]:         124 :         while (*str==' ') str++;        //eat spaces
     213                 :         124 :         return symbol;
     214                 :         124 : }
     215                 :             : 
     216                 :         284 : double get_double_argument()
     217                 :             : {
     218         [ -  + ]:         284 :         while (*str==' ') str++;
     219                 :         284 :         double result = eval(0);
     220         [ -  + ]:         284 :         while (*str==' ') str++; //eat spaces
     221                 :         284 :         return result;
     222                 :             : }
     223                 :             : 
     224                 :             : //will eat the comma
     225                 :          49 : bool has_next_parameter()
     226                 :             : {
     227         [ +  + ]:          49 :         if (*str==',')
     228                 :             :         {
     229                 :          15 :                 str++;
     230                 :          15 :                 return true;
     231                 :             :         }
     232                 :             :         return false;
     233                 :             : }
     234                 :             : 
     235                 :         117 : void require_next_parameter()
     236                 :             : {
     237         [ +  - ]:         117 :         if (*str==',')
     238                 :             :         {
     239                 :         117 :                 str++;
     240                 :         117 :                 return;
     241                 :             :         }
     242                 :           0 :         asar_throw_error(2, error_type_block, error_id_require_parameter);
     243                 :             : }
     244                 :             : 
     245                 :           2 : template <typename F> double asar_unary_wrapper()
     246                 :             : {
     247                 :           2 :         return F()(get_double_argument());
     248                 :             : }
     249                 :             : 
     250                 :           2 : template <double (*F)(double)> double asar_unary_wrapper()
     251                 :             : {
     252                 :           2 :         return F(get_double_argument());
     253                 :             : }
     254                 :             : 
     255                 :             : //possibly restrict type T in the future....
     256                 :             : //first a case for functors
     257                 :          22 : template <typename F> double asar_binary_wrapper()
     258                 :             : {
     259                 :          22 :         double first = get_double_argument();
     260                 :          22 :         require_next_parameter();
     261                 :          22 :         return F()(first, get_double_argument());
     262                 :             : }
     263                 :             : //this could be DRY with if constexpr....oh well
     264                 :          13 : template <double (*F)(double, double)> double asar_binary_wrapper()
     265                 :             : {
     266                 :          13 :         double first = get_double_argument();
     267                 :          13 :         require_next_parameter();
     268                 :          13 :         return F(first, get_double_argument());
     269                 :             : }
     270                 :             : 
     271                 :           0 : double asar_bank(double a)
     272                 :             : {
     273                 :           2 :         return (int)a >> 16;
     274                 :             : }
     275                 :             : 
     276                 :             : 
     277                 :           0 : double asar_logical_nand(double a, double b)
     278                 :             : {
     279                 :           3 :         return !(a && b);
     280                 :             : }
     281                 :             : 
     282                 :             : 
     283                 :           0 : double asar_logical_nor(double a, double b)
     284                 :             : {
     285                 :           3 :         return !(a || b);
     286                 :             : }
     287                 :             : 
     288                 :             : 
     289                 :           0 : double asar_logical_xor(double a, double b)
     290                 :             : {
     291                 :           3 :         return !!a ^ !!b;
     292                 :             : }
     293                 :             : 
     294                 :           0 : double asar_max(double a, double b)
     295                 :             : {
     296   [ +  +  +  +  :           5 :         return a > b ? a : b;
                   -  - ]
     297                 :             : }
     298                 :             : 
     299                 :           0 : double asar_min(double a, double b)
     300                 :             : {
     301   [ +  +  +  +  :           5 :         return a < b ? a : b;
                   -  - ]
     302                 :             : }
     303                 :             : 
     304                 :           3 : double asar_clamp()
     305                 :             : {
     306                 :           3 :         double value = get_double_argument();
     307                 :           3 :         require_next_parameter();
     308                 :           3 :         double low = get_double_argument();
     309                 :           3 :         require_next_parameter();
     310                 :           3 :         double high = get_double_argument();
     311                 :             :         
     312                 :           3 :         return asar_max(low, asar_min(high, value));
     313                 :             : }
     314                 :             : 
     315                 :           2 : double asar_safediv()
     316                 :             : {
     317                 :           2 :         double dividend = get_double_argument();
     318                 :           2 :         require_next_parameter();
     319                 :           2 :         double divisor = get_double_argument();
     320                 :           2 :         require_next_parameter();
     321                 :           2 :         double default_value = get_double_argument();
     322                 :             :         
     323         [ +  + ]:           2 :         return divisor == 0.0 ? default_value : dividend / divisor;
     324                 :             : }
     325                 :             : 
     326                 :          11 : double asar_select()
     327                 :             : {
     328                 :          11 :         double selector = get_double_argument();
     329                 :          11 :         require_next_parameter();
     330                 :          11 :         double a = get_double_argument();
     331                 :          11 :         require_next_parameter();
     332                 :          11 :         double b = get_double_argument();
     333                 :             :         
     334         [ +  + ]:          11 :         return selector == 0.0 ? b : a;
     335                 :             : }
     336                 :             : 
     337                 :          57 : double asar_snestopc_wrapper()
     338                 :             : {
     339                 :          57 :         return snestopc(get_double_argument());
     340                 :             : }
     341                 :             : 
     342                 :          41 : double asar_pctosnes_wrapper()
     343                 :             : {
     344                 :          41 :         return pctosnes(get_double_argument());
     345                 :             : }
     346                 :             : 
     347                 :           6 : double asar_realbase_wrapper()
     348                 :             : {
     349                 :             :         //need a better way to do this to make sure it is useful...
     350                 :             :         //foundlabel=true;  //Going to consider this an implicit label because we don't really have a better system
     351                 :           6 :         return realsnespos;
     352                 :             : }
     353                 :             : 
     354                 :           9 : template <int count> double asar_read()
     355                 :             : {
     356                 :           9 :         int target = get_double_argument();
     357                 :           9 :         int addr=snestopc_pick(target);
     358         [ -  + ]:           9 :         if(has_next_parameter())
     359                 :             :         {
     360                 :           0 :                 double default_value = get_double_argument();
     361         [ #  # ]:           0 :                 if (addr<0) return default_value;
     362         [ #  # ]:           0 :                 else if (addr+count>romlen_r) return default_value;          
     363                 :             :         }
     364                 :             :         else
     365                 :             :         {
     366   [ -  +  -  - ]:           9 :                 if (addr<0) asar_throw_error(2, error_type_block, error_id_snes_address_doesnt_map_to_rom, (hex6((unsigned int)target) + " in read function").data());
     367   [ +  +  -  + ]:          11 :                 else if (addr+count>romlen_r) asar_throw_error(2, error_type_block, error_id_snes_address_out_of_bounds, (hex6(target) + " in read function").data());
     368                 :             :         }
     369                 :             :         
     370                 :             :         unsigned int value = 0;
     371         [ +  + ]:          28 :         for(int i = 0; i < count; i++)
     372                 :             :         {
     373                 :          20 :                 value |= romdata_r[addr+i] << (8 * i);
     374                 :             :         }
     375                 :           8 :         return value;
     376                 :             : }
     377                 :             : 
     378                 :          12 : template <int count> double asar_canread()
     379                 :             : {
     380                 :             :         int length = count;
     381                 :             :         if(!length)
     382                 :             :         {
     383                 :           0 :                 length = get_double_argument();
     384                 :             :         }
     385                 :          12 :         int addr=snestopc_pick(get_double_argument());
     386   [ +  -  +  + ]:          12 :         if (addr<0 || addr+length-1>=romlen_r) return 0;
     387                 :           6 :         else return 1;
     388                 :             : }
     389                 :             : 
     390                 :          19 : template <size_t count> double asar_readfile()
     391                 :             : {
     392                 :             :         static_assert(count && count <= 4, "invalid count"); //1-4 inclusive
     393                 :             :         
     394                 :          19 :         string name = get_string_argument();
     395                 :          19 :         require_next_parameter();
     396                 :          19 :         size_t offset = get_double_argument();
     397                 :          19 :         bool should_error = !has_next_parameter();
     398                 :          19 :         cachedfile * fhandle = opencachedfile(name, should_error);
     399         [ +  + ]:          19 :         if(!should_error)
     400                 :             :         {
     401                 :           9 :                 double default_value = get_double_argument();
     402   [ +  -  +  + ]:           9 :                 if (fhandle == nullptr || fhandle->filehandle == INVALID_VIRTUAL_FILE_HANDLE) return default_value;
     403         [ +  + ]:           7 :                 if (offset < 0 || offset + count > fhandle->filesize) return default_value;
     404                 :             :         }
     405                 :             :         else
     406                 :             :         {               
     407   [ +  -  -  +  :          10 :                 if (fhandle == nullptr || fhandle->filehandle == INVALID_VIRTUAL_FILE_HANDLE) asar_throw_error(2, error_type_block, vfile_error_to_error_id(asar_get_last_io_error()), name.data());
          -  -  -  -  -  
                      - ]
     408   [ -  +  -  - ]:          10 :                 if (offset < 0 || offset + count > fhandle->filesize) asar_throw_error(2, error_type_block, error_id_file_offset_out_of_bounds, dec(offset).data(), name.data());
     409                 :             :         }
     410                 :             :         
     411                 :          14 :         unsigned char data[4] = { 0, 0, 0, 0 };
     412                 :          14 :         filesystem->read_file(fhandle->filehandle, data, offset, count);
     413                 :             :         
     414                 :             :         unsigned int value = 0;
     415         [ +  + ]:          35 :         for(size_t i = 0; i < count; i++)
     416                 :             :         {
     417                 :          21 :                 value |= data[i] << (8 * i);
     418                 :             :         }
     419                 :             :         
     420                 :          14 :         return value;
     421                 :          19 : }
     422                 :             : 
     423                 :           9 : template <size_t count> double asar_canreadfile()
     424                 :             : {
     425                 :           9 :         string name = get_string_argument();
     426                 :           9 :         require_next_parameter();
     427                 :           9 :         size_t offset = get_double_argument();
     428                 :             :         size_t length = count;
     429                 :             :         if(!count)
     430                 :             :         {
     431                 :           2 :                 require_next_parameter();
     432                 :           2 :                 length = get_double_argument();
     433                 :             :         }
     434                 :           9 :         cachedfile * fhandle = opencachedfile(name, false);
     435   [ +  -  +  + ]:           9 :         if (fhandle == nullptr || fhandle->filehandle == INVALID_VIRTUAL_FILE_HANDLE) return 0;
     436         [ +  + ]:           7 :         if (offset < 0 || offset + length > fhandle->filesize) return 0;
     437                 :             :         return 1;
     438                 :           9 : }
     439                 :             : 
     440                 :             : // returns 0 if the file is OK, 1 if the file doesn't exist, 2 if it couldn't be opened for some other reason
     441                 :          12 : static double asar_filestatus()
     442                 :             : {
     443                 :          12 :         cachedfile * fhandle = opencachedfile(get_string_argument(), false);
     444   [ +  -  +  + ]:          12 :         if (fhandle == nullptr || fhandle->filehandle == INVALID_VIRTUAL_FILE_HANDLE)
     445                 :             :         {
     446         [ -  + ]:           6 :                 if (filesystem->get_last_error() == vfe_doesnt_exist)
     447                 :             :                 {
     448                 :             :                         return 1;
     449                 :             :                 }
     450                 :             :                 else
     451                 :             :                 {
     452                 :           0 :                         return 2;
     453                 :             :                 }
     454                 :             :         }
     455                 :             :         return 0;
     456                 :             : }
     457                 :             : 
     458                 :             : // Returns the size of the specified file.
     459                 :           2 : static double asar_filesize()
     460                 :             : {
     461                 :           2 :         string name = get_string_argument();
     462                 :           2 :         cachedfile * fhandle = opencachedfile(name, false);
     463   [ +  -  -  +  :           2 :         if (fhandle == nullptr || fhandle->filehandle == INVALID_VIRTUAL_FILE_HANDLE) asar_throw_error(2, error_type_block, vfile_error_to_error_id(asar_get_last_io_error()), name.data());
          -  -  -  -  -  
                      - ]
     464                 :           2 :         return (double)fhandle->filesize;
     465                 :           2 : }
     466                 :             : 
     467                 :             : // Checks whether the specified define is defined.
     468                 :          62 : static double asar_isdefined()
     469                 :             : {
     470                 :          62 :         return defines.exists(get_string_argument());
     471                 :             : }
     472                 :             : 
     473                 :             : // RPG Hacker: What exactly makes this function overly complicated, you ask?
     474                 :             : // Well, it converts a double to a string and then back to a double.
     475                 :             : // It was the quickest reliable solution I could find, though, so there's that.
     476                 :           2 : static double asar_round()
     477                 :             : {
     478                 :           2 :         double number = get_double_argument();
     479                 :           2 :         require_next_parameter();
     480                 :             : 
     481                 :             :         // Hue hue hue... ass!
     482                 :             :         // OK, sorry, I apologize.
     483                 :           2 :         string asstring = ftostrvar(number, get_double_argument());
     484                 :             : 
     485                 :             :         // Some hacky shenanigans with variables going on here
     486                 :           2 :         const char * strbackup = str;
     487                 :           2 :         str = asstring;
     488                 :           2 :         double asdouble = (double)getnum();
     489                 :           2 :         str = strbackup;
     490                 :             : 
     491                 :           2 :         return asdouble;
     492                 :           2 : }
     493                 :             : 
     494                 :         110 : static double asar_structsize_wrapper()
     495                 :             : {
     496                 :         110 :         string symbol = get_symbol_argument();
     497         [ +  + ]:         110 :         if(symbol == "..."){
     498   [ +  +  -  + ]:         102 :                 if(!inmacro) asar_throw_error(2, error_type_block, error_id_vararg_sizeof_nomacro);
     499   [ +  +  -  + ]:         101 :                 if(numvarargs == -1) asar_throw_error(2, error_type_block, error_id_macro_not_varadic);
     500                 :         100 :                 return numvarargs;
     501                 :             :         }
     502                 :           8 :         return (double)struct_size(symbol);
     503                 :         110 : }
     504                 :             : 
     505                 :           8 : static double asar_objectsize_wrapper()
     506                 :             : {
     507                 :           8 :         return (double)object_size(get_symbol_argument());
     508                 :             : }
     509                 :             : 
     510                 :          10 : static double asar_datasize_wrapper()
     511                 :             : {
     512                 :          10 :         return (double)data_size(get_symbol_argument());
     513                 :             : }
     514                 :             : 
     515                 :          12 : static double asar_stringsequal()
     516                 :             : {
     517                 :          12 :         string string1 = get_string_argument();
     518                 :          12 :         require_next_parameter();
     519   [ +  -  +  + ]:          30 :         return (strcmp(string1, get_string_argument()) == 0 ? 1.0 : 0.0);
     520                 :          12 : }
     521                 :             : 
     522                 :           6 : static double asar_stringsequalnocase()
     523                 :             : {
     524                 :           6 :         string string1 = get_string_argument();
     525                 :           6 :         require_next_parameter();
     526   [ +  -  -  + ]:          12 :         return (stricmp(string1, get_string_argument()) == 0 ? 1.0 : 0.0);
     527                 :           6 : }
     528                 :             : 
     529                 :          21 : string copy_arg()
     530                 :             : {
     531         [ +  + ]:          21 :         if(*str == '"')
     532                 :             :         {
     533                 :           4 :                 string t = "\"";
     534                 :           8 :                 return (t += get_string_argument() + "\"");
     535                 :           4 :         }
     536                 :             :         
     537                 :          17 :         string result;
     538                 :             :         bool is_symbolic = true;
     539                 :             :         int parlevel=0;
     540                 :             :         int i = 0;
     541   [ -  +  +  +  :          34 :         while(parlevel > 0 || (str[i] != ',' && str[i] != ')'))
                   +  + ]
     542                 :             :         {
     543                 :          17 :                 is_symbolic &= is_ualnum(str[i]);
     544         [ -  + ]:          17 :                 if(str[i] == '(') parlevel++;
     545         [ -  + ]:          17 :                 else if(str[i] == ')') parlevel--;
     546                 :          17 :                 i++;
     547                 :             :         }
     548                 :          17 :         result += string(str, i);
     549                 :          17 :         str += i;
     550                 :             :         
     551         [ -  + ]:          17 :         if(!is_symbolic)
     552                 :             :         {
     553                 :             :                 const char *oldstr=str;
     554                 :           0 :                 str = (const char *)result;
     555                 :           0 :                 result = ftostr(eval(0));
     556                 :           0 :                 str = oldstr;
     557                 :             :         }
     558                 :          17 :         return result;
     559                 :          17 : }
     560                 :             : 
     561                 :             : assocarr<double (*)()> builtin_functions =
     562                 :             : {
     563                 :             :         {"sqrt", asar_unary_wrapper<sqrt>},
     564                 :             :         {"sin", asar_unary_wrapper<sin>},
     565                 :             :         {"cos", asar_unary_wrapper<cos>},
     566                 :             :         {"tan", asar_unary_wrapper<tan>},
     567                 :             :         {"asin", asar_unary_wrapper<asin>},
     568                 :             :         {"acos", asar_unary_wrapper<acos>},
     569                 :             :         {"atan", asar_unary_wrapper<atan>},
     570                 :             :         {"arcsin", asar_unary_wrapper<asin>},
     571                 :             :         {"arccos", asar_unary_wrapper<acos>},
     572                 :             :         {"arctan", asar_unary_wrapper<atan>},
     573                 :             :         {"log", asar_unary_wrapper<log>},
     574                 :             :         {"log10", asar_unary_wrapper<log10>},
     575                 :             :         {"log2", asar_unary_wrapper<log2>},
     576                 :             : 
     577                 :             :         {"ceil", asar_unary_wrapper<ceil>},
     578                 :             :         {"floor", asar_unary_wrapper<floor>},
     579                 :             : 
     580                 :             :         {"read1", asar_read<1>},        //This handles the safe and unsafe variant
     581                 :             :         {"read2", asar_read<2>},
     582                 :             :         {"read3", asar_read<3>},
     583                 :             :         {"read4", asar_read<4>},                        
     584                 :             :         {"canread", asar_canread<0>},
     585                 :             :         {"canread1", asar_canread<1>},
     586                 :             :         {"canread2", asar_canread<2>},
     587                 :             :         {"canread3", asar_canread<3>},
     588                 :             :         {"canread4", asar_canread<4>},
     589                 :             :         
     590                 :             :         {"readfile1", asar_readfile<1>},
     591                 :             :         {"readfile2", asar_readfile<2>},
     592                 :             :         {"readfile3", asar_readfile<3>},
     593                 :             :         {"readfile4", asar_readfile<4>},
     594                 :             :         {"canreadfile", asar_canreadfile<0>},
     595                 :             :         {"canreadfile1", asar_canreadfile<1>},
     596                 :             :         {"canreadfile2", asar_canreadfile<2>},
     597                 :             :         {"canreadfile3", asar_canreadfile<3>},
     598                 :             :         {"canreadfile4", asar_canreadfile<4>},
     599                 :             :         
     600                 :             :         {"filesize", asar_filesize},
     601                 :             :         {"getfilestatus", asar_filestatus},
     602                 :             :         
     603                 :             :         {"defined", asar_isdefined},
     604                 :             :         
     605                 :             :         {"snestopc", asar_snestopc_wrapper},
     606                 :             :         {"pctosnes", asar_pctosnes_wrapper},
     607                 :             :         {"realbase", asar_realbase_wrapper},
     608                 :             :         
     609                 :             :         {"max", asar_binary_wrapper<asar_max>},
     610                 :             :         {"min", asar_binary_wrapper<asar_min>},
     611                 :             :         {"clamp", asar_clamp},
     612                 :             :         
     613                 :             :         {"safediv", asar_safediv},
     614                 :             :         
     615                 :             :         {"select", asar_select},
     616                 :             :         {"bank", asar_unary_wrapper<asar_bank>},
     617                 :             :         {"not", asar_unary_wrapper<std::logical_not<unsigned int>>},
     618                 :             :         {"equal", asar_binary_wrapper<std::equal_to<double>>},
     619                 :             :         {"notequal", asar_binary_wrapper<std::not_equal_to<double>>},
     620                 :             :         {"less", asar_binary_wrapper<std::less<double>>},
     621                 :             :         {"lessequal", asar_binary_wrapper<std::less_equal<double>>},
     622                 :             :         {"greater", asar_binary_wrapper<std::greater<double>>},
     623                 :             :         {"greaterequal", asar_binary_wrapper<std::greater_equal<double>>},
     624                 :             :         
     625                 :             :         {"and", asar_binary_wrapper<std::logical_and<unsigned int>>},
     626                 :             :         {"or", asar_binary_wrapper<std::logical_or<unsigned int>>},
     627                 :             :         {"nand", asar_binary_wrapper<asar_logical_nand>},
     628                 :             :         {"nor", asar_binary_wrapper<asar_logical_nor>},
     629                 :             :         {"xor", asar_binary_wrapper<asar_logical_xor>},
     630                 :             :         
     631                 :             :         {"round", asar_round},
     632                 :             :         
     633                 :             :         {"sizeof", asar_structsize_wrapper},
     634                 :             :         {"objectsize", asar_objectsize_wrapper},
     635                 :             :         {"datasize", asar_datasize_wrapper},
     636                 :             :         
     637                 :             :         {"stringsequal", asar_stringsequal},
     638                 :             :         {"stringsequalnocase", asar_stringsequalnocase}
     639                 :             : };
     640                 :             : 
     641                 :             : assocarr<double (*)()> functions;
     642                 :             : 
     643                 :             : struct funcdat {
     644                 :             :         autoptr<char*> name;
     645                 :             :         int numargs;
     646                 :             :         autoptr<char*> argbuf;//this one isn't used, it's just to free it up
     647                 :             :         autoptr<char**> arguments;
     648                 :             :         autoptr<char*> content;
     649                 :             : };
     650                 :             : static assocarr<funcdat> user_functions;
     651                 :             : 
     652                 :          15 : static double asar_call_user_function()
     653                 :             : {
     654                 :          15 :         autoarray<string> args;
     655                 :          15 :         funcdat &user_function = user_functions[current_user_function_name];
     656                 :          15 :         string real_content;
     657                 :             :         
     658         [ -  + ]:          15 :         while (*str==' ') str++;
     659                 :          15 :         bool has_next = *str != ')';
     660                 :             :         
     661         [ +  + ]:          36 :         for (int i=0;i<user_function.numargs;i++)
     662                 :             :         {
     663         [ -  + ]:          21 :                 if(!has_next)
     664                 :             :                 {
     665                 :           0 :                         asar_throw_error(2, error_type_block, error_id_expected_parameter, current_user_function_name);
     666                 :             :                 }
     667                 :          42 :                 args[i] = copy_arg();
     668                 :          21 :                 has_next = has_next_parameter();
     669                 :             :         }
     670                 :             :         
     671         [ -  + ]:          15 :         if(has_next)
     672                 :             :         {
     673                 :           0 :                 asar_throw_error(2, error_type_block, error_id_unexpected_parameter, current_user_function_name);
     674                 :             :         }
     675                 :             :         
     676         [ +  + ]:          77 :         for(int i=0; user_function.content[i]; i++)
     677                 :             :         {
     678   [ +  +  -  + ]:          62 :                 if(!is_alpha(user_function.content[i]) && user_function.content[i] != '_')
     679                 :             :                 {
     680                 :          37 :                         real_content += user_function.content[i];
     681                 :          37 :                         continue;
     682                 :             :                 }
     683                 :             :                 bool found = false;
     684         [ +  + ]:          66 :                 for (int j=0;user_function.arguments[j];j++)
     685                 :             :                 {
     686                 :             :                         //this should *always* have a null term or another character after 
     687                 :          41 :                         bool potential_arg = stribegin(user_function.content+i, user_function.arguments[j]);
     688                 :          41 :                         int next_char = i+strlen(user_function.arguments[j]);
     689   [ +  +  +  -  :          41 :                         if(potential_arg && (!is_alnum(user_function.content[next_char]) && user_function.content[next_char] != '_'))
                   +  - ]
     690                 :             :                         {
     691                 :          21 :                                 real_content += args[j];
     692                 :          21 :                                 i = next_char - 1;
     693                 :             :                                 found = true;
     694                 :             :                         }
     695                 :             :                 }
     696                 :             :                 
     697         [ +  + ]:          25 :                 if(!found){
     698         [ +  + ]:          40 :                         for(; is_ualnum(user_function.content[i]); i++){
     699                 :          36 :                                 real_content += user_function.content[i];
     700                 :             :                         }
     701                 :           4 :                         real_content += user_function.content[i];
     702                 :             :                 }
     703                 :             :         }
     704                 :          15 :         const char * oldstr=str;
     705                 :          15 :         str = (const char *)real_content;
     706                 :          15 :         double result = eval(0);
     707                 :          15 :         str = oldstr;
     708                 :          15 :         return result;
     709                 :          15 : }
     710                 :             : 
     711                 :          15 : void createuserfunc(const char * name, const char * arguments, const char * content)
     712                 :             : {
     713         [ -  + ]:          15 :         if (!confirmqpar(content)) asar_throw_error(0, error_type_block, error_id_mismatched_parentheses);
     714         [ -  + ]:          15 :         if(functions.exists(name)) //functions holds both types.
     715                 :             :         {
     716                 :             :                 //asar_throw_error(0, error_type_block, error_id_function_redefined, name);
     717                 :           0 :                 asar_throw_warning(1, warning_id_feature_deprecated, "overwriting a previously defined function", "change the function name");
     718                 :             :         }
     719                 :          15 :         funcdat& user_function=user_functions[name];
     720                 :          15 :         user_function.name= duplicate_string(name);
     721                 :          15 :         user_function.argbuf= duplicate_string(arguments);
     722                 :          15 :         user_function.arguments=qsplit(user_function.argbuf, ",", &(user_function.numargs));
     723                 :          15 :         user_function.content= duplicate_string(content);
     724         [ +  + ]:          36 :         for (int i=0;user_function.arguments[i];i++)
     725                 :             :         {
     726         [ +  + ]:          54 :                 for(int j=0;user_function.arguments[j];j++)
     727                 :             :                 {
     728   [ +  +  -  + ]:          33 :                         if(i!=j && !stricmp(user_function.arguments[i], user_function.arguments[j]))
     729                 :             :                         {
     730                 :           0 :                                 asar_throw_error(0, error_type_block, error_id_duplicate_param_name, user_function.arguments[i], name);
     731                 :             :                         }
     732                 :             :                 }
     733         [ -  + ]:          21 :                 if (!confirmname(user_function.arguments[i]))
     734                 :             :                 {
     735                 :           0 :                         user_functions.remove(name);
     736                 :           0 :                         asar_throw_error(0, error_type_block, error_id_invalid_param_name);
     737                 :             :                 }
     738                 :             :         }
     739                 :             :         
     740                 :          15 :         functions[name] = asar_call_user_function;
     741                 :          15 : }
     742                 :             : 
     743                 :      918844 : static double getnumcore()
     744                 :             : {
     745         [ +  + ]:      918844 :         if (*str=='(')
     746                 :             :         {
     747                 :         268 :                 str++;
     748                 :         268 :                 double rval=eval(0);
     749         [ -  + ]:         268 :                 if (*str != ')') asar_throw_error(2, error_type_block, error_id_mismatched_parentheses);
     750                 :         268 :                 str++;
     751                 :         268 :                 return rval;
     752                 :             :         }
     753         [ +  + ]:      918576 :         if (*str=='$')
     754                 :             :         {
     755         [ -  + ]:        3449 :                 if (!is_xdigit(str[1])) asar_throw_error(2, error_type_block, error_id_invalid_hex_value);
     756         [ +  - ]:        3449 :                 if (to_lower(str[2])=='x') return -42;//let str get an invalid value so it'll throw an invalid operator later on
     757                 :        3449 :                 return strtoull(str+1, const_cast<char**>(&str), 16);
     758                 :             :         }
     759         [ +  + ]:      915127 :         if (*str=='%')
     760                 :             :         {
     761         [ -  + ]:          24 :                 if (str[1] != '0' && str[1] != '1') asar_throw_error(2, error_type_block, error_id_invalid_binary_value);
     762                 :          24 :                 return strtoull(str+1, const_cast<char**>(&str), 2);
     763                 :             :         }
     764         [ +  + ]:      915103 :         if (*str=='\'')
     765                 :             :         {
     766   [ +  -  -  + ]:          24 :                 if (!str[1] || str[2] != '\'') asar_throw_error(2, error_type_block, error_id_invalid_character);
     767                 :          24 :                 unsigned int rval=table.table[(unsigned char)str[1]];
     768                 :          24 :                 str+=3;
     769                 :          24 :                 return rval;
     770                 :             :         }
     771         [ +  + ]:      915079 :         if (is_digit(*str))
     772                 :             :         {
     773                 :             :                 const char* end = str;
     774   [ +  +  +  + ]:     4113243 :                 while (is_digit(*end) || *end == '.') end++;
     775                 :      914183 :                 string number;
     776                 :      914183 :                 number.assign(str, (int)(end - str));
     777                 :      914183 :                 str = end;
     778                 :      914183 :                 return atof(number);
     779                 :      914183 :         }
     780         [ +  + ]:         896 :         if (is_alpha(*str) || *str=='_' || *str=='.' || *str=='?')
     781                 :             :         {
     782                 :         893 :                 const char * start=str;
     783   [ +  +  +  +  :        8512 :                 while (is_alnum(*str) || *str == '_' || *str == '.') str++;
                   +  + ]
     784                 :         893 :                 int len=(int)(str-start);
     785         [ -  + ]:         893 :                 while (*str==' ') str++;
     786         [ +  + ]:         893 :                 if (*str=='(')
     787                 :             :                 {
     788                 :         447 :                         str++;
     789                 :             :                         // RPG Hacker: This is only here to assure that all strings are still
     790                 :             :                         // alive in memory when we call our functions further down
     791                 :             :                         double result;
     792                 :             :                         while (true)
     793                 :             :                         {
     794         [ -  + ]:         447 :                                 while (*str==' ') str++;
     795                 :         447 :                                 string function_name = string(start, len);
     796         [ +  - ]:         447 :                                 if(functions.exists(function_name))
     797                 :             :                                 {
     798                 :         447 :                                         current_user_function_name = function_name;
     799                 :         447 :                                         result = functions[function_name]();
     800                 :             :                                 }
     801                 :             :                                 else
     802                 :             :                                 {
     803                 :           0 :                                         str++;
     804                 :             :                                         break;
     805                 :             :                                 }
     806                 :             :                                 
     807         [ +  - ]:         444 :                                 if (*str==')')
     808                 :             :                                 {
     809                 :         444 :                                         str++;
     810                 :             :                                         return result;
     811                 :             :                                 }
     812                 :           0 :                                 asar_throw_error(2, error_type_block, error_id_malformed_function_call);
     813                 :         447 :                         }
     814                 :             : 
     815                 :           0 :                         asar_throw_error(2, error_type_block, error_id_function_not_found, start);
     816                 :             :                 }
     817                 :             :                 else
     818                 :             :                 {
     819                 :         446 :                         foundlabel=true;
     820                 :             : 
     821                 :             :                         const char *old_start = start;
     822                 :         446 :                         snes_label label_data = labelval(&start);
     823                 :         446 :                         int i=(int)label_data.pos;
     824                 :         446 :                         foundlabel_static &= label_data.is_static;
     825                 :             :                         bool scope_passed = false;
     826                 :             :                         bool subscript_passed = false;
     827         [ +  + ]:        1192 :                         while (str < start)
     828                 :             :                         {
     829         [ +  + ]:         300 :                                 if (*str == '.') scope_passed = true;
     830         [ +  + ]:         300 :                                 if (*(str++) == '[')
     831                 :             :                                 {
     832         [ -  + ]:          30 :                                         if (subscript_passed)
     833                 :             :                                         {
     834                 :           0 :                                                 asar_throw_error(2, error_type_block, error_id_multiple_subscript_operators);
     835                 :           0 :                                                 break;
     836                 :             :                                         }
     837                 :             :                                         subscript_passed = true;
     838         [ -  + ]:          30 :                                         if (scope_passed)
     839                 :             :                                         {
     840                 :           0 :                                                 asar_throw_error(2, error_type_block, error_id_invalid_subscript);
     841                 :             :                                                 break;
     842                 :             :                                         }
     843                 :          30 :                                         string struct_name = substr(old_start, (int)(str - old_start - 1));
     844                 :          30 :                                         i += (int)(eval(0) * object_size(struct_name));
     845                 :          30 :                                 }
     846                 :             :                         }
     847                 :             : 
     848                 :         446 :                         str=start;
     849         [ +  + ]:         446 :                         if (i==-1) forwardlabel=true;
     850                 :         446 :                         return (int)i&0xFFFFFF;
     851                 :             :                 }
     852                 :             :         }
     853                 :           3 :         asar_throw_error(2, error_type_block, error_id_invalid_number);
     854                 :           0 :         return 0.0;
     855                 :             : }
     856                 :             : 
     857                 :     1129607 : static double sanitize(double val)
     858                 :             : {
     859         [ -  + ]:     1129607 :         if (val != val) asar_throw_error(2, error_type_block, error_id_nan);
     860   [ +  -  +  + ]:     1129607 :         if (math_round && !default_math_round_off) return trunc(val); // originally used int cast, but that broke numbers > $8000_0000
     861                 :             :         return val;
     862                 :             : }
     863                 :             : 
     864                 :      918878 : static double getnum()
     865                 :             : {
     866         [ -  + ]:      918878 :         while (*str==' ') str++;
     867                 :             : #define prefix(sym, func) if (*str == sym) { str+=1; double val=getnum(); return sanitize(func); }
     868                 :             : #define prefix_dep(sym, func) if (*str == sym) { str+=1; asar_throw_warning(2, warning_id_feature_deprecated, "xkas style numbers ", "remove the #"); double val=getnum(); return sanitize(func); }
     869                 :             : #define prefix2(sym, sym2, func) if (*str == sym && *(str+1) == sym2) { str+=2; double val=getnum(); return sanitize(func); }
     870                 :      918878 :         prefix('-', -val);
     871                 :      918850 :         prefix('~', ~(int)val);
     872   [ +  +  +  - ]:      918848 :         prefix2('<', ':', (int)val>>16);
     873                 :      918844 :         prefix('+', val);
     874   [ +  +  -  + ]:      918844 :         prefix_dep('#' && emulatexkas, val);
     875                 :             : #undef prefix
     876                 :      918844 :         return sanitize(getnumcore());
     877                 :             : }
     878                 :             : 
     879                 :       37573 : int64_t getnum(const char* instr)
     880                 :             : {
     881                 :       37573 :         return getnum64(instr);
     882                 :             :         
     883                 :             :         // randomdude999: perform manual bounds-checking and 2's complement,
     884                 :             :         // to prevent depending on UB
     885                 :             :         double num = math(instr);
     886                 :             :         if(num < 0) {
     887                 :             :                 // manual 2's complement
     888                 :             :                 if((-num) > (double)UINT32_MAX) {
     889                 :             :                         // out of bounds, return closest inbounds value
     890                 :             :                         // (this value is the most negative value possible)
     891                 :             :                         return ((uint32_t)INT32_MAX)+1;
     892                 :             :                 }
     893                 :             :                 return ~((uint32_t)(-num))+1;
     894                 :             :         } else {
     895                 :             :                 if(num > (double)UINT32_MAX) {
     896                 :             :                         // out of bounds, return closest inbounds value
     897                 :             :                         return UINT32_MAX;
     898                 :             :                 }
     899                 :             :                 return (uint32_t)num;
     900                 :             :         }
     901                 :             : }
     902                 :             : 
     903                 :       37777 : int64_t getnum64(const char* instr)
     904                 :             : {
     905                 :             :         // randomdude999: perform manual bounds-checking
     906                 :             :         // to prevent depending on UB
     907                 :       37777 :         double num = math(instr);
     908         [ +  - ]:       37765 :         if(num < (double)INT64_MIN) {
     909                 :             :                 return INT64_MIN;
     910         [ +  - ]:       37765 :         } else if(num > (double)INT64_MAX) {
     911                 :             :                 return INT64_MAX;
     912                 :             :         }
     913                 :       37765 :         return (int64_t)num;
     914                 :             : }
     915                 :             : 
     916                 :             : // RPG Hacker: Same function as above, but doesn't truncate our number via int conversion
     917                 :      316776 : double getnumdouble(const char * instr)
     918                 :             : {
     919                 :      316776 :         return math(instr);
     920                 :             : }
     921                 :             : 
     922                 :             : 
     923                 :           0 : static double oper_wrapped_throw(asar_error_id errid)
     924                 :             : {
     925                 :           0 :         asar_throw_error(2, error_type_block, errid);
     926                 :           0 :         return 0.0;
     927                 :             : }
     928                 :             : 
     929                 :      813694 : static double eval(int depth)
     930                 :             : {
     931                 :      813694 :         const char* posneglabel = str;
     932                 :      813694 :         string posnegname = posneglabelname(&posneglabel, false);
     933                 :             : 
     934         [ +  + ]:      813694 :         if (posnegname.length() > 0)
     935                 :             :         {
     936   [ +  +  +  - ]:          56 :                 if (*posneglabel != '\0' && *posneglabel != ')') goto notposneglabel;
     937                 :             : 
     938                 :          28 :                 str = posneglabel;
     939                 :             : 
     940                 :          28 :                 foundlabel=true;
     941         [ +  + ]:          28 :                 if (*(posneglabel-1) == '+') forwardlabel=true;
     942                 :          28 :                 snes_label label_data = labelval(posnegname);
     943                 :          28 :                 foundlabel_static &= label_data.is_static;
     944                 :          28 :                 return label_data.pos & 0xFFFFFF;
     945                 :             :         }
     946                 :      813638 : notposneglabel:
     947                 :     1627332 :         recurseblock rec;
     948                 :      813666 :         double left=getnum();
     949                 :             :         double right;
     950         [ -  + ]:      813660 :         while (*str==' ') str++;
     951   [ +  +  +  +  :     1024395 :         while (*str && *str != ')' && *str != ','&& *str != ']')
                   +  + ]
     952                 :             :         {
     953         [ -  + ]:      210744 :                 while (*str==' ') str++;
     954                 :             :                 // why was this an int cast
     955   [ +  -  +  + ]:      210744 :                 if (math_round && !default_math_round_off) left=trunc(left);
     956                 :             : #define oper(name, thisdepth, contents)      \
     957                 :             :                         if (!strncmp(str, name, strlen(name))) \
     958                 :             :                         {                                      \
     959                 :             :                                 if (math_pri || default_math_pri)                        \
     960                 :             :                                 {                                    \
     961                 :             :                                         if (depth<=thisdepth)              \
     962                 :             :                                         {                                  \
     963                 :             :                                                 str+=strlen(name);               \
     964                 :             :                                                 right=eval(thisdepth+1);         \
     965                 :             :                                         }                                  \
     966                 :             :                                         else return left;                  \
     967                 :             :                                 }                                    \
     968                 :             :                                 else                                 \
     969                 :             :                                 {                                    \
     970                 :             :                                         str+=strlen(name);                 \
     971                 :             :                                         right=getnum();                    \
     972                 :             :                                 }                                    \
     973                 :             :                                 left=sanitize(contents);             \
     974                 :             :                                 continue;                            \
     975                 :             :                         }
     976                 :      210744 :                 oper("**", 4, pow((double)left, (double)right));
     977                 :      210738 :                 oper("*", 3, left*right);
     978   [ +  +  +  +  :      210726 :                 oper("/", 3, right != 0.0 ? left / right : oper_wrapped_throw(error_id_division_by_zero));
          -  +  +  -  +  
          -  +  -  +  -  
             -  -  +  - ]
     979   [ -  +  -  -  :      210720 :                 oper("%", 3, right != 0.0 ? fmod((double)left, (double)right) : oper_wrapped_throw(error_id_modulo_by_zero));
          -  -  -  -  -  
          -  -  -  -  -  
             -  -  -  - ]
     980                 :      210720 :                 oper("+", 2, left+right);
     981                 :          92 :                 oper("-", 2, left-right);
     982   [ -  +  -  -  :           3 :                 oper("<<", 1, right >= 0.0 ? (int64_t)left<<(uint64_t)right : oper_wrapped_throw(error_id_negative_shift));
          -  -  -  -  -  
          -  -  -  -  -  
             -  -  -  - ]
     983   [ -  +  -  -  :           3 :                 oper(">>", 1, right >= 0.0 ? (int64_t)left>>(uint64_t)right : oper_wrapped_throw(error_id_negative_shift));
          -  -  -  -  -  
          -  -  -  -  -  
             -  -  -  - ]
     984                 :           3 :                 oper("&", 0, (int64_t)left&(int64_t)right);
     985                 :           3 :                 oper("|", 0, (int64_t)left|(int64_t)right);
     986                 :           3 :                 oper("^", 0, (int64_t)left^(int64_t)right);
     987                 :           3 :                 asar_throw_error(2, error_type_block, error_id_unknown_operator);
     988                 :             : #undef oper
     989                 :             :         }
     990                 :             :         return left;
     991                 :      813694 : }
     992                 :             : 
     993                 :             : //static autoptr<char*> freeme;
     994                 :      354553 : double math(const char * s)
     995                 :             : {       
     996                 :             :         //free(freeme);
     997                 :             :         //freeme=NULL;
     998                 :      354553 :         foundlabel=false;
     999                 :      354553 :         foundlabel_static=true;
    1000                 :      354553 :         forwardlabel=false;
    1001                 :             :         double rval;
    1002                 :             :         
    1003   [ +  -  +  + ]:      354553 :         if(math_pri || default_math_pri)
    1004                 :             :         {
    1005                 :        1559 :                 str = s;
    1006                 :        1559 :                 rval = eval(0);
    1007                 :             :         }
    1008                 :             :         else
    1009                 :             :         {
    1010                 :      352994 :                 str = s;
    1011                 :      352994 :                 rval = eval(0);
    1012                 :             : 
    1013                 :             :                 double pri_rval = NAN;
    1014                 :             : 
    1015                 :      352985 :                 suppress_all_warnings = true;
    1016                 :      352985 :                 math_pri = true;
    1017                 :             :                 try
    1018                 :             :                 {
    1019                 :      352985 :                         str = s;
    1020                 :      352985 :                         pri_rval = eval(0);
    1021                 :             :                 }
    1022                 :           0 :                 catch (errfatal&) {}
    1023                 :      352985 :                 suppress_all_warnings = false;
    1024                 :      352985 :                 math_pri = false;
    1025                 :             : 
    1026         [ +  - ]:      352985 :                 if (pri_rval != rval)
    1027                 :             :                 {
    1028                 :           0 :                         asar_throw_warning(2, warning_id_feature_deprecated, "xkas style left to right math ", "apply order of operations");
    1029                 :             :                 }
    1030                 :             :         }
    1031         [ +  + ]:      354544 :         if (*str)
    1032                 :             :         {
    1033         [ -  + ]:           3 :                 if (*str == ',') asar_throw_error(2, error_type_block, error_id_invalid_input);
    1034                 :           3 :                 else asar_throw_error(2, error_type_block, error_id_mismatched_parentheses);
    1035                 :             :         }
    1036                 :      354541 :         return rval;
    1037                 :             : }
    1038                 :             : 
    1039                 :         281 : void initmathcore()
    1040                 :             : {
    1041                 :         281 :         functions.reset();
    1042                 :         281 :         builtin_functions.each([](const char* key, double (*val)()) {
    1043                 :       17703 :                 functions[key] = val;
    1044                 :       35406 :                 functions[STR "_" + key] = val;
    1045                 :       17703 :         });
    1046                 :         281 :         user_functions.reset();
    1047                 :         281 : }
    1048                 :             : 
    1049                 :         279 : void deinitmathcore()
    1050                 :             : {
    1051                 :             :         //not needed
    1052                 :         279 : }
        

Generated by: LCOV version 2.0-1