Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | latest s2, re-enabled test combinations disabled when string interning was recently turned off. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
6085b8689d1a3850dce4c7457fe2d697 |
User & Date: | stephan 2016-01-31 17:54:04.675 |
Context
2016-02-10
| ||
16:30 | Updated s2 and related build bits, removed the libfossil-injected s2.Buffer.compress() and friends because those have been ported over to the s2 core. check-in: a25251e6b0 user: stephan tags: trunk | |
2016-01-31
| ||
17:54 | latest s2, re-enabled test combinations disabled when string interning was recently turned off. check-in: 6085b8689d user: stephan tags: trunk | |
2016-01-28
| ||
12:40 | minor script updates. check-in: 1cffc35efe user: stephan tags: trunk | |
Changes
Changes to s2/Makefile.
︙ | ︙ | |||
162 163 164 165 166 167 168 169 170 171 | unit: unit-proxy unit2: UNIT_SCRIPTS_ALL:=$(filter unit2/%,$(UNIT_SCRIPT_LIST)) unit2: unit-proxy .PHONY: unit-r .PHONY: unit-rc unit-r: S2SH.SHELL.FLAGS:=--a --R --C unit-r: unit unit-rc: S2SH.SHELL.FLAGS:=--a --R --C unit-rc: unit units: | > > > > | | 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 | unit: unit-proxy unit2: UNIT_SCRIPTS_ALL:=$(filter unit2/%,$(UNIT_SCRIPT_LIST)) unit2: unit-proxy .PHONY: unit-r .PHONY: unit-rc unit-r: S2SH.SHELL.FLAGS:=--a --R --C unit-r: unit unit-s: S2SH.SHELL.FLAGS:=--a -R -C --S unit-s: unit unit-rc: S2SH.SHELL.FLAGS:=--a --R --C unit-rc: unit unit-rsc: S2SH.SHELL.FLAGS:=--a --R --C --S unit-rsc: unit units: @for i in unit unit-r unit-rc unit-s unit-rsc; do \ echo "Making $$i ..."; \ $(MAKE) $$i || exit $$?; \ done include vg.make |
Changes to s2/r-tester.sh.
︙ | ︙ | |||
136 137 138 139 140 141 142 | echo "Massified $test: try: ms_print ${msp} | less" } if [ -e f-s2sh ]; then # kludge for the libfossil source tree S2SH_ADD_FLAGS="${S2SH_ADD_FLAGS} -a" fi | | | 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 | echo "Massified $test: try: ms_print ${msp} | less" } if [ -e f-s2sh ]; then # kludge for the libfossil source tree S2SH_ADD_FLAGS="${S2SH_ADD_FLAGS} -a" fi S2SHFLAGS="--a -R -S ${S2SH_ADD_FLAGS}" # Reminder: some fsl modules rely on code set up by s2sh init script, # so we cannot use the --a option in libfossil. echo S2SHFLAGS=$S2SHFLAGS for test in $list; do echo "Running require.s2 test: ${test}" outfile=${rdir}/${test}.test_out verbose "Output going to: $outfile" |
︙ | ︙ |
Changes to s2/s2_amalgamation.c.
︙ | ︙ | |||
14281 14282 14283 14284 14285 14286 14287 14288 14289 14290 14291 14292 14293 14294 | CWAL_FMT_DOUBLE, CWAL_FMT_STRING, CWAL_FMT_STRING_SQL, CWAL_FMT_CHAR, CWAL_FMT_TYPENAME, CWAL_FMT_BLOB, CWAL_FMT_JSON, CWAL_FMT_MAX }; typedef enum cwal_format_t cwal_format_t; enum cwal_format_flags { CWAL_FMT_F_NONE = 0, CWAL_FMT_F_SIGNED = 0x01, | > > | 14281 14282 14283 14284 14285 14286 14287 14288 14289 14290 14291 14292 14293 14294 14295 14296 | CWAL_FMT_DOUBLE, CWAL_FMT_STRING, CWAL_FMT_STRING_SQL, CWAL_FMT_CHAR, CWAL_FMT_TYPENAME, CWAL_FMT_BLOB, CWAL_FMT_JSON, CWAL_FMT_URLENCODE, CWAL_FMT_URLDECODE, CWAL_FMT_MAX }; typedef enum cwal_format_t cwal_format_t; enum cwal_format_flags { CWAL_FMT_F_NONE = 0, CWAL_FMT_F_SIGNED = 0x01, |
︙ | ︙ | |||
14361 14362 14363 14364 14365 14366 14367 14368 14369 14370 14371 14372 14373 14374 | cwal_format_info * fi, cwal_value const * v ); static int cwal_format_part_basics( cwal_engine * e, cwal_buffer * tgt, cwal_format_info * fi, cwal_value const * v ); static int cwal_format_part_blob( cwal_engine * e, cwal_buffer * tgt, cwal_format_info * fi, cwal_value const * v ); static int cwal_format_part_json( cwal_engine * e, cwal_buffer * tgt, cwal_format_info * fi, cwal_value const * v ); static const cwal_format_info CWAL_FORMAT_INFO[CWAL_FMT_MAX+1] = { /* Maintenance reminder: these MUST be in the same order the entries are defined in cwal_format_t. */ /* {type,flags,precision,width,position,errMsg,pad,f} */ | > > > > | 14363 14364 14365 14366 14367 14368 14369 14370 14371 14372 14373 14374 14375 14376 14377 14378 14379 14380 | cwal_format_info * fi, cwal_value const * v ); static int cwal_format_part_basics( cwal_engine * e, cwal_buffer * tgt, cwal_format_info * fi, cwal_value const * v ); static int cwal_format_part_blob( cwal_engine * e, cwal_buffer * tgt, cwal_format_info * fi, cwal_value const * v ); static int cwal_format_part_json( cwal_engine * e, cwal_buffer * tgt, cwal_format_info * fi, cwal_value const * v ); static int cwal_format_part_urlenc( cwal_engine * e, cwal_buffer * tgt, cwal_format_info * fi, cwal_value const * v ); static int cwal_format_part_urldec( cwal_engine * e, cwal_buffer * tgt, cwal_format_info * fi, cwal_value const * v ); static const cwal_format_info CWAL_FORMAT_INFO[CWAL_FMT_MAX+1] = { /* Maintenance reminder: these MUST be in the same order the entries are defined in cwal_format_t. */ /* {type,flags,precision,width,position,errMsg,pad,f} */ |
︙ | ︙ | |||
14385 14386 14387 14388 14389 14390 14391 14392 14393 14394 14395 14396 14397 14398 | FMT(DOUBLE,double), FMT(STRING,string), FMT(STRING_SQL,sql), FMT(CHAR,char), FMT(TYPENAME,basics), FMT(BLOB,blob), FMT(JSON,json), #undef FMT {CWAL_FMT_MAX, 0, 0, 0, 0,NULL,' ', NULL}, }; static const cwal_format_info cwal_format_info_empty = { CWAL_FMT_UNKNOWN, 0/*flags*/, | > > | 14391 14392 14393 14394 14395 14396 14397 14398 14399 14400 14401 14402 14403 14404 14405 14406 | FMT(DOUBLE,double), FMT(STRING,string), FMT(STRING_SQL,sql), FMT(CHAR,char), FMT(TYPENAME,basics), FMT(BLOB,blob), FMT(JSON,json), FMT(URLENCODE,urlenc), FMT(URLDECODE,urldec), #undef FMT {CWAL_FMT_MAX, 0, 0, 0, 0,NULL,' ', NULL}, }; static const cwal_format_info cwal_format_info_empty = { CWAL_FMT_UNKNOWN, 0/*flags*/, |
︙ | ︙ | |||
14750 14751 14752 14753 14754 14755 14756 14757 14758 14759 14760 14761 14762 14763 | for( ; !rc && (width > n); --width){ rc = cwal_buffer_append( e, tgt, &fi->pad, 1 ); } } return rc; } } /** Parse the range [b,*e) as a java.lang.String.format()-style format string: %N$[flags][width][.precision][type] */ static int cwal_format_parse_info( char const * b, char const ** e, | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 14758 14759 14760 14761 14762 14763 14764 14765 14766 14767 14768 14769 14770 14771 14772 14773 14774 14775 14776 14777 14778 14779 14780 14781 14782 14783 14784 14785 14786 14787 14788 14789 14790 14791 14792 14793 14794 14795 14796 14797 14798 14799 14800 14801 14802 14803 14804 14805 14806 14807 14808 14809 14810 14811 14812 14813 14814 14815 14816 14817 14818 14819 14820 14821 14822 14823 14824 14825 14826 14827 14828 14829 14830 14831 14832 14833 14834 14835 14836 14837 14838 14839 14840 14841 14842 14843 14844 14845 14846 14847 14848 14849 14850 14851 14852 14853 14854 14855 14856 14857 14858 14859 14860 14861 14862 14863 14864 14865 14866 14867 14868 14869 14870 14871 14872 14873 14874 14875 14876 14877 14878 14879 14880 14881 14882 14883 14884 14885 14886 14887 14888 14889 14890 14891 14892 14893 14894 14895 14896 14897 14898 14899 14900 14901 14902 14903 14904 14905 14906 | for( ; !rc && (width > n); --width){ rc = cwal_buffer_append( e, tgt, &fi->pad, 1 ); } } return rc; } } static int cwal_httpurl_needs_escape( int c ) { /* Definition of "safe" and "unsafe" chars was taken from: http://www.codeguru.com/cpp/cpp/cpp_mfc/article.php/c4029/ */ return ( (c >= 32 && c <=47) || ( c>=58 && c<=64) || ( c>=91 && c<=96) || ( c>=123 && c<=126) || ( c<32 || c>=127) ); } int cwal_format_part_urlenc( cwal_engine * e, cwal_buffer * tgt, cwal_format_info * fi, cwal_value const * v ){ cwal_size_t slen = 0; char const * str = cwal_value_get_cstr(v, &slen); char ch; int rc = 0; cwal_size_t j = 0; char * bufpt = NULL; cwal_size_t const oldUsed = e->buffer.used; static char const * hex = "0123456789ABCDEF"; if(!str){ fi->errMsg = "URL encoding requires a String value."; return CWAL_RC_TYPE; } rc = cwal_buffer_reserve(e, &e->buffer, oldUsed + slen * 3 ); if(rc) return rc; bufpt = (char *)(e->buffer.mem + oldUsed); ch = *str; for( ; !rc && ch; ch = *(++str) ){ if(!cwal_httpurl_needs_escape(ch) ){ bufpt[j++] = ch; }else{ bufpt[j++] = '%'; bufpt[j++] = hex[((ch>>4)&0xf)]; bufpt[j++] = hex[(ch&0xf)]; } } assert( (void *)bufpt == (void*)e->buffer.mem ); rc = cwal_buffer_append(e, tgt, bufpt, j); e->buffer.used = oldUsed; e->buffer.mem[e->buffer.used] = 0; return 0; } /* cwal_hexchar_to_int(): For 'a'-'f', 'A'-'F' and '0'-'9', returns the appropriate decimal number. For any other character it returns -1. */ static int cwal_hexchar_to_int( int ch ) { if( (ch>='0' && ch<='9') ) return ch-'0'; else if( (ch>='a' && ch<='f') ) return ch-'a'+10; else if( (ch>='A' && ch<='F') ) return ch-'A'+10; else return -1; } static int cwal_is_xdigit( int ch ){ return ('a'<=ch && 'f'>=ch) ? 1 : (('A'<=ch && 'F'>=ch) ? 1 : ('0'<=ch && '9'>=ch ? 1 : 0)); } int cwal_format_part_urldec( cwal_engine * e, cwal_buffer * tgt, cwal_format_info * fi, cwal_value const * v ){ cwal_size_t slen = 0; char const * str = cwal_value_get_cstr(v, &slen); int rc = 0; char ch = 0, ch2 = 0; char xbuf[4]; int decoded; if(!str){ fi->errMsg = "URL decoding requires a String value."; return CWAL_RC_TYPE; } else if(!slen) return 0; else if(slen<3){ /* can't be urlencoded */ return cwal_buffer_append(e, tgt, str, slen); } ch = *str; while( !rc && ch ){ if( ch == '%' ){ ch = *(++str); ch2 = *(++str); if( cwal_is_xdigit((int)ch) && cwal_is_xdigit((int)ch2) ){ decoded = (cwal_hexchar_to_int( ch ) * 16) + cwal_hexchar_to_int( ch2 ); xbuf[0] = (char)decoded; xbuf[1] = 0; rc = cwal_buffer_append(e, tgt, xbuf, 1); ch = *(++str); continue; } else{ xbuf[0] = '%'; xbuf[1] = ch; xbuf[2] = ch2; xbuf[3] = 0; rc = cwal_buffer_append(e, tgt, xbuf, 3); ch = *(++str); continue; } } else if( ch == '+' ){ xbuf[0] = ' '; xbuf[1] = 0; rc = cwal_buffer_append(e, tgt, xbuf, 1); ch = *(++str); continue; } xbuf[0] = ch; xbuf[1] = 0; rc = cwal_buffer_append(e, tgt, xbuf, 1); ch = *(++str); } return rc; } /** Parse the range [b,*e) as a java.lang.String.format()-style format string: %N$[flags][width][.precision][type] */ static int cwal_format_parse_info( char const * b, char const ** e, |
︙ | ︙ | |||
14893 14894 14895 14896 14897 14898 14899 14900 14901 14902 14903 14904 14905 14906 14907 14908 | break; case 'x': fi->type = CWAL_FMT_INT_HEXLC; ++p; break; case 'X': fi->type = CWAL_FMT_INT_HEXUC; ++p; break; default: fi->errMsg = "Unknown format type specifier."; return CWAL_RC_RANGE; } switch(fi->type){ case CWAL_FMT_INT_DEC: case CWAL_FMT_INT_HEXLC: case CWAL_FMT_INT_HEXUC: if(fi->precision && cwalFormatNoPrecision != fi->precision){ | > > > > > > > > > > > > > | > > | 15036 15037 15038 15039 15040 15041 15042 15043 15044 15045 15046 15047 15048 15049 15050 15051 15052 15053 15054 15055 15056 15057 15058 15059 15060 15061 15062 15063 15064 15065 15066 15067 15068 15069 15070 15071 15072 15073 15074 15075 15076 15077 15078 15079 15080 15081 | break; case 'x': fi->type = CWAL_FMT_INT_HEXLC; ++p; break; case 'X': fi->type = CWAL_FMT_INT_HEXUC; ++p; break; case 'r': fi->type = CWAL_FMT_URLENCODE; ++p; break; case 'R': fi->type = CWAL_FMT_URLDECODE; ++p; break; default: fi->errMsg = "Unknown format type specifier."; return CWAL_RC_RANGE; } switch(fi->type){ case CWAL_FMT_URLENCODE: case CWAL_FMT_URLDECODE: if(fi->width){ fi->errMsg = "Conversion does not support width."; return CWAL_RC_MISUSE; } /* fall through */ case CWAL_FMT_INT_DEC: case CWAL_FMT_INT_HEXLC: case CWAL_FMT_INT_HEXUC: if(fi->precision && cwalFormatNoPrecision != fi->precision){ fi->errMsg = "Conversion does not support precision."; return CWAL_RC_MISUSE; } break; case CWAL_FMT_CHAR: if(fi->precision<0){ fi->errMsg = "Character precision (repetition) may not be negative."; return CWAL_RC_MISUSE; } break; default: break; } *e = p; fi->f = CWAL_FORMAT_INFO[fi->type].f; return 0; } |
︙ | ︙ | |||
21758 21759 21760 21761 21762 21763 21764 | assert((st->size >= op->arity) || (op->assoc>0 && op->arity==1 /* unary +, -, ~ */)); #endif if(st->size < op->arity){ rc = s2_engine_err_set(se, CWAL_RC_RANGE, "Not enough operands on the stack."); }else{ | < < < < < < < < < < < < < < | < < < < > > > | 21916 21917 21918 21919 21920 21921 21922 21923 21924 21925 21926 21927 21928 21929 21930 21931 21932 21933 21934 21935 21936 | assert((st->size >= op->arity) || (op->assoc>0 && op->arity==1 /* unary +, -, ~ */)); #endif if(st->size < op->arity){ rc = s2_engine_err_set(se, CWAL_RC_RANGE, "Not enough operands on the stack."); }else{ rc = op->call(op, se, op->arity, &rv); popArgCount = op->arity; } }else{ #if 1 assert(!"not possible"); #else /* Variadic operator ... */ s2_stoken * t = se->st.vals.top; int i = 0; char doBreak = 0; /* Count how the arguments by looking for a S2_T_MarkVariadicStart token. */ for( ; t && !doBreak && (i <st->size); t = t->next ){ |
︙ | ︙ | |||
21812 21813 21814 21815 21816 21817 21818 21819 21820 21821 21822 21823 21824 21825 | s2_stoken * variadicCheck = s2_engine_peek_token(se); assert(variadicCheck); assert(S2_T_MarkVariadicStart == variadicCheck->ttype); } s2_engine_pop_token( se, 0 ) /* S2_T_MarkVariadicStart */; popArgCount = i + 1 /* variadic marker */; } } if(!rc){ assert( st->size == (oldStackSize - popArgCount) ); if(st->size != (oldStackSize - popArgCount)){ rc = s2_engine_err_set(se, CWAL_RC_MISUSE, "Unexpected stack size after " "running operator '%s'\n", | > | 21955 21956 21957 21958 21959 21960 21961 21962 21963 21964 21965 21966 21967 21968 21969 | s2_stoken * variadicCheck = s2_engine_peek_token(se); assert(variadicCheck); assert(S2_T_MarkVariadicStart == variadicCheck->ttype); } s2_engine_pop_token( se, 0 ) /* S2_T_MarkVariadicStart */; popArgCount = i + 1 /* variadic marker */; } #endif } if(!rc){ assert( st->size == (oldStackSize - popArgCount) ); if(st->size != (oldStackSize - popArgCount)){ rc = s2_engine_err_set(se, CWAL_RC_MISUSE, "Unexpected stack size after " "running operator '%s'\n", |
︙ | ︙ | |||
23885 23886 23887 23888 23889 23890 23891 23892 | return se ? se->e : 0; } s2_scope * s2_scope_current( s2_engine * se ){ return (se && se->e) ? se->currentScope : 0; } int s2_scope_push( s2_engine * se, s2_scope * tgt ){ | > > > > > | > > > > > | 24029 24030 24031 24032 24033 24034 24035 24036 24037 24038 24039 24040 24041 24042 24043 24044 24045 24046 24047 24048 24049 24050 24051 24052 24053 24054 24055 24056 24057 24058 24059 24060 24061 24062 24063 24064 24065 24066 24067 24068 24069 24070 24071 24072 24073 24074 24075 24076 24077 24078 24079 24080 24081 24082 24083 24084 24085 24086 | return se ? se->e : 0; } s2_scope * s2_scope_current( s2_engine * se ){ return (se && se->e) ? se->currentScope : 0; } /* defined in s2_eval.c */ void s2_dotop_state( s2_engine * se, cwal_value * self, cwal_value * lhs, cwal_value * key ); int s2_scope_push( s2_engine * se, s2_scope * tgt ){ int rc = 0; cwal_scope * pScope = &tgt->scope; assert(se); assert(se->e); assert(tgt); assert(!tgt->parent); /* s2_dotop_state(se, 0, 0, 0); */ rc = cwal_scope_push( se->e, &pScope ); if(!rc){ /* assert(tgt->scope.parent); */ if((int)tgt->scope.level > se->metrics.maxScopeDepth){ se->metrics.maxScopeDepth = (int)tgt->scope.level; } tgt->parent = se->currentScope; se->currentScope = tgt; se->sguard = &tgt->sguard; /* MARKER(("pushed %p\n",(void const *)tgt)); */ /* Make sure that ternary depth is not counted across scopes. We need a similar hack for non-scope-pushing blocks, now that i think about it. */ s2_engine_subexpr_save(se, &tgt->saved); }else{ assert(!"This can't happen if the args are valid!"); rc = CWAL_RC_ASSERT; } return rc; } int s2_scope_pop2( s2_engine * se, cwal_value * upScopeThis ){ int rc; s2_scope * sc = se->currentScope; assert(se); assert(se->e); assert(se->e->current); s2_dotop_state(se, 0, 0, 0) /* necessary to keep from holding unpropagated, stale refs */; if(sc==&se->topScope){ upScopeThis = 0 /* cannot propagate this */; cwal_exception_set(se->e, 0); s2_propagating_set(se, 0); } assert(se->e->current == &sc->scope); if(upScopeThis){ |
︙ | ︙ | |||
23977 23978 23979 23980 23981 23982 23983 23984 23985 23986 23987 23988 23989 23990 | popping the scope don't like this at all.*/ else{ s2_engine_sweep(se); } #endif }else{ assert(!"This can't happen if the args are valid!"); } return rc; } int s2_scope_pop( s2_engine * se ){ return s2_scope_pop2(se, 0); } | > | 24131 24132 24133 24134 24135 24136 24137 24138 24139 24140 24141 24142 24143 24144 24145 | popping the scope don't like this at all.*/ else{ s2_engine_sweep(se); } #endif }else{ assert(!"This can't happen if the args are valid!"); rc = CWAL_RC_ASSERT; } return rc; } int s2_scope_pop( s2_engine * se ){ return s2_scope_pop2(se, 0); } |
︙ | ︙ | |||
24595 24596 24597 24598 24599 24600 24601 | }else{ *rv = destV; cwal_value_unhand(destV); } return rc; } | | | | | | | > > | < | 24750 24751 24752 24753 24754 24755 24756 24757 24758 24759 24760 24761 24762 24763 24764 24765 24766 24767 24768 24769 24770 24771 24772 24773 24774 24775 24776 24777 24778 24779 24780 24781 24782 24783 24784 24785 24786 24787 24788 24789 24790 24791 24792 24793 24794 24795 24796 24797 24798 24799 24800 | }else{ *rv = destV; cwal_value_unhand(destV); } return rc; } int s2_ctor_method_set( s2_engine * se, cwal_value * container, cwal_function * method ){ if(!se || !container || !method) return CWAL_RC_MISUSE; else if(!cwal_props_can(container)) return CWAL_RC_TYPE; else{ return s2_set_with_flags_v( se, container, se->cache.keyCtorNew, cwal_function_value(method), CWAL_VAR_F_CONST | CWAL_VAR_F_HIDDEN ); } } int s2_ctor_callback_set( s2_engine * se, cwal_value * container, cwal_callback_f method ){ int rc; cwal_function * f; cwal_value * fv; if(!se || !container || !method) return CWAL_RC_MISUSE; else if(!cwal_props_can(container)) return CWAL_RC_TYPE; fv = s2_new_callback(se, method); f = fv ? cwal_value_get_function(fv) : NULL; if(f){ cwal_value_ref(fv); rc = s2_ctor_method_set( se, container, f ); cwal_value_unref(fv); }else{ rc = CWAL_RC_OOM; } return rc; } char s2_scope_is_newing(s2_engine * se){ return (&se->currentScope->scope == se->e->current /* ^^^ reminder: cwal_scope_push() may add scopes without s2 seeing them. */ && se->currentScope->newingThis) ? 1 : 0; } int s2_ctor_fetch( s2_engine * se, s2_ptoker const * pr, cwal_value * operand, cwal_function **rv, int errPolicy ){ cwal_value * vtor = 0; |
︙ | ︙ | |||
25992 25993 25994 25995 25996 25997 25998 | key with (s2_keyword **) on s2_keyword::word. */ static int s2_keyword_cmp(void const * key, void const * kw){ s2_keyword const * k = ((s2_keyword const *)key); s2_keyword const * w = *((s2_keyword const **)kw); if(k->wordLen == w->wordLen) return memcmp(k->word, w->word, (size_t)k->wordLen); | > > > | > > | 26148 26149 26150 26151 26152 26153 26154 26155 26156 26157 26158 26159 26160 26161 26162 26163 26164 26165 26166 26167 | key with (s2_keyword **) on s2_keyword::word. */ static int s2_keyword_cmp(void const * key, void const * kw){ s2_keyword const * k = ((s2_keyword const *)key); s2_keyword const * w = *((s2_keyword const **)kw); if(k->wordLen == w->wordLen) return memcmp(k->word, w->word, (size_t)k->wordLen); #if !defined(NDEBUG) else if(!w->word){ assert(!"sentinel gets trimmed from the list length"); return 1 /* sentinel entry */; } #endif else if(k->word[0] != w->word[0]) return (int)k->word[0] - (int)w->word[0]; else{ int const len = (k->wordLen<w->wordLen) ? k->wordLen : w->wordLen; int const cmp = memcmp(k->word, w->word, (size_t)len); return cmp ? cmp : ((len==k->wordLen) ? -1 : 1); } } |
︙ | ︙ | |||
26203 26204 26205 26206 26207 26208 26209 26210 26211 26212 26213 26214 26215 26216 | /* MARKER(("opErrPos=%p\n", (void const *)se->opErrPos)); */ rc = s2_throw_err_ptoker(se, pr ? pr : se->currentScript); break; } return rc; } /** Internal helper for s2_eval_expr(). Possibly processes pending operators in se's stack, depending on op and its precedence in relation to the operator (if any) to the left. Returns 0 on success (which includes it doing nothing of | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 26364 26365 26366 26367 26368 26369 26370 26371 26372 26373 26374 26375 26376 26377 26378 26379 26380 26381 26382 26383 26384 26385 26386 26387 26388 26389 26390 26391 26392 26393 26394 26395 26396 26397 26398 26399 26400 26401 26402 26403 26404 26405 26406 26407 26408 26409 26410 26411 26412 26413 26414 26415 26416 26417 26418 26419 26420 26421 26422 26423 26424 26425 26426 26427 26428 26429 26430 26431 26432 26433 26434 26435 26436 26437 26438 26439 26440 26441 26442 26443 26444 | /* MARKER(("opErrPos=%p\n", (void const *)se->opErrPos)); */ rc = s2_throw_err_ptoker(se, pr ? pr : se->currentScript); break; } return rc; } /** Sets up se's internals so that it knows the most recent dot-op self/lhs/key. If self is not NULL then self is considered to be "this" in the corresponding downstream handling (i.e. it's a property access which binds "this"), else it does not. self is always lhs or 0. Pass all 0's to reset it. */ void s2_dotop_state( s2_engine * se, cwal_value * self, cwal_value * lhs, cwal_value * key ){ #if 0 se->dotOpSelf = self; se->dotOpLhs = lhs; se->dotOpKey = key; #else /* Reminder the validity checks here point to, essentially, misuse in s2, where we've not cleaned up this state before it goes stale. A potential future problem is vacuuming-up of these pointers, which case we can't solve without a per-s2_scope array/container to hold these and make them vacuum-proof. */ cwal_value * oldSelf = se->dotOpSelf; cwal_value * oldLhs = se->dotOpLhs; cwal_value * oldKey = se->dotOpKey; /** Assert that all of them appear to still be valid references (because it's easy to mess that up). These assertions are not guaranteed to trigger in all error cases, but they catch the most common one that we've prematurely unref'd a value and he have a pointer to its cwal-side recycling bin. */ if(oldSelf){ assert( cwal_value_refcount(oldSelf) || cwal_value_is_builtin(oldSelf) ); } if(oldLhs){ assert( cwal_value_refcount(oldLhs) || cwal_value_is_builtin(oldLhs)); } if(oldKey){ assert( cwal_value_refcount(oldKey) || cwal_value_is_builtin(oldKey) ); } /** Because any of self/lhs/key can refer to or contain/own any other, as well as be the same instance of oldSelf/oldLhs/oldKey (in any combination!), we have to ref them all before we unref any of them. */ if(self) cwal_value_ref(self); if(lhs) cwal_value_ref(lhs); if(key) cwal_value_ref(key); se->dotOpSelf = self; se->dotOpLhs = lhs; se->dotOpKey = key; if(oldSelf) cwal_value_unref(oldSelf); if(oldLhs) cwal_value_unref(oldLhs); if(oldKey) cwal_value_unref(oldKey); #endif } /** Internal helper for s2_eval_expr(). Possibly processes pending operators in se's stack, depending on op and its precedence in relation to the operator (if any) to the left. Returns 0 on success (which includes it doing nothing of |
︙ | ︙ | |||
26304 26305 26306 26307 26308 26309 26310 26311 26312 26313 26314 26315 26316 26317 26318 26319 26320 26321 26322 26323 26324 26325 26326 26327 26328 26329 26330 26331 26332 26333 26334 26335 26336 26337 | /* se->currentScript = oldScript; */ s2_engine_subexpr_restore(se, &save); if(sub.errPos) pr->errPos = sub.errPos; return s2_check_interrupted(se, rc); } } } int s2_eval_expr( s2_engine * se, s2_ptoker * st, int evalFlags, cwal_value ** rv){ return s2_eval_expr_impl(se, st, 0, evalFlags, rv); } /** Expects pr to be a comma-separated list of expressions, until its EOF. Empty expressions and a stray trailing comma are not allowed. Evaluates each token and appends it to dest. Returns 0 on success. Some errors are thrown as exceptions, but syntax errors are not and propagated errors might not be exceptions. */ static int s2_eval_to_array( s2_engine * se, s2_ptoker * pr, cwal_array * dest ){ int rc = 0; s2_op const * opComma = s2_ttype_op(S2_T_Comma); s2_ptoken prev = s2_ptoken_empty; char const * errMsg = 0; assert(!se->skipLevel); while( !rc ){ s2_ptoken next = s2_ptoken_empty; cwal_value * v = 0; if( (rc = s2_eval_expr_impl( se, pr, opComma, 0, &v)) ) break; if(!v){ if(s2_ptoker_is_eof(pr)){ if(S2_T_Comma==prev.ttype){ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 26532 26533 26534 26535 26536 26537 26538 26539 26540 26541 26542 26543 26544 26545 26546 26547 26548 26549 26550 26551 26552 26553 26554 26555 26556 26557 26558 26559 26560 26561 26562 26563 26564 26565 26566 26567 26568 26569 26570 26571 26572 26573 26574 26575 26576 26577 26578 26579 26580 26581 26582 26583 26584 26585 26586 26587 26588 26589 26590 26591 26592 26593 26594 26595 26596 26597 26598 26599 26600 26601 26602 26603 26604 26605 26606 26607 26608 26609 26610 26611 26612 26613 26614 26615 26616 26617 26618 26619 26620 26621 26622 26623 26624 26625 26626 26627 26628 26629 26630 26631 26632 26633 | /* se->currentScript = oldScript; */ s2_engine_subexpr_restore(se, &save); if(sub.errPos) pr->errPos = sub.errPos; return s2_check_interrupted(se, rc); } } } /** Like s2_eval_current_sub(se, pr, 0, rv), but pushes a scope and sets a local "this" variable to the self value. s2_ptoken_is_true_squiggly(&pr->token) MUST be true: this function assert()s it (only to simplify skip-mode handling, though we could extend it to handle other block-level constructs as well). ACHTUNG: self must not be a temporary value: it MUST have a ref or this will kill it. Exception: in skip-mode, self is not evaluated. */ static int s2_eval_current_sub_with_this( s2_engine * se, s2_ptoker * pr, cwal_value * self, cwal_value **rv ){ assert( s2_ptoken_is_true_squiggly(&pr->token) ); if(se->skipLevel){ if(rv) *rv = cwal_value_undefined(); return 0; }else{ s2_scope sc = s2_scope_empty; cwal_value * xrv = 0; int rc = s2_scope_push(se, &sc); if(rc) return rc; rc = s2_var_decl_v(se, se->cache.keyThis, self, 0); if(!rc){ rc = s2_eval_current_sub(se, pr, 0, rv ? &xrv : NULL); } s2_scope_pop2(se, rc ? 0 : xrv); if(!rc && rv) *rv = xrv /* will be NULL on an empty expr except in skip-mode */; /* TODO: centralize this handling somewhere else? We should probably add it to object/array literals, etc. */ if(rc){ s2_keyword const * kword = 0; switch(rc){ case CWAL_RC_RETURN: kword = s2_ttype_keyword(S2_T_KeywordReturn); assert(kword); s2_propagating_set(se, 0); break; case CWAL_RC_BREAK: kword = s2_ttype_keyword(S2_T_KeywordBreak); assert(kword); s2_propagating_set(se, 0); break; case CWAL_RC_CONTINUE: kword = s2_ttype_keyword(S2_T_KeywordContinue); assert(kword); break; default: break; } if(kword){ rc = s2_err_ptoker(se, pr, CWAL_SCR_SYNTAX, /* if we pass on the same rc, error reporting won't DTRT. */ "Unhandled '%s' in script block.", kword->word); } } return rc; } } int s2_eval_expr( s2_engine * se, s2_ptoker * st, int evalFlags, cwal_value ** rv){ return s2_eval_expr_impl(se, st, 0, evalFlags, rv); } /** Expects pr to be a comma-separated list of expressions, until its EOF. Empty expressions and a stray trailing comma are not allowed. Evaluates each token and appends it to dest. Returns 0 on success. Some errors are thrown as exceptions, but syntax errors are not and propagated errors might not be exceptions. */ static int s2_eval_to_array( s2_engine * se, s2_ptoker * pr, cwal_array * dest ){ int rc = 0; s2_op const * opComma = s2_ttype_op(S2_T_Comma); s2_ptoken prev = s2_ptoken_empty; char const * errMsg = 0; assert(!se->skipLevel); /* s2_dotop_state(se, 0, 0, 0); */ while( !rc ){ s2_ptoken next = s2_ptoken_empty; cwal_value * v = 0; if( (rc = s2_eval_expr_impl( se, pr, opComma, 0, &v)) ) break; if(!v){ if(s2_ptoker_is_eof(pr)){ if(S2_T_Comma==prev.ttype){ |
︙ | ︙ | |||
26908 26909 26910 26911 26912 26913 26914 | cwal_value * fv = 0; cwal_value * vSelf = 0; s2_scope _SCOPE = s2_scope_empty; s2_scope * scope = &_SCOPE; s2_strace_entry strace = s2_strace_entry_empty; cwal_function * theFunc; s2_func_state * fst = 0; | < | | 27204 27205 27206 27207 27208 27209 27210 27211 27212 27213 27214 27215 27216 27217 27218 27219 27220 27221 27222 27223 27224 27225 27226 | cwal_value * fv = 0; cwal_value * vSelf = 0; s2_scope _SCOPE = s2_scope_empty; s2_scope * scope = &_SCOPE; s2_strace_entry strace = s2_strace_entry_empty; cwal_function * theFunc; s2_func_state * fst = 0; /* cwal_value * vKey; */ assert(S2_T_ParenGroup==pr->token.ttype); if(!se->skipLevel){ rc = s2_scope_push(se, scope); if(rc) return rc; } if(rv) *rv = 0; /* Check if this is a FUNC() or OBJ.FUNC() call... */ opTok = s2_engine_peek_op(se); op = opTok ? s2_ttype_op( opTok->ttype ) : 0; /* To consider: if dot is not a dot op but se->dotOpLhs is set, then some LHS (possibly a (subexpr)) possibly |
︙ | ︙ | |||
26971 26972 26973 26974 26975 26976 26977 | assignment ops as well, so that (x.y)=3 could work. */ /* MARKER(("Possibly stealing a 'this'\n")); */ assert(!fv); assert(!vSelf); vSelf = se->dotOpSelf; /* s2_dump_val(vSelf, "se->dotOpThis"); */ | | < > | | 27266 27267 27268 27269 27270 27271 27272 27273 27274 27275 27276 27277 27278 27279 27280 27281 27282 27283 27284 27285 27286 27287 27288 27289 27290 27291 27292 27293 | assignment ops as well, so that (x.y)=3 could work. */ /* MARKER(("Possibly stealing a 'this'\n")); */ assert(!fv); assert(!vSelf); vSelf = se->dotOpSelf; /* s2_dump_val(vSelf, "se->dotOpThis"); */ if(vSelf) cwal_value_ref(vSelf); fv = s2_engine_pop_value(se) /* presumably a dot-op result */; assert(fv); cwal_value_ref( fv ); }else{ fv = s2_engine_pop_value(se) /* hopefully a function */; cwal_value_ref( fv ); } s2_dotop_state(se, 0, 0, 0); /* In skip mode, we're done. We had to get the values off the stack, though, so we couldn't do this first. */ if(se->skipLevel>0){ if(rv) *rv = cwal_value_undefined(); goto end; } rc = s2_strace_push_pos(se, pr, origin.begin, &strace ) /* we have to do this fairly late so that the the (still pending) call doesn't confuse the the trace. */ |
︙ | ︙ | |||
27016 27017 27018 27019 27020 27021 27022 | if(fst && (fst->flags & S2_FUNCSTATE_F_EMPTY_BODY && fst->flags & S2_FUNCSTATE_F_EMPTY_PARAMS)){ /* If a script function has neither parameters nor a body, we don't have to do any of the following work. However, in order to get fst, we have to get theFunc, which requires setting up a scope and all that. */ | | | 27311 27312 27313 27314 27315 27316 27317 27318 27319 27320 27321 27322 27323 27324 27325 | if(fst && (fst->flags & S2_FUNCSTATE_F_EMPTY_BODY && fst->flags & S2_FUNCSTATE_F_EMPTY_PARAMS)){ /* If a script function has neither parameters nor a body, we don't have to do any of the following work. However, in order to get fst, we have to get theFunc, which requires setting up a scope and all that. */ if(rv) *rv = cwal_value_undefined(); }else{ /* Process the args and call() the func... */ s2_ptoker sub = s2_ptoker_empty; cwal_value * arV = 0; cwal_array * oldArgV; s2_func_state const * oldScriptFunc = se->currentScriptFunc; cwal_array * ar = cwal_new_array(se->e); |
︙ | ︙ | |||
27081 27082 27083 27084 27085 27086 27087 | use/abuse it in the docs. */; se->currentScriptFunc = oldScriptFunc; assert(!se->callArgV && "Gets unset via the post-call() hook"); se->callArgV = oldArgV; /* assert(0==oldArgV); */ cwal_value_make_vacuum_proof(arV, 0); | > | > | < < < < > | > | | > > > | | | 27376 27377 27378 27379 27380 27381 27382 27383 27384 27385 27386 27387 27388 27389 27390 27391 27392 27393 27394 27395 27396 27397 27398 27399 27400 27401 27402 27403 27404 27405 27406 27407 27408 27409 27410 27411 27412 27413 27414 27415 27416 27417 27418 27419 27420 27421 27422 27423 27424 27425 27426 27427 27428 27429 27430 27431 27432 | use/abuse it in the docs. */; se->currentScriptFunc = oldScriptFunc; assert(!se->callArgV && "Gets unset via the post-call() hook"); se->callArgV = oldArgV; /* assert(0==oldArgV); */ cwal_value_make_vacuum_proof(arV, 0); if(!rc && rv && *rv){ cwal_value_ref(*rv); } cwal_value_unref(arV); } end: /* s2_dotop_state( se, 0, 0, 0 ); */ rc = s2_check_interrupted(se, rc); switch(rc){ case 0: if( rv && !*rv ) *rv = cwal_value_undefined(); break; case CWAL_RC_BREAK: case CWAL_RC_CONTINUE: assert(se->err.code); rc = s2_throw_err(se, 0, s2_ptoker_name_first(pr, 0), 0, 0); break; #if 0 case CWAL_RC_RETURN: rc = 0; if(rv){ *rv = s2_propagating_take(se); assert(*rv); cwal_value_ref(*rv); } else cwal_propagating_set(se, NULL); break; #endif case CWAL_RC_EXCEPTION: s2_exception_add_script_props(se, pr) /* Needed to decorate calls to native functions. */; /* fall through */ case CWAL_RC_OOM: case CWAL_RC_EXIT: case CWAL_RC_FATAL: case CWAL_RC_INTERRUPTED: case CWAL_RC_ASSERT: /* do we want assertion errors to translate to exceptions if they go up the call stack? */ if(rv) *rv = 0; break; default: if(rv) *rv = 0; if(se->err.code){ /* Likely a syntax-related error pending */ rc = s2_throw_err(se, 0, 0, 0, 0); }else{ #if 1 rc = s2_throw_ptoker(se, pr, rc, "Function call returned non-exception " |
︙ | ︙ | |||
27149 27150 27151 27152 27153 27154 27155 | #endif } break; } if(strace.pr){ s2_strace_pop(se); } | > > > > | | < < < | > > > > > > > > > > > > > > > > > > > > > > > > > > > | 27447 27448 27449 27450 27451 27452 27453 27454 27455 27456 27457 27458 27459 27460 27461 27462 27463 27464 27465 27466 27467 27468 27469 27470 27471 27472 27473 27474 27475 27476 27477 27478 27479 27480 27481 27482 27483 27484 27485 27486 27487 27488 27489 27490 27491 27492 27493 27494 27495 27496 27497 27498 27499 27500 27501 | #endif } break; } if(strace.pr){ s2_strace_pop(se); } if(!rc && rv && *rv){ assert(cwal_value_refcount(*rv)>0 /* we ref'd it above */ || cwal_value_is_builtin(*rv)); } if(vSelf) cwal_value_unref(vSelf); if(fv) cwal_value_unref(fv); if(scope->parent){ assert(scope == se->currentScope); s2_scope_pop2(se, rc ? 0 : (rv ? *rv : 0)); assert(scope != se->currentScope); } if(!rc && rv && *rv){ assert(cwal_value_refcount(*rv)>0 /* we ref'd it above */ || cwal_value_is_builtin(*rv)); cwal_value_unhand(*rv); } return rc; } /** If true, s2_eval_expr_impl() internally uses a local array to keep references active and vacuum-proofed. HOLY COW... when recycling is disabled, this causes alloc counts and total (not peak) memory to skyrocket (nearly 60% increase in the 20160131 unit tests). With recycling on alloc counts go up by roughly 3% but peak memory goes up anywhere from 1k to 7k (as the recycling bins accumulate) in those same unit tests. After changing this, MAKE SURE to run all the valgrind tests with various combinations of recycling and string interning!!! */ #define EVAL_USE_HOLDER 0 #if EVAL_USE_HOLDER static int s2_eval_hold(s2_engine * se, cwal_array * tgt, cwal_value * v){ return cwal_value_is_builtin(v) ? 0 : cwal_array_append(tgt, v); } #endif /** Internal impl of s2_eval_expr(). If fromLhsOp is not 0, this call is assumed to be the RHS of that operator. Upon encountering an operator of that precedence or less, that operator is put back into the tokenizer and evaluation |
︙ | ︙ | |||
27213 27214 27215 27216 27217 27218 27219 27220 27221 27222 27223 27224 27225 | int totalValCount = 0 /* just for some error checks */; int nextTokenFlags = /* The s2_next_token() flags for the very next token */ (evalFlags & S2_EVAL_NO_SKIP_FIRST_EOL/* fromLhsOp && S2_T_RHSEvalNoEOL!=fromLhsOp->id */) ? S2_NEXT_NO_SKIP_EOL : 0; s2_scope _SCOPE = s2_scope_empty /* cwal stack, if (flags&S2_EVAL_PUSH_SCOPE) */; s2_scope * scope = &_SCOPE; #ifndef NDEBUG /* Just for sanity checking */ int const oldValCount = se->st.vals.size; int const oldOpCount = se->st.ops.size; #endif if( se->flags.interrupted ) return se->flags.interrupted; | > > > > | | 27539 27540 27541 27542 27543 27544 27545 27546 27547 27548 27549 27550 27551 27552 27553 27554 27555 27556 27557 27558 27559 27560 27561 27562 27563 | int totalValCount = 0 /* just for some error checks */; int nextTokenFlags = /* The s2_next_token() flags for the very next token */ (evalFlags & S2_EVAL_NO_SKIP_FIRST_EOL/* fromLhsOp && S2_T_RHSEvalNoEOL!=fromLhsOp->id */) ? S2_NEXT_NO_SKIP_EOL : 0; s2_scope _SCOPE = s2_scope_empty /* cwal stack, if (flags&S2_EVAL_PUSH_SCOPE) */; s2_scope * scope = &_SCOPE; #if EVAL_USE_HOLDER cwal_array * holder = 0 /* holds pending expression values to keep them referenced and vacuum-safe. */; #endif #ifndef NDEBUG /* Just for sanity checking */ int const oldValCount = se->st.vals.size; int const oldOpCount = se->st.ops.size; #endif if( se->flags.interrupted ) return se->flags.interrupted; else if(!fromLhsOp) s2_dotop_state(se, 0, 0, 0); if(S2_EVAL_PUSH_SCOPE & evalFlags){ MARKER(("Oh, this scope-pushing bit in eval_expr_impl IS used.\n")); assert(!"This isn't used, is it?"); rc = s2_scope_push(se, scope); if(rc) return rc; assert(scope->parent); assert(0==se->sguard->sweep); |
︙ | ︙ | |||
27241 27242 27243 27244 27245 27246 27247 27248 27249 27250 27251 27252 27253 27254 | if(++se->metrics.subexpDepth > se->metrics.peakSubexpDepth){ se->metrics.peakSubexpDepth = se->metrics.subexpDepth; } st->errPos = 0; /* if(rv) *rv = 0; */ if((S2_EVAL_PRE_SWEEP & evalFlags) && !fromLhsOp && !se->st.vals.size && !se->st.ops.size ){ /* MARKER(("SWEEPING from eval_expr_impl\n")); */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 27571 27572 27573 27574 27575 27576 27577 27578 27579 27580 27581 27582 27583 27584 27585 27586 27587 27588 27589 27590 27591 27592 27593 27594 27595 27596 27597 27598 27599 27600 27601 27602 27603 27604 27605 27606 27607 27608 27609 27610 27611 27612 27613 | if(++se->metrics.subexpDepth > se->metrics.peakSubexpDepth){ se->metrics.peakSubexpDepth = se->metrics.subexpDepth; } st->errPos = 0; #if EVAL_USE_HOLDER #define eval_hold(V) if( holder && (rc = s2_eval_hold(se, holder, (V)))) goto end #else #define eval_hold(V) (void)0 #endif #if EVAL_USE_HOLDER /** Reminder to self: we have to explicitly ref/unhand se->dotOpSelf/dotOpLhs/dotOpKey to keep them alive (i.e. to keep holder from cleaning them up) after this op returns (needed by 'unset' and possibly others). */ holder = cwal_new_array(se->e); if(!holder){ rc = CWAL_RC_OOM; goto end; }else{ cwal_value * hv = cwal_array_value(holder); /* ++se->sguard->vacuum; */ cwal_value_rescope(&se->currentScope->scope, hv) /* in case a cwal-level API has pushed a scope without us knowing */; cwal_value_ref(hv); cwal_value_make_vacuum_proof(hv,1); } #endif /* ^^^^ EVAL_USE_HOLDER */ /* if(rv) *rv = 0; */ if((S2_EVAL_PRE_SWEEP & evalFlags) && !fromLhsOp && !se->st.vals.size && !se->st.ops.size ){ /* MARKER(("SWEEPING from eval_expr_impl\n")); */ |
︙ | ︙ | |||
27424 27425 27426 27427 27428 27429 27430 27431 27432 27433 27434 27435 27436 27437 | break; } lhs = 0; rc = s2_eval_ternary(se, st, &lhs); if(rc) break; else{ assert(lhs); continue; } } case S2_T_Identifier:{ /* If an Identifier is the RHS of a dot operator, change its type to PropertyKey so that identifier expansion is not done for this property access. The raw token bytes | > | 27783 27784 27785 27786 27787 27788 27789 27790 27791 27792 27793 27794 27795 27796 27797 | break; } lhs = 0; rc = s2_eval_ternary(se, st, &lhs); if(rc) break; else{ assert(lhs); eval_hold(lhs); continue; } } case S2_T_Identifier:{ /* If an Identifier is the RHS of a dot operator, change its type to PropertyKey so that identifier expansion is not done for this property access. The raw token bytes |
︙ | ︙ | |||
27483 27484 27485 27486 27487 27488 27489 | break; } if(se->flags.interrupted && !rc) rc = se->flags.interrupted; if(rc || doBreak) break; op = s2_ttype_op( pt.ttype ); if(op && !fromLhsOp){ | | | 27843 27844 27845 27846 27847 27848 27849 27850 27851 27852 27853 27854 27855 27856 27857 | break; } if(se->flags.interrupted && !rc) rc = se->flags.interrupted; if(rc || doBreak) break; op = s2_ttype_op( pt.ttype ); if(op && !fromLhsOp){ s2_dotop_state( se, 0, 0, 0 ) /* If these get stale, Very Bad Things happen in the cwal core (assertions, if we're lucky). */; /* se->dotOpId = 0 */ /* keep Other Bad Things from happening */; /* Reminder: this means that assignment ops cannot tell which dot-like op triggered them. */ } |
︙ | ︙ | |||
27717 27718 27719 27720 27721 27722 27723 27724 27725 27726 27727 27728 27729 27730 | if(S2_T_OpOr3 != pt.ttype && S2_T_OpElvis != pt.ttype){ /* Clean this up: s2> x = 0; for( var i = 0; i < 100; (i++, x++ || 1, ++i) ); MARKER: s2.c:296:s2_engine_sweep(): Swept up 48 value(s) in sweep mode */ cwal_refunref(lhs); } continue; } }/*if(shortIt)*/ break; }/* end &&, ||, ||| */ case S2_T_Identifier:{ | > > | 28077 28078 28079 28080 28081 28082 28083 28084 28085 28086 28087 28088 28089 28090 28091 28092 | if(S2_T_OpOr3 != pt.ttype && S2_T_OpElvis != pt.ttype){ /* Clean this up: s2> x = 0; for( var i = 0; i < 100; (i++, x++ || 1, ++i) ); MARKER: s2.c:296:s2_engine_sweep(): Swept up 48 value(s) in sweep mode */ cwal_refunref(lhs); }else{ eval_hold(lhs); } continue; } }/*if(shortIt)*/ break; }/* end &&, ||, ||| */ case S2_T_Identifier:{ |
︙ | ︙ | |||
27741 27742 27743 27744 27745 27746 27747 27748 27749 27750 27751 27752 27753 27754 | s2_op const * kOp = s2_ttype_op(kword->id); assert(kOp); pt.ttype = kword->id; op = kOp; }else{ pt.ttype = st->token.ttype = kword->id; rc = kword->call(kword, se, st, &tVal); rc = s2_check_interrupted(se, rc); if(!rc && !tVal){ st->errPos = pt.begin; rc = s2_err_ptoker(se, st, CWAL_RC_ASSERT, "Keyword '%s' eval'd to <NULL>, " "which is currently verboten", kword->word); | > | 28103 28104 28105 28106 28107 28108 28109 28110 28111 28112 28113 28114 28115 28116 28117 | s2_op const * kOp = s2_ttype_op(kword->id); assert(kOp); pt.ttype = kword->id; op = kOp; }else{ pt.ttype = st->token.ttype = kword->id; rc = kword->call(kword, se, st, &tVal); s2_dotop_state( se, 0, 0, 0 ); rc = s2_check_interrupted(se, rc); if(!rc && !tVal){ st->errPos = pt.begin; rc = s2_err_ptoker(se, st, CWAL_RC_ASSERT, "Keyword '%s' eval'd to <NULL>, " "which is currently verboten", kword->word); |
︙ | ︙ | |||
27818 27819 27820 27821 27822 27823 27824 | rc = s2_throw_ptoker(se, st, CWAL_RC_NOT_FOUND, "Could not resolve identifier " "'%.*s'", tlen, pt.begin); } }else if(prevOp && s2_ttype_is_identifier_prefix(prevOp->id)){ /* Previous token was prefix ++/-- (or similar) */ | < | > | < < < < < < < < < < | 28181 28182 28183 28184 28185 28186 28187 28188 28189 28190 28191 28192 28193 28194 28195 28196 28197 28198 28199 28200 28201 28202 28203 | rc = s2_throw_ptoker(se, st, CWAL_RC_NOT_FOUND, "Could not resolve identifier " "'%.*s'", tlen, pt.begin); } }else if(prevOp && s2_ttype_is_identifier_prefix(prevOp->id)){ /* Previous token was prefix ++/-- (or similar) */ if(!s2_next_is_dotish(se, st)){ rc = s2_ptoken_create_value(se, &pt, &tVal); if(!tVal){ assert(rc); /* rc = CWAL_RC_OOM; */ } }else{ pt.ttype = S2_T_Value; } }else if(s2_next_wants_identifier(se, st)){ /* Required so that assignment gets the identifier's string value, but we let it get validated above so that we get precise error location info. We just hope that pending ops don't invalidate it (potential corner case?). */ tVal = 0; |
︙ | ︙ | |||
28018 28019 28020 28021 28022 28023 28024 28025 28026 28027 28028 28029 28030 28031 28032 28033 28034 28035 | break; } #endif assert(pt.adjBegin); assert(pt.adjEnd); assert(pt.adjEnd >= pt.adjBegin); if(S2_T_ParenGroup==pt.ttype){ if(s2_looks_like_fcall(se, st, (S2_EVAL_STOP_AT_CALL & evalFlags), prevOp, &rc) && !rc){ if(S2_EVAL_STOP_AT_CALL & evalFlags){ doBreak = 1; }else{ /* MARKER(("Looks like func call? rc=%s prevOp=%s\n", s2_rc_cstr(rc), prevOp?prevOp->sym:"<NULL>")); */ rc = s2_eval_fcall(se, st, &tVal); } break; | > > | | 28371 28372 28373 28374 28375 28376 28377 28378 28379 28380 28381 28382 28383 28384 28385 28386 28387 28388 28389 28390 28391 28392 28393 28394 28395 28396 28397 28398 | break; } #endif assert(pt.adjBegin); assert(pt.adjEnd); assert(pt.adjEnd >= pt.adjBegin); if(S2_T_ParenGroup==pt.ttype){ doBreak = 0; if(s2_looks_like_fcall(se, st, (S2_EVAL_STOP_AT_CALL & evalFlags), prevOp, &rc) && !rc){ if(S2_EVAL_STOP_AT_CALL & evalFlags){ doBreak = 1; }else{ /* MARKER(("Looks like func call? rc=%s prevOp=%s\n", s2_rc_cstr(rc), prevOp?prevOp->sym:"<NULL>")); */ rc = s2_eval_fcall(se, st, &tVal); } break; } else if(rc) break; } if(pt.adjEnd > pt.adjBegin){ /* In order to know whether it's really empty, and fail consistently across both skipping and non-skipping mode, we have to parse the subexpr regardless of skip level :/. */ |
︙ | ︙ | |||
28296 28297 28298 28299 28300 28301 28302 28303 28304 28305 28306 28307 28308 28309 28310 28311 28312 28313 | if((se->flags.traceStack>0) && (S2_T_Identifier==pt.ttype)){ MARKER(("Identifier token: %.*s\n", tlen, pt.begin)); } vtok = s2_engine_push_tv(se, pt.ttype, tVal); if(!vtok){ rc = CWAL_RC_OOM; }else{ ++totalValCount; vtok->srcPos = pt.begin; if(se->skipLevel>0){ #if 1 /* s2_dump_val(tVal, "what is this"); */ assert((tVal == cwal_value_undefined()) && "current internal convention for " "skip-mode evaluation was violated"); #endif } } | > | | 28651 28652 28653 28654 28655 28656 28657 28658 28659 28660 28661 28662 28663 28664 28665 28666 28667 28668 28669 28670 28671 28672 28673 28674 28675 28676 28677 | if((se->flags.traceStack>0) && (S2_T_Identifier==pt.ttype)){ MARKER(("Identifier token: %.*s\n", tlen, pt.begin)); } vtok = s2_engine_push_tv(se, pt.ttype, tVal); if(!vtok){ rc = CWAL_RC_OOM; }else{ eval_hold(tVal); ++totalValCount; vtok->srcPos = pt.begin; if(se->skipLevel>0){ #if 1 /* s2_dump_val(tVal, "what is this"); */ assert((tVal == cwal_value_undefined()) && "current internal convention for " "skip-mode evaluation was violated"); #endif } } }/*if(!rc)*/ }/*if op else value */ }/* for-each token */ if(rc && !st->errPos){ st->errPos = (pt.begin && (pt.begin != pt.end)) ? pt.begin : prevTok.begin; }else if(!rc){ assert(capBegin); |
︙ | ︙ | |||
28393 28394 28395 28396 28397 28398 28399 28400 28401 28402 28403 28404 28405 28406 28407 28408 | s2_dump_val(xrv, "eval_expr result"); } if(rv) *rv = xrv; else cwal_refunref(xrv); } end: if(rc){ rc= 1 ? rc : 0 /* put breakpoint here (the ?: is to avoid assignment-to-self warning from clang).*/; } /* Clean up... */ if(!fromLhsOp){ /* We must clear these avoid picking them up after they're stale. However, they's needed by, e.g. (unset x.y). */ | > | > > > > > > > > > > > > > > > > > > > > > | 28749 28750 28751 28752 28753 28754 28755 28756 28757 28758 28759 28760 28761 28762 28763 28764 28765 28766 28767 28768 28769 28770 28771 28772 28773 28774 28775 28776 28777 28778 28779 28780 28781 28782 28783 28784 28785 28786 28787 28788 28789 28790 28791 28792 28793 28794 28795 28796 28797 28798 28799 28800 28801 28802 28803 | s2_dump_val(xrv, "eval_expr result"); } if(rv) *rv = xrv; else cwal_refunref(xrv); } end: #undef eval_hold if(rc){ rc= 1 ? rc : 0 /* put breakpoint here (the ?: is to avoid assignment-to-self warning from clang).*/; } /* Clean up... */ if(!fromLhsOp){ /* We must clear these avoid picking them up after they're stale. However, they's needed by, e.g. (unset x.y). */ s2_dotop_state( se, 0, 0, 0 ); } if(rc && !se->err.code && st->errMsg && (CWAL_RC_EXCEPTION!=rc)){ /* Error from the tokenizer. */ rc = s2_err_ptoker(se, st, rc, 0); } rc = s2_rv_maybe_accept(se, scope->scope.parent /* 0 is okay */, rc, rv); #if EVAL_USE_HOLDER if(holder){ cwal_value * hv = cwal_array_value(holder); /* --se->sguard->vacuum; */ cwal_value_make_vacuum_proof(hv, 0); assert(1==cwal_value_refcount(hv)); if(!rc && rv) cwal_value_ref(*rv); if(se->dotOpSelf) cwal_value_ref(se->dotOpSelf); if(se->dotOpLhs) cwal_value_ref(se->dotOpLhs); if(se->dotOpKey) cwal_value_ref(se->dotOpKey); cwal_value_unref(hv); holder = 0; if(!rc && rv) cwal_value_unhand(*rv); if(se->dotOpSelf) cwal_value_unhand(se->dotOpSelf); if(se->dotOpLhs) cwal_value_unhand(se->dotOpLhs); if(se->dotOpKey) cwal_value_unhand(se->dotOpKey); } #endif /* ^^^^ EVAL_USE_HOLDER */ if(!evalIt){ assert(se->skipLevel==1+oldSkipLevel); se->skipLevel = oldSkipLevel; } if(ownStack){ s2_engine_stack_swap(se, &priorStack); s2_estack_clear(se, &priorStack, 1); |
︙ | ︙ | |||
28444 28445 28446 28447 28448 28449 28450 28451 28452 28453 28454 28455 28456 28457 | }else{ if(!scope->parent){ --se->sguard->sweep; } } return rc; } int s2_eval_buffer( s2_engine * se, char newScope, char const * name, cwal_buffer const * buf, cwal_value **rv ){ return s2_eval_cstr( se, newScope, name, | > > | 28822 28823 28824 28825 28826 28827 28828 28829 28830 28831 28832 28833 28834 28835 28836 28837 | }else{ if(!scope->parent){ --se->sguard->sweep; } } return rc; } #undef EVAL_USE_HOLDER int s2_eval_buffer( s2_engine * se, char newScope, char const * name, cwal_buffer const * buf, cwal_value **rv ){ return s2_eval_cstr( se, newScope, name, |
︙ | ︙ | |||
29666 29667 29668 29669 29670 29671 29672 | else if(!se->skipLevel){ if(!se->dotOpLhs || !se->dotOpKey){ pr->errPos = ident.begin; return s2_throw_ptoker( se, pr, CWAL_SCR_SYNTAX, "Illegal RHS for %s operation.", kw->word); } | | | | | | | > > | 30046 30047 30048 30049 30050 30051 30052 30053 30054 30055 30056 30057 30058 30059 30060 30061 30062 30063 30064 30065 30066 30067 30068 | else if(!se->skipLevel){ if(!se->dotOpLhs || !se->dotOpKey){ pr->errPos = ident.begin; return s2_throw_ptoker( se, pr, CWAL_SCR_SYNTAX, "Illegal RHS for %s operation.", kw->word); } /* cwal_value_ref(se->dotOpLhs); */ /* cwal_value_ref(se->dotOpKey); */ /* Do we want to support: unset hash # key? */ rc = s2_handle_set_result(se, pr, s2_set_v( se, se->dotOpLhs, se->dotOpKey, 0 )); /* cwal_value_unhand(se->dotOpLhs); */ /* cwal_value_unhand(se->dotOpKey); */ s2_dotop_state(se, 0, 0, 0); if(rc) return rc; } if(s2_ptoker_next_is_ttype(se, pr, 0, S2_T_Comma, 1)){ goto next_part; } break; } default: |
︙ | ︙ | |||
30754 30755 30756 30757 30758 30759 30760 30761 30762 30763 30764 30765 30766 30767 | */ s2_engine * se = s2_engine_from_state(args->engine); se->callArgV = 0 /* Make sure this doesn't propagate through to a script func that this native function calls. Been there, debugged that! */; /* MARKER(("Not a script function (or empty function). Not injecting argv/this.\n")); */ return 0; } #if 0 else if(cwal_scope_search(args->scope, 0, "argv", 4, NULL)){ /* argv is already set. This is (we hope) a callback which itself passed on a call via cwal_function_call_in_scope(). Do we have a better mechanism for avoiding a duplicate init in that case? | > | 31136 31137 31138 31139 31140 31141 31142 31143 31144 31145 31146 31147 31148 31149 31150 | */ s2_engine * se = s2_engine_from_state(args->engine); se->callArgV = 0 /* Make sure this doesn't propagate through to a script func that this native function calls. Been there, debugged that! */; /* MARKER(("Not a script function (or empty function). Not injecting argv/this.\n")); */ s2_dotop_state( se, 0, 0, 0 ) /* necessary!!! */; return 0; } #if 0 else if(cwal_scope_search(args->scope, 0, "argv", 4, NULL)){ /* argv is already set. This is (we hope) a callback which itself passed on a call via cwal_function_call_in_scope(). Do we have a better mechanism for avoiding a duplicate init in that case? |
︙ | ︙ | |||
30780 30781 30782 30783 30784 30785 30786 30787 30788 30789 30790 30791 30792 30793 | cwal_scope * s = args->scope; s2_engine * se = fs ? fs->se : s2_engine_from_state(args->engine); cwal_value * v; assert(fs && "Currently always true here."); assert(se); calleeV = cwal_function_value(args->callee); assert(calleeV); if(!fs /* native call, which _might_ eval script code */ || !(/* empty function */ fs->flags & S2_FUNCSTATE_F_EMPTY_BODY && fs->flags & S2_FUNCSTATE_F_EMPTY_PARAMS) ){ | > > | 31163 31164 31165 31166 31167 31168 31169 31170 31171 31172 31173 31174 31175 31176 31177 31178 | cwal_scope * s = args->scope; s2_engine * se = fs ? fs->se : s2_engine_from_state(args->engine); cwal_value * v; assert(fs && "Currently always true here."); assert(se); calleeV = cwal_function_value(args->callee); assert(calleeV); s2_dotop_state( se, 0, 0, 0 ) /* necessary!!! */; if(!fs /* native call, which _might_ eval script code */ || !(/* empty function */ fs->flags & S2_FUNCSTATE_F_EMPTY_BODY && fs->flags & S2_FUNCSTATE_F_EMPTY_PARAMS) ){ |
︙ | ︙ | |||
30873 30874 30875 30876 30877 30878 30879 | /* s2_func_state * fs = (s2_func_state *)cwal_args_callee_state(args, &s2_func_state_empty); */ assert(se); /* MARKER(("Callback post-hook\n")); */ /* s2_dump_val(cwal_array_value(se->callArgV), "se->callArgV"); */ se->callArgV = 0 /* required for certain calling combinations of native vs script funcs to work. */; | < | 31258 31259 31260 31261 31262 31263 31264 31265 31266 31267 31268 31269 31270 31271 | /* s2_func_state * fs = (s2_func_state *)cwal_args_callee_state(args, &s2_func_state_empty); */ assert(se); /* MARKER(("Callback post-hook\n")); */ /* s2_dump_val(cwal_array_value(se->callArgV), "se->callArgV"); */ se->callArgV = 0 /* required for certain calling combinations of native vs script funcs to work. */; /** Reminder to self: We can potentially use this callback to communicate certain non-zero results back up the call chain, e.g. CWAL_RC_OOM could be stuffed into a dedicated error code propagation slot (the plan is to consolidate return/exit/etc. with the |
︙ | ︙ | |||
31142 31143 31144 31145 31146 31147 31148 | if(!rc){ cwal_value * ctorResult = 0 /* the ctor result */; cwal_array * oldArgV = se->callArgV /* not _actually_ sure this is needed, but there might be a corner case or two without it. */; se->callArgV = args; if(args) cwal_value_ref(cwal_array_value(args)); | < < | < < < < | | 31526 31527 31528 31529 31530 31531 31532 31533 31534 31535 31536 31537 31538 31539 31540 31541 31542 31543 31544 31545 31546 31547 | if(!rc){ cwal_value * ctorResult = 0 /* the ctor result */; cwal_array * oldArgV = se->callArgV /* not _actually_ sure this is needed, but there might be a corner case or two without it. */; se->callArgV = args; if(args) cwal_value_ref(cwal_array_value(args)); sc.newingThis = newThis; rc = args ? cwal_function_call_array(&sc.scope, ctor, newThis, &ctorResult, args) : cwal_function_call_in_scope(&sc.scope, ctor, newThis, &ctorResult, 0, NULL) ; sc.newingThis = 0; assert(!se->callArgV && "callArgV Gets unset via the call() hook(s)"); se->callArgV = oldArgV; if(args) cwal_value_unhand(cwal_array_value(args)); if(!rc && ctorResult && newThis != ctorResult && cwal_value_undefined() != ctorResult){ /* |
︙ | ︙ | |||
31212 31213 31214 31215 31216 31217 31218 31219 31220 31221 31222 31223 31224 31225 31226 31227 | s2_ptoken tIdent = s2_ptoken_empty; cwal_size_t idLen; cwal_value * operand = 0; cwal_function * ctor = 0; cwal_array * args = 0; cwal_value * vargs = 0; s2_ptoker ptArgs = s2_ptoker_empty; s2_strace_entry strace = s2_strace_entry_empty; s2_ptoken const origin = pr->token; rc = s2_strace_push_pos(se, pr, origin.begin, &strace ) /* treat new() like a function for stack trace purposes or exceptions may contain far-off location info. */; if(rc) return rc /* after this, no more 'return', only goto end */; while(s2_is_space(*pr->token.end)){ /* Cosmetic workaround! */ | > > > > | 31590 31591 31592 31593 31594 31595 31596 31597 31598 31599 31600 31601 31602 31603 31604 31605 31606 31607 31608 31609 | s2_ptoken tIdent = s2_ptoken_empty; cwal_size_t idLen; cwal_value * operand = 0; cwal_function * ctor = 0; cwal_array * args = 0; cwal_value * vargs = 0; s2_ptoker ptArgs = s2_ptoker_empty; s2_ptoken tTail = s2_ptoken_empty; s2_ptoken tWithThis = s2_ptoken_empty; s2_strace_entry strace = s2_strace_entry_empty; s2_ptoken const origin = pr->token; cwal_value * xrv = 0; assert(rv); rc = s2_strace_push_pos(se, pr, origin.begin, &strace ) /* treat new() like a function for stack trace purposes or exceptions may contain far-off location info. */; if(rc) return rc /* after this, no more 'return', only goto end */; while(s2_is_space(*pr->token.end)){ /* Cosmetic workaround! */ |
︙ | ︙ | |||
31235 31236 31237 31238 31239 31240 31241 31242 31243 31244 31245 31246 31247 31248 31249 | else if(operand) cwal_value_ref(operand); if(!operand || S2_T_ParenGroup!=pr->token.ttype){ rc = s2_err_ptoker(se, pr, CWAL_SCR_SYNTAX, "Expecting EXPR(...) after '%s'.", kw->word); goto end; } tIdent = pr->capture; idLen = (cwal_size_t)(tIdent.end-tIdent.begin); #if 0 MARKER(("Capture=%.*s\n", (int)(pr->capture.end-pr->capture.begin), pr->capture.begin)); MARKER(("tIdent=%.*s\n", (int)idLen, tIdent.begin)); #endif if(se->skipLevel>0){ | > | | | 31617 31618 31619 31620 31621 31622 31623 31624 31625 31626 31627 31628 31629 31630 31631 31632 31633 31634 31635 31636 31637 31638 31639 31640 31641 | else if(operand) cwal_value_ref(operand); if(!operand || S2_T_ParenGroup!=pr->token.ttype){ rc = s2_err_ptoker(se, pr, CWAL_SCR_SYNTAX, "Expecting EXPR(...) after '%s'.", kw->word); goto end; } tTail = pr->token; tIdent = pr->capture; idLen = (cwal_size_t)(tIdent.end-tIdent.begin); #if 0 MARKER(("Capture=%.*s\n", (int)(pr->capture.end-pr->capture.begin), pr->capture.begin)); MARKER(("tIdent=%.*s\n", (int)idLen, tIdent.begin)); #endif if(se->skipLevel>0){ xrv = cwal_value_undefined(); goto check_tail; }else if(!cwal_props_can(operand)){ rc = s2_throw_ptoker(se, pr, CWAL_RC_EXCEPTION, "'%s' expects a container, " "but '%.*s' resolves to type '%s'.", kw->word, (int)idLen, tIdent.begin, cwal_value_type_name(operand)); goto end; |
︙ | ︙ | |||
31285 31286 31287 31288 31289 31290 31291 | /* cwal_value_ref(operand); */ s2_ptoker_sub_from_toker( &ptArgs, pr ); rc = s2_eval_to_array( se, &ptArgs, args ); /* cwal_value_unhand(operand); */ /* cwal_value_make_vacuum_proof(operand, 0); */ if(!rc){ /* s2_dump_val(vargs,"call args"); */ | | | > > > > > > > > > > > > > > > > > > > < | > > > | > > > | 31668 31669 31670 31671 31672 31673 31674 31675 31676 31677 31678 31679 31680 31681 31682 31683 31684 31685 31686 31687 31688 31689 31690 31691 31692 31693 31694 31695 31696 31697 31698 31699 31700 31701 31702 31703 31704 31705 31706 31707 31708 31709 31710 31711 31712 31713 31714 31715 31716 31717 31718 31719 31720 31721 31722 | /* cwal_value_ref(operand); */ s2_ptoker_sub_from_toker( &ptArgs, pr ); rc = s2_eval_to_array( se, &ptArgs, args ); /* cwal_value_unhand(operand); */ /* cwal_value_make_vacuum_proof(operand, 0); */ if(!rc){ /* s2_dump_val(vargs,"call args"); */ rc = s2_ctor_apply( se, operand, ctor, args, &xrv ); /* s2_dump_val(xrv, "result from 'new'"); */ } check_tail: if(rc){ assert(!xrv); }else{ if(xrv) cwal_value_ref(xrv); /* Check for a {body} part after the T(...), and treat it like an inlined extension to the ctor like in Java: new X() {{ ... }}. */ s2_next_token(se, pr, 0, &tWithThis); if(s2_ptoken_is_true_squiggly(&tWithThis)){ pr->token = tTail = tWithThis; /*MARKER(("Got post-new() body: %.*s\n", (int)(tTail.end-tTail.begin), tTail.begin));*/ if(!se->skipLevel){ rc = s2_eval_current_sub_with_this(se, pr, xrv, NULL); } } } end: if(strace.pr){ s2_strace_pop(se); } if(operand){ cwal_value_unref(operand); operand = 0; } if(vargs){ cwal_value_make_vacuum_proof(vargs, 0); cwal_value_unref(vargs); } if(!rc){ pr->token = tTail; *rv = xrv; cwal_value_unhand(xrv); }else if(xrv){ cwal_value_unref(xrv); } return rc; } int s2_keyword_f_enum( s2_keyword const * kw, s2_engine * se, s2_ptoker * pr, cwal_value **rv){ int rc; s2_ptoken tName = s2_ptoken_empty; |
︙ | ︙ | |||
31547 31548 31549 31550 31551 31552 31553 31554 31555 31556 31557 31558 31559 31560 31561 31562 31563 | cwal_container_client_flags_set(store, S2_VAL_F_ENUM); cwal_value_unhand(store); *rv = store; } return rc; } int s2_keyword_f_typeinfo( s2_keyword const * kw, s2_engine * se, s2_ptoker * pr, cwal_value **rv){ s2_ptoken tIdent = s2_ptoken_empty; s2_ptoker prBody = s2_ptoker_empty; s2_ptoker const * oldScript = se->currentScript; cwal_size_t idLen = 0; cwal_value * xrv = 0; int rc; int buul = -1 /* <0=unknown, 0=false, >0=true */; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > | < < < < | < < > | | < | > > > > > | < > > | 31954 31955 31956 31957 31958 31959 31960 31961 31962 31963 31964 31965 31966 31967 31968 31969 31970 31971 31972 31973 31974 31975 31976 31977 31978 31979 31980 31981 31982 31983 31984 31985 31986 31987 31988 31989 31990 31991 31992 31993 31994 31995 31996 31997 31998 31999 32000 32001 32002 32003 32004 32005 32006 32007 32008 32009 32010 32011 32012 32013 32014 32015 32016 32017 32018 32019 32020 32021 32022 32023 32024 32025 32026 32027 32028 32029 32030 32031 32032 32033 32034 32035 32036 32037 32038 32039 32040 32041 32042 32043 32044 32045 32046 32047 32048 32049 32050 32051 32052 32053 32054 32055 32056 32057 32058 32059 32060 32061 32062 32063 32064 32065 32066 32067 32068 32069 32070 32071 32072 32073 32074 32075 32076 32077 32078 32079 32080 32081 32082 32083 32084 32085 32086 32087 32088 32089 32090 32091 32092 32093 32094 32095 32096 32097 32098 32099 32100 32101 32102 32103 32104 32105 32106 32107 32108 32109 32110 32111 32112 32113 32114 32115 32116 32117 32118 32119 32120 32121 32122 32123 32124 32125 32126 32127 32128 32129 32130 32131 32132 32133 32134 32135 32136 32137 32138 32139 32140 32141 32142 32143 32144 32145 32146 32147 32148 32149 32150 32151 32152 32153 32154 32155 32156 32157 32158 32159 32160 32161 32162 32163 32164 32165 32166 32167 32168 32169 32170 32171 32172 32173 32174 32175 32176 32177 32178 32179 32180 32181 32182 32183 32184 32185 32186 32187 32188 32189 32190 32191 32192 32193 32194 32195 32196 | cwal_container_client_flags_set(store, S2_VAL_F_ENUM); cwal_value_unhand(store); *rv = store; } return rc; } /** Tag type IDs for typeinfo(TAG ...). */ enum s2_typeinfo_words { /* Sentinel value. Must be 0. */ TYPEINFO_NONE = 0, /** True if operand can be used as an operand for the "new" keyword. */ TYPEINFO_CANNEW, /** True if operand is or has an array in its prototype chain. */ TYPEINFO_HASARRAY, /** True if operand is or has an enum in its prototype chain. */ TYPEINFO_HASENUM, /** True if operand is or has an exception in its prototype chain. */ TYPEINFO_HASEXCEPTION, /** True if operand is or has a hash in its prototype chain. */ TYPEINFO_HASHASH, /** True if operand is or has a native in its prototype chain. */ TYPEINFO_HASNATIVE, /** True if operand is or has an Object in its prototype chain. */ TYPEINFO_HASOBJECT, /** True if operand has a prototype. */ TYPEINFO_HASPROTOYPE, /** True if operand is an array. */ TYPEINFO_ISARRAY, /** True if operand is a bool. */ TYPEINFO_ISBOOL, /** True if operand is a buffer. */ TYPEINFO_ISBUFFER, /** True if operand is callable (is a function or has a function in its prototype chain). */ TYPEINFO_ISCALLABLE, /** True if operand is a container (can hold its own properties). */ TYPEINFO_ISCONTAINER, /** True if operand is the name of a declared (currently in-scope) variable/const. */ TYPEINFO_ISDECLARED, /** True if operand is legal for use with the dot operator. */ TYPEINFO_ISDEREFABLE, /** True if operand is a double. */ TYPEINFO_ISDOUBLE, /** True if operand is an enum. */ TYPEINFO_ISENUM, /** True if operand is an exception. */ TYPEINFO_ISEXCEPTION, /** True if operand is a function. */ TYPEINFO_ISFUNCTION, /** True if operand is a hash. */ TYPEINFO_ISHASH, /** True if operand is an integer . */ TYPEINFO_ISINT, /** True if operand is a var/const declared in the local scope. */ TYPEINFO_ISLOCAL, /** True if operand is a native. */ TYPEINFO_ISNATIVE, /** True if the _current_ scope was started by the 'new' keyword. */ TYPEINFO_ISNEWING, /** True if operand is an integer or a double. */ TYPEINFO_ISNUMBER, /** True if operand is an integer, a double, a boolean, or a numeric-format string (one parseable by NumberPrototype.parseNumber()). */ TYPEINFO_ISNUMERIC, /** True if operand is an Object */ TYPEINFO_ISOBJECT, /** True if operand is a string. */ TYPEINFO_ISSTRING, /** True if operand is a Unique-type value. */ TYPEINFO_ISUNIQUE, /** Evaluates to the type's name (as as the typename keyword). */ TYPEINFO_NAME, /** Evaluates to the operand's refcount. */ TYPEINFO_REFCOUNT }; typedef struct { enum s2_typeinfo_words type; char const * word; cwal_size_t wordLen; /** Argument type: 0 = none >0 = expr <0 = identifier */ int argType; } s2_typeinfo_word; static const s2_typeinfo_word s2TypeInfoWords[] = { /* Keep these sorted by their 'word' member, as we do a binary search on that. */ { TYPEINFO_CANNEW, "cannew", 6, 1}, { TYPEINFO_HASARRAY, "hasarray", 8, 1}, { TYPEINFO_HASENUM, "hasenum", 7, 1}, { TYPEINFO_HASEXCEPTION,"hasexception", 12, 1}, { TYPEINFO_HASHASH, "hashash", 7, 1}, { TYPEINFO_HASNATIVE, "hasnative", 9, 1}, { TYPEINFO_HASOBJECT, "hasobject", 9, 1}, { TYPEINFO_HASPROTOYPE, "hasprototype", 12, 1}, { TYPEINFO_ISARRAY, "isarray", 7, 1}, { TYPEINFO_ISBOOL, "isbool", 6, 1}, { TYPEINFO_ISBUFFER, "isbuffer", 8, 1}, { TYPEINFO_ISCALLABLE, "iscallable", 10, 1}, { TYPEINFO_ISCONTAINER, "iscontainer", 11, 1}, { TYPEINFO_ISDECLARED, "isdeclared", 10, -1}, { TYPEINFO_ISDEREFABLE, "isderefable", 11, 1}, { TYPEINFO_ISDOUBLE, "isdouble", 8, 1}, { TYPEINFO_ISENUM, "isenum", 6, 1}, { TYPEINFO_ISEXCEPTION, "isexception", 11, 1}, { TYPEINFO_ISFUNCTION, "isfunction", 10, 1}, { TYPEINFO_ISHASH, "ishash", 6, 1}, { TYPEINFO_ISINT, "isinteger", 9, 1}, { TYPEINFO_ISLOCAL, "islocal", 7, -1}, { TYPEINFO_ISNATIVE, "isnative", 8, 1}, { TYPEINFO_ISNEWING, "isnewing", 8, 0}, { TYPEINFO_ISNUMBER, "isnumber", 8, 1}, { TYPEINFO_ISNUMERIC, "isnumeric", 9, 1}, { TYPEINFO_ISOBJECT, "isobject", 8, 1}, { TYPEINFO_ISSTRING, "isstring", 8, 1}, { TYPEINFO_ISUNIQUE, "isunique", 8, 1}, { TYPEINFO_NAME, "name", 4, 1}, { TYPEINFO_REFCOUNT, "refcount", 8, 1}, { TYPEINFO_NONE, 0, 0, 0}/* end-of-list sentinel: entries must be 0 */ }; /** Comparison func for bsearch(), comparing (s2_typeinfo_word *) key with (s2_typeinfo_word *) on s2_typeinfo_word::word. */ static int s2_typeinfo_cmp(void const * key, void const * kw){ s2_typeinfo_word const * k = ((s2_typeinfo_word const *)key); s2_typeinfo_word const * w = ((s2_typeinfo_word const *)kw); if(k->wordLen == w->wordLen) return memcmp(k->word, w->word, (size_t)k->wordLen); #if !defined(NDEBUG) else if(!w->word){ assert(!"sentinel gets trimmed from the list length"); return 1 /* sentinel entry */; } #endif else if(k->word[0] != w->word[0]) return (int)k->word[0] - (int)w->word[0]; else{ cwal_size_t const len = (k->wordLen<w->wordLen) ? k->wordLen : w->wordLen; int const cmp = memcmp(k->word, w->word, (size_t)len); return cmp ? cmp : ((len==k->wordLen) ? -1 : 1); } } int s2_keyword_f_typeinfo( s2_keyword const * kw, s2_engine * se, s2_ptoker * pr, cwal_value **rv){ s2_ptoken tIdent = s2_ptoken_empty; s2_ptoker prBody = s2_ptoker_empty; s2_ptoker const * oldScript = se->currentScript; cwal_size_t idLen = 0; cwal_value * xrv = 0; int rc; int buul = -1 /* <0=unknown, 0=false, >0=true */; s2_typeinfo_word const * word; *rv = 0; /** Ideas: typeinfo(FLAG EXPR) We use (...) to avoid potential precedence confusion for use cases such as: typeinfo iscallable X || throw "need a callable type" i.e. does the || belong the RHS of the typeinfo or not? We punt on that problem by adding the parenthesis, making it unambiguous. FLAG is one of the words defined above. */ rc = s2_next_token( se, pr, 0, 0 ); if(rc) goto end; if(S2_T_ParenGroup!=pr->token.ttype){ rc = s2_err_ptoker(se, pr, CWAL_SCR_SYNTAX, "Expecting (IDENTIFIER ...) after '%s'.", kw->word); goto end; } if(se->skipLevel>0){ /** Reminder to self: someday we should arguably continue going in skip mode so that we can validate that the contents of (...) are syntactically valid. */ *rv = cwal_value_undefined(); goto end; } s2_ptoker_sub_from_toker(&prBody, pr); rc = s2_next_token(se, &prBody, 0, 0); if(rc) goto end; else if(S2_T_Identifier!=prBody.token.ttype){ rc = s2_err_ptoker(se, &prBody, CWAL_SCR_SYNTAX, "Expected typeinfo tag in %s(TAG ...).", kw->word); goto end; } se->currentScript = &prBody; tIdent = prBody.token; assert(tIdent.end-tIdent.begin>0); idLen = (cwal_size_t)(tIdent.end-tIdent.begin); assert(idLen); /* MARKER(("typeinfo tag: %.*s\n", (int)idLen, tIdent.begin)); */ /* Look for sub-keyword match... TODO: binary search. Need to move the struct decl up a scope for that. */ { s2_typeinfo_word wordKey; wordKey.word = tIdent.begin; wordKey.wordLen = idLen; wordKey.type = TYPEINFO_REFCOUNT /*any will do*/; wordKey.argType = 0; word = (s2_typeinfo_word const *)bsearch(&wordKey, s2TypeInfoWords, sizeof(s2TypeInfoWords) /sizeof(s2TypeInfoWords[0]) -1/*sentinel*/, sizeof(s2_typeinfo_word), s2_typeinfo_cmp); } if(0!=rc || !word->word){ /* Note that in skip mode we've skipped over the whole (...), so this won't be triggered in skip mode (an exception to the rule/guideline regarding "blatant syntax errors"). Whether or not that needs "fixing" (such that this error could be triggered in skip mode) is as yet undecided. |
︙ | ︙ | |||
31770 31771 31772 31773 31774 31775 31776 | rc = s2_err_ptoker(se, &prBody, CWAL_SCR_SYNTAX, "Expecting comma after %s(%.*s ...).", kw->word, (int)idLen, tIdent.begin); goto end; } #endif | | | < | | | | | | | | | > > > | | | | | > | | > > > > > | | | | | | | | | | | | | | > | > > > > > > > > > > > > > > | 32212 32213 32214 32215 32216 32217 32218 32219 32220 32221 32222 32223 32224 32225 32226 32227 32228 32229 32230 32231 32232 32233 32234 32235 32236 32237 32238 32239 32240 32241 32242 32243 32244 32245 32246 32247 32248 32249 32250 32251 32252 32253 32254 32255 32256 32257 32258 32259 32260 32261 32262 32263 32264 32265 32266 32267 32268 32269 32270 32271 32272 32273 32274 32275 32276 32277 32278 32279 32280 32281 32282 | rc = s2_err_ptoker(se, &prBody, CWAL_SCR_SYNTAX, "Expecting comma after %s(%.*s ...).", kw->word, (int)idLen, tIdent.begin); goto end; } #endif if(word->argType<0){ /* typeinfo(tag IDENTIFIER) */ rc = s2_next_token(se, &prBody, 0, 0); if(rc) goto end; else if(S2_T_Identifier != prBody.token.ttype){ rc = s2_err_ptoker(se, &prBody, CWAL_SCR_SYNTAX, "The %s('%s' ...) tag requires an IDENTIFIER " "(variable name).", kw->word, word->word); goto end; } switch(word->type){ case TYPEINFO_ISLOCAL: case TYPEINFO_ISDECLARED: xrv = s2_var_get(se, TYPEINFO_ISLOCAL==word->type ? 0 : -1, prBody.token.begin, (cwal_size_t)(prBody.token.end - prBody.token.begin)); buul = xrv ? 1 : 0; xrv = 0; cwal_value_ref(xrv); break; default: assert(!"Missing entry for argType<0!"); break; } }else if(word->argType>0){ /* typeinfo(tag EXPR) */ rc = s2_eval_expr_impl(se, &prBody, 0, (TYPEINFO_NAME==word->type) ? S2_EVAL_UNKNOWN_IDENTIFIER_AS_UNDEFINED : 0 , &xrv); if(rc){ assert(!xrv); goto end; }else if(!xrv){ rc = s2_err_ptoker(se, &prBody, CWAL_SCR_SYNTAX, "Expecting non-empty expression after %s(%s, ...).", kw->word, word ? word->word : "..."); goto end; } cwal_value_ref(xrv); }else{ /* typeinfo(tag) */ ++se->skipLevel; rc = s2_eval_expr_impl(se, &prBody, 0, 0, &xrv); --se->skipLevel; if(rc){ assert(!xrv); goto end; }else if(xrv){ cwal_value_ref(xrv); rc = s2_err_ptoker(se, &prBody, CWAL_SCR_SYNTAX, "Got unexpected expression in %s(%s <HERE>).", kw->word, word->word); goto end; } } assert(!rc); switch(word->type){ #define TYPEWORD(WORD,PREDICATE) \ case WORD: buul = PREDICATE(xrv); break |
︙ | ︙ | |||
31837 31838 31839 31840 31841 31842 31843 31844 | break; case TYPEINFO_ISLOCAL: case TYPEINFO_ISDECLARED: /* handled above */ assert(buul >= 0); break; case TYPEINFO_ISNEWING: | > | > | 32302 32303 32304 32305 32306 32307 32308 32309 32310 32311 32312 32313 32314 32315 32316 32317 32318 32319 32320 | break; case TYPEINFO_ISLOCAL: case TYPEINFO_ISDECLARED: /* handled above */ assert(buul >= 0); break; case TYPEINFO_ISNEWING: buul = s2_scope_is_newing(se); break; case TYPEINFO_ISNUMERIC: if(!(buul = cwal_value_is_number(xrv)) && cwal_value_is_string(xrv)){ /* check for numeric-format strings a-la 0.prototype.parseNumber(). */ cwal_size_t slen = 0; char const * src = cwal_value_get_cstr(xrv, &slen); |
︙ | ︙ | |||
31946 31947 31948 31949 31950 31951 31952 | *rv = cwal_new_bool(buul ? 1 : 0); }else{ assert(*rv); } end: se->currentScript = oldScript; | | > | | 32413 32414 32415 32416 32417 32418 32419 32420 32421 32422 32423 32424 32425 32426 32427 32428 32429 | *rv = cwal_new_bool(buul ? 1 : 0); }else{ assert(*rv); } end: se->currentScript = oldScript; if(xrv){ if(!rc && *rv == xrv) cwal_value_unhand(xrv); else cwal_value_unref(xrv); } return rc; } cwal_value * s2_propagating_get( s2_engine * se ){ |
︙ | ︙ | |||
32591 32592 32593 32594 32595 32596 32597 | }; rc = s2_install_functions(se, proto, funcs, 0 ); if(rc) goto end; else { cwal_value * fv = 0; s2_get(se, proto, "new", 3, &fv); assert(fv && "we JUST put this in there!"); | | | 33059 33060 33061 33062 33063 33064 33065 33066 33067 33068 33069 33070 33071 33072 33073 | }; rc = s2_install_functions(se, proto, funcs, 0 ); if(rc) goto end; else { cwal_value * fv = 0; s2_get(se, proto, "new", 3, &fv); assert(fv && "we JUST put this in there!"); rc = s2_ctor_method_set( se, proto, cwal_value_get_function(fv) ); } } #undef FUNC2 #undef CHECKV #undef RC |
︙ | ︙ | |||
34173 34174 34175 34176 34177 34178 34179 34180 34181 34182 34183 34184 34185 34186 | #else #define MARKER(pfexp) (void)0 #endif #define s2__pop_val s2_engine_pop_value #define s2__pop_tok s2_engine_pop_token /** Operator for unary and binary addition and subtraction. Required stack (from top to bottom): Binary: RHS LHS Unary: RHS | > > > > | 34641 34642 34643 34644 34645 34646 34647 34648 34649 34650 34651 34652 34653 34654 34655 34656 34657 34658 | #else #define MARKER(pfexp) (void)0 #endif #define s2__pop_val s2_engine_pop_value #define s2__pop_tok s2_engine_pop_token /* defined in s2_eval.c */ void s2_dotop_state( s2_engine * se, cwal_value * self, cwal_value * lhs, cwal_value * key ); /** Operator for unary and binary addition and subtraction. Required stack (from top to bottom): Binary: RHS LHS Unary: RHS |
︙ | ︙ | |||
35245 35246 35247 35248 35249 35250 35251 | rc = s2_engine_err_set(se, CWAL_RC_TYPE, "Invalid LHS value (type %s) for " "'%s' operator.", cwal_value_type_name(lhs), op->sym); }else if(se->skipLevel){ if(S2_T_OpDot == op->id){ | > > | | > > | | > | | > > > | < | 35717 35718 35719 35720 35721 35722 35723 35724 35725 35726 35727 35728 35729 35730 35731 35732 35733 35734 35735 35736 35737 35738 35739 35740 35741 35742 35743 35744 35745 35746 35747 35748 35749 35750 35751 35752 35753 35754 35755 35756 35757 35758 35759 35760 35761 35762 35763 35764 35765 35766 35767 35768 35769 35770 35771 35772 35773 35774 35775 35776 35777 35778 35779 35780 35781 35782 35783 35784 35785 35786 35787 35788 35789 | rc = s2_engine_err_set(se, CWAL_RC_TYPE, "Invalid LHS value (type %s) for " "'%s' operator.", cwal_value_type_name(lhs), op->sym); }else if(se->skipLevel){ if(S2_T_OpDot == op->id){ s2_dotop_state( se, lhs, lhs, rhs ); assert( se->dotOpSelf == se->dotOpLhs ); assert( se->dotOpSelf == lhs ); assert( se->dotOpKey == rhs ); }else{ s2_dotop_state( se, 0, cwal_value_undefined(), cwal_value_undefined() ); assert(!se->dotOpSelf); assert(cwal_value_undefined() == se->dotOpLhs); assert(cwal_value_undefined() == se->dotOpKey); } *rv = cwal_value_undefined(); rc = 0; }else{ /* X.Y and X#Y... */ cwal_value * xrv = 0; /* s2_dotop_state( se, 0, 0, 0 ); */ /* s2_dump_val(lhs,"dot op lhs"); */ if(S2_T_OpDot == op->id){ const int isArrayAccess = cwal_value_is_integer(rhs) && cwal_value_array_part(se->e,lhs) /* Workaround to keep array.int's array from becoming 'this' if it resolves to a function which gets called. */ ; rc = s2_get_v(se, lhs, rhs, &xrv); if(!rc){ s2_dotop_state( se, isArrayAccess ? 0 : lhs, lhs, rhs ); } }else{ /* X#Y */ cwal_hash * h; assert(S2_T_OpHash==op->id); #if 0 if(!s2_op_check_overload(op, se, 0, lhs, rhs, &xrv, &rc) && !rc){ #endif h = cwal_value_hash_part(se->e, lhs); if(!h){ rc = s2_engine_err_set(se, CWAL_RC_TYPE, "Invalid (non-Hash) LHS for '%s' operator.", op->sym); }else{ xrv = cwal_hash_search_v( h, rhs ); } #if 0 } #endif if(!rc) s2_dotop_state(se, 0, lhs, rhs); } if(!rc){ /* Hmmm. We can't cwal_refunref() the operands to these ops. We need to tweak the bits which use these parts (namely assignments) to refunref these. */ /* s2_dotop_state( se, opSelf, lhs, rhs ); */ *rv = xrv ? xrv : cwal_value_undefined(); } } return rc; } int s2_op_f_oload_arrow( s2_op const * op, s2_engine * se, |
︙ | ︙ | |||
35322 35323 35324 35325 35326 35327 35328 | assert(rc); } #if 0 /*??? can of worms ??? */ if(!rc){ /* Has to be done afterwards b/c overload can overwrite these, triggering an assertion in fcall() */ | | < | 35801 35802 35803 35804 35805 35806 35807 35808 35809 35810 35811 35812 35813 35814 35815 | assert(rc); } #if 0 /*??? can of worms ??? */ if(!rc){ /* Has to be done afterwards b/c overload can overwrite these, triggering an assertion in fcall() */ s2_dotop_state( se, se->dotOpSelf, lhs, rhs ); /* s2_dump_val(rhs,"se->dotOpKey"); */ /* s2_dump_val(lhs,"se->dotOpLhs"); */ } #endif } return rc; } |
︙ | ︙ | |||
35566 35567 35568 35569 35570 35571 35572 | cwal_value * vResolved = 0, * vResult = 0; cwal_int_t addVal = 0; char gotOverLoad = 0; char resolvedIsContainer = 0; assert(1==op->arity); self = se->dotOpLhs; key = self ? se->dotOpKey : 0; | > > | > > > > | > | 36044 36045 36046 36047 36048 36049 36050 36051 36052 36053 36054 36055 36056 36057 36058 36059 36060 36061 36062 36063 36064 36065 36066 36067 36068 36069 36070 36071 36072 36073 36074 36075 | cwal_value * vResolved = 0, * vResult = 0; cwal_int_t addVal = 0; char gotOverLoad = 0; char resolvedIsContainer = 0; assert(1==op->arity); self = se->dotOpLhs; key = self ? se->dotOpKey : 0; if(key) cwal_value_ref(key); if(self) cwal_value_ref(self); s2_dotop_state( se, 0, 0, 0 ); if(key) cwal_value_unhand(key); if(self) cwal_value_unhand(self); se->dotOpId = 0; vTok = s2__pop_tok(se, 1); if(se->skipLevel>0){ /* FIXME: refunref self/key, as appropriate. What about dotOpId?*/ *rv = cwal_value_undefined(); s2_stoken_free(se, vTok, 1); return 0; } if(!self){ assert(!key); key = vTok->value; } identType = vTok->ttype; s2_stoken_free(se, vTok, 1); vTok = 0; /* if (self) then we know (well, hope) this was a prefix op to X.Y. |
︙ | ︙ | |||
36637 36638 36639 36640 36641 36642 36643 | }; rc = s2_install_functions(se, proto, funcs, 0); if(rc) goto end; else { cwal_value * fv = 0; s2_get(se, proto, "new", 3, &fv); assert(fv && "we JUST put this in there!"); | | | 37122 37123 37124 37125 37126 37127 37128 37129 37130 37131 37132 37133 37134 37135 37136 | }; rc = s2_install_functions(se, proto, funcs, 0); if(rc) goto end; else { cwal_value * fv = 0; s2_get(se, proto, "new", 3, &fv); assert(fv && "we JUST put this in there!"); rc = s2_ctor_method_set( se, proto, cwal_value_get_function(fv) ); } } #undef SET #undef CHECKV end: |
︙ | ︙ | |||
38502 38503 38504 38505 38506 38507 38508 | }; rc = s2_install_functions(se, proto, funcs, 0); if(rc) goto end; else { cwal_value * fv = 0; s2_get(se, proto, "new", 3, &fv); assert(fv && "we JUST put this in there!"); | | | 38987 38988 38989 38990 38991 38992 38993 38994 38995 38996 38997 38998 38999 39000 39001 | }; rc = s2_install_functions(se, proto, funcs, 0); if(rc) goto end; else { cwal_value * fv = 0; s2_get(se, proto, "new", 3, &fv); assert(fv && "we JUST put this in there!"); rc = s2_ctor_method_set( se, proto, cwal_value_get_function(fv) ); } } end: return rc ? NULL /* remember: proto is stashed at this point, so no leak. */ |
︙ | ︙ |
Changes to s2/s2_amalgamation.h.
︙ | ︙ | |||
11 12 13 14 15 16 17 | # endif # ifndef _BSD_SOURCE # define _BSD_SOURCE # endif #endif /* start of file ../cwal_amalgamation.h */ #if !defined(CWAL_VERSION_STRING) | | | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | # endif # ifndef _BSD_SOURCE # define _BSD_SOURCE # endif #endif /* start of file ../cwal_amalgamation.h */ #if !defined(CWAL_VERSION_STRING) # define CWAL_VERSION_STRING "cwal fc4ced93115269518c0b2f51baafc3bf6d718e95 2016-01-31 17:26:10 built 2016-01-31 17:33" #endif /* start of file include/wh/cwal/cwal_config.h */ #if !defined(WANDERINGHORSE_NET_CWAL_CONFIG_H_INCLUDED) #define WANDERINGHORSE_NET_CWAL_CONFIG_H_INCLUDED 1 #if !defined(CWAL_VERSION_STRING) #define CWAL_VERSION_STRING "cwal version ???" |
︙ | ︙ | |||
8445 8446 8447 8448 8449 8450 8451 8452 8453 8454 8455 8456 8457 8458 | Returns a handle to v's originating cwal_engine, or NULL if !v. */ cwal_engine * cwal_value_engine( cwal_value const * v ); /** Returns the current owning scope of v, or NULL if !v. */ cwal_scope * cwal_value_scope( cwal_value const * v ); /** Possibly reallocates self->list, changing its size. This function ensures that self->list has at least n entries. If n | > > > | 8445 8446 8447 8448 8449 8450 8451 8452 8453 8454 8455 8456 8457 8458 8459 8460 8461 | Returns a handle to v's originating cwal_engine, or NULL if !v. */ cwal_engine * cwal_value_engine( cwal_value const * v ); /** Returns the current owning scope of v, or NULL if !v. Note that this is always 0 for values for which cwal_value_is_builtin() returns true. */ cwal_scope * cwal_value_scope( cwal_value const * v ); /** Possibly reallocates self->list, changing its size. This function ensures that self->list has at least n entries. If n |
︙ | ︙ | |||
10683 10684 10685 10686 10687 10688 10689 10690 10691 10692 10693 10694 10695 10696 | O(1) and cost no new memory. Token instances must not be in use more than once concurrently, e.g. a token may not be in more than one stack at a time, nor may it be in the same stack multiple times. Multiple entries may reference the same value, provided it is otherwise safe from being swept/vacuumed up. */ struct s2_stoken{ /** A s2_token_types value. */ int ttype; /** | > | 10686 10687 10688 10689 10690 10691 10692 10693 10694 10695 10696 10697 10698 10699 10700 | O(1) and cost no new memory. Token instances must not be in use more than once concurrently, e.g. a token may not be in more than one stack at a time, nor may it be in the same stack multiple times. Multiple entries may reference the same value, provided it is otherwise safe from being swept/vacuumed up. */ struct s2_stoken{ /** A s2_token_types value. */ int ttype; /** |
︙ | ︙ | |||
10899 10900 10901 10902 10903 10904 10905 10906 10907 10908 10909 10910 10911 10912 | copy initialization. */ extern const s2_op s2_op_empty; #endif /** Holds a stack of s2_stokens. */ struct s2_stoken_stack { /** The top of the stack. Maintained via s2_stoken_stack_push(), s2_stoken_stack_pop(), and friends. | > > > > > > > > > > > > > | 10903 10904 10905 10906 10907 10908 10909 10910 10911 10912 10913 10914 10915 10916 10917 10918 10919 10920 10921 10922 10923 10924 10925 10926 10927 10928 10929 | copy initialization. */ extern const s2_op s2_op_empty; #endif /** Holds a stack of s2_stokens. Reminders to self: - 20160131 this type was designed to _not_ ref/unref values added to the stack, but that may have turned out to be a mistake. It simplifies much other code but string interning combined with our internal use of "temp" values leads to unmanagable/incorrect refcounts for interned string values in some cases, triggering cwal-level corruption detection assertions. Rewiring s2 so that this type does much of the reference count managent for a given (sub)expression is certainly worth considering, but could require a weekend or more of intense concentration :/. */ struct s2_stoken_stack { /** The top of the stack. Maintained via s2_stoken_stack_push(), s2_stoken_stack_pop(), and friends. |
︙ | ︙ | |||
11074 11075 11076 11077 11078 11079 11080 11081 11082 11083 11084 11085 11086 11087 | */ struct s2_scope { cwal_scope scope; s2_sweep_guard sguard; s2_scope * parent; s2_subexpr_savestate saved; int ctorCallFlag; }; #define s2_scope_empty_m {\ cwal_scope_empty_m/*scope*/, \ s2_sweep_guard_empty_m/*sguard*/, \ 0/*parent*/, \ s2_subexpr_savestate_empty_m/*saved*/, \ | > > > > > > | > | 11091 11092 11093 11094 11095 11096 11097 11098 11099 11100 11101 11102 11103 11104 11105 11106 11107 11108 11109 11110 11111 11112 11113 11114 11115 11116 11117 11118 11119 | */ struct s2_scope { cwal_scope scope; s2_sweep_guard sguard; s2_scope * parent; s2_subexpr_savestate saved; int ctorCallFlag; /** Set very to allow typeinfo(issnewing) to elide its second argument. It also incidentally lets us implement that check more cleanly. */ void /*cwal_value*/ const * newingThis; }; #define s2_scope_empty_m {\ cwal_scope_empty_m/*scope*/, \ s2_sweep_guard_empty_m/*sguard*/, \ 0/*parent*/, \ s2_subexpr_savestate_empty_m/*saved*/, \ 0/*ctorCallFlag*/, \ 0/*newingThis*/\ } extern const s2_scope s2_scope_empty; /** This class encapsulates a basic stack engine which uses the cwal_value type as its generic operand type. |
︙ | ︙ | |||
11292 11293 11294 11295 11296 11297 11298 | /** Used to communicate the "argv" value between the interpreter parts which call functions and the pre-call hook called by cwal. */ cwal_array * callArgV; | | | 11316 11317 11318 11319 11320 11321 11322 11323 11324 11325 11326 11327 11328 11329 11330 | /** Used to communicate the "argv" value between the interpreter parts which call functions and the pre-call hook called by cwal. */ cwal_array * callArgV; /** Gets set by the stack layer when an operator (A) triggers an error and (B) has its srcPos set. Used to communicate operator-triggered error location information back to the parser layer. */ char const * opErrPos; |
︙ | ︙ | |||
15018 15019 15020 15021 15022 15023 15024 | cwal_value * fv; f = cwal_new_function( se->e, my_callback_f, my_callback_state, my_callback_state_finalizer_f, my_type_id ); if(!f) return CWAL_RC_OOM; fv = cwal_function_value(fv); assert(f == cwal_value_get_function(fv)); // will always be the case if f is valid cwal_value_ref(fv); | | | | | | | | 15042 15043 15044 15045 15046 15047 15048 15049 15050 15051 15052 15053 15054 15055 15056 15057 15058 15059 15060 15061 15062 15063 15064 15065 15066 15067 15068 15069 15070 15071 15072 15073 15074 15075 15076 15077 | cwal_value * fv; f = cwal_new_function( se->e, my_callback_f, my_callback_state, my_callback_state_finalizer_f, my_type_id ); if(!f) return CWAL_RC_OOM; fv = cwal_function_value(fv); assert(f == cwal_value_get_function(fv)); // will always be the case if f is valid cwal_value_ref(fv); rc = s2_ctor_method_set( se, myContainer, f ); cwal_value_unref(fv); return rc; @endcode In such a setup, from inside the my_callback() implementation, cwal_args_state(args->engine, my_type_id) can be used to (type-safely) fetch the my_callback_state pointer. The s2_engine instance associated with the call can be fetched via s2_engine_from_args(args). @see s2_ctor_callback_set() */ int s2_ctor_method_set( s2_engine * se, cwal_value * container, cwal_function * method ); /** A convenience form of s2_ctor_method_set() which instantiates a cwal_function from the its 3rd argument using s2_new_callback(). Returns CWAL_RC_MISUSE if any argument is NULL, else returns as for s2_ctor_method_set(). */ int s2_ctor_callback_set( s2_engine * se, cwal_value * container, cwal_callback_f method ); /** Invokes a "constructor" function in the same manner as the 'new' keyword does. If ctor is NULL then s2 looks in operand (which must be a container type) for a property named "s2::new". If that property is not found or is not a Function, se's error state is set and non-0 is returned. |
︙ | ︙ | |||
15093 15094 15095 15096 15097 15098 15099 | "new" keyword. This only returns true if v is a container which holds (not counting properties inherited from prototypes) a key named "s2::new" with a value which is-a/has-a Function. */ char s2_value_is_newable( s2_engine * se, cwal_value * v ); /** | | | < < | | 15117 15118 15119 15120 15121 15122 15123 15124 15125 15126 15127 15128 15129 15130 15131 15132 15133 15134 | "new" keyword. This only returns true if v is a container which holds (not counting properties inherited from prototypes) a key named "s2::new" with a value which is-a/has-a Function. */ char s2_value_is_newable( s2_engine * se, cwal_value * v ); /** Returns true (non-0) if se's current scope was started by the "new" keyword. */ char s2_scope_is_newing(s2_engine * se); /** @internal Looks for a constructor function from operand, _not_ looking in prototypes (because ctors should generally not be inherited). |
︙ | ︙ |
Changes to s2/shell.c.
︙ | ︙ | |||
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | #else static void noop_printf(char const * fmt, ...) {} #define MARKER if(0) noop_printf #endif #define MESSAGE(pfexp) printf pfexp #define VERBOSE(pfexp) if(App.verboseMode) { printf("verbose: "); MESSAGE(pfexp); }(void)0 /* If S2_SHELL_EXTEND is defined, the client must define s2_shell_extend() (see shell_extend.c for one implementation) and link it in with this app. It will be called relatively early in the initialization process so that any auto-loaded scripts can make use of it. It must, on error, return one of the non-0 CWAL_RC_xxx error codes (NOT a code from outside the range! EVER!). An error is treated as fatal to the shell. See shell_extend.c for a documented example of how to use this approach to extending this app. */ #if defined(S2_SHELL_EXTEND) | > > > | | 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 | #else static void noop_printf(char const * fmt, ...) {} #define MARKER if(0) noop_printf #endif #define MESSAGE(pfexp) printf pfexp #define VERBOSE(pfexp) if(App.verboseMode) { printf("verbose: "); MESSAGE(pfexp); }(void)0 #if !defined(S2_SHELL_EXTEND_FUNC_NAME) #define S2_SHELL_EXTEND_FUNC_NAME s2_shell_extend #endif /* If S2_SHELL_EXTEND is defined, the client must define s2_shell_extend() (see shell_extend.c for one implementation) and link it in with this app. It will be called relatively early in the initialization process so that any auto-loaded scripts can make use of it. It must, on error, return one of the non-0 CWAL_RC_xxx error codes (NOT a code from outside the range! EVER!). An error is treated as fatal to the shell. See shell_extend.c for a documented example of how to use this approach to extending this app. */ #if defined(S2_SHELL_EXTEND) extern int S2_SHELL_EXTEND_FUNC_NAME(s2_engine * se, int argc, char const * const * argv); #endif /** Global app-level state. */ static struct { char const * appName; |
︙ | ︙ | |||
201 202 203 204 205 206 207 | */ cwal_memcap_config memcap; } App = { 0/*appName*/, 1/*enableArg0Autoload*/, 1/*enableValueRecycling*/, 35/*maxChunkCount*/, | | | 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 | */ cwal_memcap_config memcap; } App = { 0/*appName*/, 1/*enableArg0Autoload*/, 1/*enableValueRecycling*/, 35/*maxChunkCount*/, 1/*enableStringInterning*/, 0/*showMetrics*/, 0/*verboseMode*/, 0/*traceAssertions*/, 0/*traceStacks*/, 0/*traceSweeps*/, 1/*scopesUseHashes*/, 0/*inFile*/, |
︙ | ︙ | |||
1034 1035 1036 1037 1038 1039 1040 | slen = cwal_strlen(arg0) - (exe ? 4 : 0); rc = sprintf(fn, "%.*s.s2", (int)slen, arg0); assert(rc<BufSize-1); rc = 0; scriptName = fn; } if(s2_file_is_accessible(scriptName, 0)){ | > > > | | | | | | | | > > > > | 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 | slen = cwal_strlen(arg0) - (exe ? 4 : 0); rc = sprintf(fn, "%.*s.s2", (int)slen, arg0); assert(rc<BufSize-1); rc = 0; scriptName = fn; } if(s2_file_is_accessible(scriptName, 0)){ if(App.cleanroom){ VERBOSE(("Clean-room mode is active: NOT auto-loading script [%s].\n", scriptName)); }else{ cwal_value * rv = 0; VERBOSE(("Auto-loading script [%s].\n", scriptName)); rc = s2_eval_filename(se, 1, scriptName, -1, &rv); if(rc){ MESSAGE(("Error auto-loading init script [%s]: " "error #%d (%s).\n", scriptName, rc, s2_rc_cstr(rc))); s2sh_report_result(se, rc, &rv); } else{ cwal_refunref(rv); } } } return rc; } int s2sh_main(int argc, char const * const * argv){ enum { |
︙ | ︙ | |||
1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 | se = UseStackS2Engine ? &SE : s2_engine_alloc(e); assert(se); assert(UseStackS2Engine ? !se->allocStamp : (se->allocStamp == e)); if((rc = s2_engine_init( se, e ))) goto end; if(!App.cleanroom){ if((rc = s2_install_core_prototypes(se))) goto end; } se->sweepInterval += App.addSweepInterval; se->vacuumInterval += App.addVacuumInterval; se->flags.traceStack = App.traceStacks; se->flags.traceAssertions = App.traceAssertions; se->flags.traceSweeps = App.traceSweeps; s2_clampdown_level_set(se, App.clampDown); | > < > | > > > | 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 | se = UseStackS2Engine ? &SE : s2_engine_alloc(e); assert(se); assert(UseStackS2Engine ? !se->allocStamp : (se->allocStamp == e)); if((rc = s2_engine_init( se, e ))) goto end; if(!App.cleanroom){ if((rc = s2_install_core_prototypes(se))) goto end; else if( (rc = s2_setup_s2_global(se)) ) goto end; } se->sweepInterval += App.addSweepInterval; se->vacuumInterval += App.addVacuumInterval; se->flags.traceStack = App.traceStacks; se->flags.traceAssertions = App.traceAssertions; se->flags.traceSweeps = App.traceSweeps; s2_clampdown_level_set(se, App.clampDown); s2_set_interrupt_handlable( se ) /* after infrastructure, before the auto-loaded script, in case it contains an endless loop or some such. */; #if defined(S2_SHELL_EXTEND) if(!App.cleanroom){ if( (rc = S2_SHELL_EXTEND_FUNC_NAME(se, argc, argv)) ) goto end; }else{ VERBOSE(("Clean-room mode is active: NOT running client-side shell extensions.\n")); } #endif if( (rc=s2sh_autoload(se)) ) goto end; rc = s2sh_main2(se); App.s2Global = 0; end: |
︙ | ︙ | |||
1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 | }ARG("--W"){ App.traceSweeps = 0; }ARG("-w"){ ++App.addSweepInterval; }ARG("+w"){ ++App.addVacuumInterval; }ARG("-S"){ MARKER(("WARNING: string interning is disabled (despite -S) " "because it can backfire badly in some " "(unpredictable) cases.\n")); | > > > | > | 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 | }ARG("--W"){ App.traceSweeps = 0; }ARG("-w"){ ++App.addSweepInterval; }ARG("+w"){ ++App.addVacuumInterval; }ARG("-S"){ #if 0 MARKER(("WARNING: string interning is disabled (despite -S) " "because it can backfire badly in some " "(unpredictable) cases.\n")); App.enableStringInterning = 0; #else App.enableStringInterning = 1; #endif }ARG("--S"){ App.enableStringInterning = 0; }ARG("-i"){ App.interactive = 1; }ARG("-f"){ GET_FLAG_VAL(App.inFile); assert(App.inFile); |
︙ | ︙ | |||
1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 | #define SO(T) MARKER(("sizeof("#T")=%d\n", (int)sizeof(T))) SO(s2_stoken); SO(s2_ptoken); SO(s2_ptoker); SO(s2_op); SO(s2_engine); SO(cwal_engine); #undef SO }else{ MARKER(("Unknown argument: %s\n", arg)); assert(!"Unknown argument"); return CWAL_RC_MISUSE; } } | > | 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 | #define SO(T) MARKER(("sizeof("#T")=%d\n", (int)sizeof(T))) SO(s2_stoken); SO(s2_ptoken); SO(s2_ptoker); SO(s2_op); SO(s2_engine); SO(cwal_engine); SO(cwal_memchunk_overlay); #undef SO }else{ MARKER(("Unknown argument: %s\n", arg)); assert(!"Unknown argument"); return CWAL_RC_MISUSE; } } |
︙ | ︙ |
Changes to s2/shell_extend.c.
︙ | ︙ | |||
2696 2697 2698 2699 2700 2701 2702 | FUNC("transactionState", cb_fsl_db_trans_state); FUNC("close", cb_fsl_db_finalize); FUNC("each", cb_fsl_db_each); FUNC("exec", cb_fsl_db_exec); FUNC("execMulti", cb_fsl_db_exec_multi); FUNC("lastInsertId", cb_fsl_db_last_insert_id); FUNC("open", cb_fsl_db_ctor); | | | 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 | FUNC("transactionState", cb_fsl_db_trans_state); FUNC("close", cb_fsl_db_finalize); FUNC("each", cb_fsl_db_each); FUNC("exec", cb_fsl_db_exec); FUNC("execMulti", cb_fsl_db_exec_multi); FUNC("lastInsertId", cb_fsl_db_last_insert_id); FUNC("open", cb_fsl_db_ctor); rc = s2_ctor_method_set(se, proto, cwal_value_get_function(v)); if(rc) goto end; FUNC("prepare", cb_fsl_db_prepare); FUNC("selectValue", cb_fsl_db_select_value); FUNC("selectValues", cb_fsl_db_select_values); v = fsl_stmt_prototype(se); VCHECK; |
︙ | ︙ | |||
2754 2755 2756 2757 2758 2759 2760 | /* FUNC("closeConfig", cb_fsl_config_close); */ FUNC("finalize", cb_fsl_cx_finalize); FUNC("getUserName", cb_fsl_cx_user_name); FUNC("loadBlob", cb_fsl_cx_content_get); FUNC("loadManifest",cb_fsl_cx_deck_load); FUNC("loginCookieName", cb_fsl_login_cookie_name); FUNC("new", cb_fsl_cx_ctor); | | | 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 | /* FUNC("closeConfig", cb_fsl_config_close); */ FUNC("finalize", cb_fsl_cx_finalize); FUNC("getUserName", cb_fsl_cx_user_name); FUNC("loadBlob", cb_fsl_cx_content_get); FUNC("loadManifest",cb_fsl_cx_deck_load); FUNC("loginCookieName", cb_fsl_login_cookie_name); FUNC("new", cb_fsl_cx_ctor); rc = s2_ctor_method_set(se, proto, cwal_value_get_function(v)); if(rc) goto end; FUNC("openCheckout", cb_fsl_checkout_open_dir); FUNC("openConfig", cb_fsl_config_open); FUNC("openDb", cb_fsl_db_ctor); FUNC("openRepo", cb_fsl_repo_open); FUNC("symToRid", cb_fsl_cx_sym2rid); FUNC("symToUuid", cb_fsl_cx_sym2uuid); |
︙ | ︙ |
Changes to s2/unit/020-050-buffer.s2.
︙ | ︙ | |||
134 135 136 137 138 139 140 141 142 143 144 145 146 147 | check( "'h''i'", '%1$Q', "h'i" ); check( 'NULL', '%1$Q', null ); // check 0-precision characters... check( '', '%1$.0c', '*' ); check( '', '%1$0.0c', '*' ); check( ' ', '%1$2.0c', '*' ) /* arguable, but currently true */; } scope{ var b = Buffer(100); var x = 0, y = 0; b << <<<EOF for(var i = 0; i < 5; ++i) ++x, --y; | > > > > > > > > > > | 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 | check( "'h''i'", '%1$Q', "h'i" ); check( 'NULL', '%1$Q', null ); // check 0-precision characters... check( '', '%1$.0c', '*' ); check( '', '%1$0.0c', '*' ); check( ' ', '%1$2.0c', '*' ) /* arguable, but currently true */; // check urlencoding/decoding check( 'a%20b%26c', '%1$r', 'a b&c' ); check( 'a b&c', '%1$R', 'a%20b%26c' ); check( 'a%2zb', '%1$R', 'a%2zb' ); assert catch {'%1$.1r'.applyFormat()}.message.indexOf('precision')>0; assert catch {'%1$1r'.applyFormat()}.message.indexOf('width')>0; assert catch {'%1$.1R'.applyFormat()}.message.indexOf('precision')>0; assert catch {'%1$1R'.applyFormat()}.message.indexOf('width')>0; } scope{ var b = Buffer(100); var x = 0, y = 0; b << <<<EOF for(var i = 0; i < 5; ++i) ++x, --y; |
︙ | ︙ |
Changes to s2/vg.make.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # We keep these in a separate file to avoid a rebuild when changing # these flags. Damn... some automatic rules foil us here. ######################################################################## # Valgrind sanity checks... VG := $(call ShakeNMake.CALL.FIND_FILE,valgrind) ifneq (,$(VG)) VG_REPORT := VG.report.csv VG_FLAGS ?= --leak-check=full -v --show-reachable=yes --track-origins=yes #SCRIPT_LIST := $(shell ls -1 test-[0-9]*.s2 | sort) # Whether or not to collect massif-based stats... RUN_MASSIF := 1 .PHONY: vg # Reminder: don't use -A b/c it breaks output buffering tests! | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # We keep these in a separate file to avoid a rebuild when changing # these flags. Damn... some automatic rules foil us here. ######################################################################## # Valgrind sanity checks... VG := $(call ShakeNMake.CALL.FIND_FILE,valgrind) ifneq (,$(VG)) VG_REPORT := VG.report.csv VG_FLAGS ?= --leak-check=full -v --show-reachable=yes --track-origins=yes #SCRIPT_LIST := $(shell ls -1 test-[0-9]*.s2 | sort) # Whether or not to collect massif-based stats... RUN_MASSIF := 1 .PHONY: vg # Reminder: don't use -A b/c it breaks output buffering tests! VG_SHELL_FLAGS=--a -S VG_UNIT_RUN_CMD = ./$(f-s2sh.BIN) $(VG_SHELL_FLAGS) vg: $(f-s2sh.BIN) $(UNIT_GENERATED) @echo "Running: $(VG) $(VG_FLAGS) $(VG_UNIT_RUN_CMD) ..."; \ export LD_LIBRARY_PATH="$(TOP_SRCDIR):$${LD_LIBRARY_PATH}"; \ massif_tmp=tmp.massif; \ for i in $(sort $(UNIT_SCRIPT_LIST)) $(UNIT_GENERATED); do \ vgout=$$i.vg; \ |
︙ | ︙ | |||
53 54 55 56 57 58 59 | $(patsubst %,unit/%,*.vg *._out *.massif *.db *~ *.uncompressed *.z *.zip *.2) \ $(patsubst %,unit2/%,*.vg *._out *.massif *.db *~ *.uncompressed *.z *.zip *.2) \ ) # 'vg' proxies which tweak various s2/cwal-level optimizations... #vgp: VG_SHELL_FLAGS+=--p #vgp: VG_REPORT:=VG.report-p.csv #vgp: vg | | | | > > > > > > > > > > | | 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | $(patsubst %,unit/%,*.vg *._out *.massif *.db *~ *.uncompressed *.z *.zip *.2) \ $(patsubst %,unit2/%,*.vg *._out *.massif *.db *~ *.uncompressed *.z *.zip *.2) \ ) # 'vg' proxies which tweak various s2/cwal-level optimizations... #vgp: VG_SHELL_FLAGS+=--p #vgp: VG_REPORT:=VG.report-p.csv #vgp: vg vgr: VG_SHELL_FLAGS+=--R -C -S vgr: VG_REPORT:=VG.report-r.csv vgr: vg vgs: VG_SHELL_FLAGS+=--S -R -C vgs: VG_REPORT:=VG.report-s.csv vgs: vg #vgt: VG_SHELL_FLAGS+=--t #vgt: VG_REPORT:=VG.report-t.csv #vgt: vg vgrs: VG_SHELL_FLAGS+=--R -C --S vgrs: VG_REPORT:=VG.report-rs.csv vgrs: vg vgrsc: VG_SHELL_FLAGS+=--R --C --S vgrsc: VG_REPORT:=VG.report-rsc.csv vgrsc: vg # vgrst: VG_SHELL_FLAGS+=--r --s --t # vgrst: VG_REPORT:=VG.report-rst.csv # vgrst: vg # vgprst: VG_SHELL_FLAGS+=--r --s --t --p # vgprst: VG_REPORT:=VG.report-prst.csv # vgprst: vg VG_REPORT_MEGA := VG.report-mega.csv CLEAN_FILES += $(VG_REPORT_MEGA) VG_COMMANDS := \ $(MAKE) vg \ && $(MAKE) vgr \ && $(MAKE) vgs \ && $(MAKE) vgrs \ && $(MAKE) vgrsc vgall: @start=$$(date); \ echo "Start time: $$start"; \ $(VG_COMMANDS) || exit; \ echo "Run time: $$start - $$(date)"; \ rm -f $(VG_REPORT_MEGA); \ for i in VG.report*.csv; do \ test -s $$i || continue; \ echo $$i | grep t-mega >/dev/null && continue; \ echo "Report: $$i"; \ cut -d, -f1,2,4,5 $$i | tr ',' '\t'; \ done > $(VG_REPORT_MEGA); \ echo "Consolidated valgrind report is in [$(VG_REPORT_MEGA)]." endif #/$(VG) ######################################################################## |