Skip to content

Commit

Permalink
Expunge LOCALRA; tweaks to symbis; version to beta-27
Browse files Browse the repository at this point in the history
  • Loading branch information
HenryHRich committed Jan 8, 2025
1 parent a4869e7 commit abffee0
Show file tree
Hide file tree
Showing 12 changed files with 39 additions and 32 deletions.
12 changes: 7 additions & 5 deletions jsrc/cx.c
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,8 @@ DF2(jtxdefn){
L *sympv=SYMORIGIN; // bring into local
L *ybuckptr = &sympv[LXAV0(locsym)[(US)yxbucks]]; // pointer to sym block for y, known to exist
if(likely(w!=0)){ // If y given, install it & incr usecount as in assignment. Include the script index of the modification
I vtype=QCNAMED|(LOCALRA?QCRAREQD:REPSGN(AT(w))&QCRAREQD)|ATYPETOVALTYPE(AT(w)); // install QCSYMVAL flags
// obsolete I vtype=QCNAMED|(REPSGN(AT(w))&QCRAREQD)|ATYPETOVALTYPE(AT(w)); // install QCSYMVAL flags: named, with type
I vtype=unlikely(ISSPARSE(AT(w)))?QCNAMED+QCRAREQD+VALTYPESPARSE:QCNAMED+QCNOUN; // install QCSYMVAL flags: named, with type; FA needed iff sparse. Must be a noun
ybuckptr->fval=MAKEFVAL(w,vtype); ybuckptr->sn=jt->currslistx; // finish the assignment, with QCSYMVAL semantics
// If input is abandoned inplace and not the same as x, DO NOT increment usecount, but mark as abandoned and make not-inplace. Otherwise ra
// We can handle an abandoned argument only if it is direct or recursive, since only those values can be assigned to a name
Expand All @@ -319,7 +320,8 @@ DF2(jtxdefn){
if(a!=0){
L *xbuckptr = &sympv[LXAV0(locsym)[yxbucks>>16]]; // pointer to sym block for x
if(!C_CRC32C&&xbuckptr==ybuckptr)xbuckptr=xbuckptr->next+sympv;
I vtype=QCNAMED|(LOCALRA?QCRAREQD:REPSGN(AT(a))&QCRAREQD)|ATYPETOVALTYPE(AT(a)); // install QCSYMVAL flags
// obsolete I vtype=QCNAMED|(LOCALRA?QCRAREQD:REPSGN(AT(a))&QCRAREQD)|ATYPETOVALTYPE(AT(a)); // install QCSYMVAL flags
I vtype=unlikely(ISSPARSE(AT(a)))?QCNAMED+QCRAREQD+VALTYPESPARSE:QCNAMED+QCNOUN; // install QCSYMVAL flags: named, with type; FA needed iff sparse
xbuckptr->fval=MAKEFVAL(a,vtype); xbuckptr->sn=jt->currslistx;
if(likely(a!=w)&(SGNTO0(AC(a)&(((AT(a)^AFLAG(a))&RECURSIBLE)-1))&((I)jtinplace>>JTINPLACEAX))){
AFLAGORLOCAL(a,AFKNOWNNAMED); xbuckptr->flag=LPERMANENT|LWASABANDONED; ACIPNOABAND(a); ramkrecursv(a);
Expand Down Expand Up @@ -427,7 +429,7 @@ nextlinedebug:;
dobblock:
// B-block (present on every sentence in the B-block)
// run the sentence
parseline(z,if((UI)jt->tnextpushp-(UI)old>TPOPSLACK*SZI)tpop(old);,t=0;); // *** run user's line *** sets tcesx to thisline/nextline; t=0 so t doesn't have to be preserved over subrt calls
parseline(z,if((UI)jt->tnextpushp-(UI)old>TPOPSLACKB*SZI)tpop(old);,t=0;); // *** run user's line *** sets tcesx to thisline/nextline; t=0 so t doesn't have to be preserved over subrt calls
// if there is no error, step to next line. debug mode has set the value to use if any, or 0 to request a new line
if(likely(z!=0)){bic=ic; ic-=(tcesx>>(32+TCESXTYPEX+5))+1; // advance to next sentence to be executed, which is NSI, or NSI+1 if BBLOCKEND
// the sequence BBLOCKEND BBLOCKEND indicates that the second BBLOCKEND was originally an END that went to NSI which was BBLOCK, i. e. end. for an if./select. followed by BBLOCK.
Expand Down Expand Up @@ -466,13 +468,13 @@ nextlinedebug:;
// Check for assert. Since this is only for T-blocks we tolerate the test (rather than duplicating code)
if(unlikely(TEQ5(tcesx,CASSERT))){
if(JT(jt,assert)){
parseline(t,{if((UI)jt->tnextpushp-(UI)old>TPOPSLACK*SZI)if(likely((tcesx&((UI8)TCESXCECANT<<32))!=0))tpop(old);else z=gc(z,old);},);
parseline(t,{if((UI)jt->tnextpushp-(UI)old>(0)*SZI)if(likely((tcesx&((UI8)TCESXCECANT<<32))!=0))tpop(old);else z=gc(z,old);},); // 0 to force flushes during testcases
if(t&&!(NOUN&AT(t)&&all1(eq(num(1),t))))t=pee(cwsent,CWTCESX2(cwsent,ic),EVASSERT,NPGpysfmtdl<<(BW-2)); // if assert., signal post-execution error if result not all 1s.
if(likely(t!=0)){ // assert without error
t=mtv; // An assert is an entire T-block and must clear t afterward lest t be freed before it is checked by an empty while. So we use a safe permanent value, mtv.
}
}else{--ic; goto nextline;} // if ignored assert, go to NSI
}else{parseline(t,{if((UI)jt->tnextpushp-(UI)old>TPOPSLACK*SZI)if(likely((tcesx&((UI8)TCESXCECANT<<32))!=0))tpop(old);else z=gc(z,old);},);} // no assert: run the line resets tcesx to thisline/nextline
}else{parseline(t,{if((UI)jt->tnextpushp-(UI)old>(TPOPSLACKT)*SZI)if(likely((tcesx&((UI8)TCESXCECANT<<32))!=0))tpop(old);else z=gc(z,old);},);} // no assert: run the line resets tcesx to thisline/nextline
// this is return point from running the line
if(likely(t!=0)){tic=ic,--ic; // if no error, continue on. --ic must be in bounds for a non-assert T block (there must be another control word)
if(unlikely(TXOR5(tcesx,CDO)|jt->uflags.trace))goto nextlinetcesx; // next line not do.; T block extended to more than 1 line (rare).
Expand Down
5 changes: 2 additions & 3 deletions jsrc/j.h
Original file line number Diff line number Diff line change
Expand Up @@ -800,14 +800,13 @@ struct jtimespec jmtfclk(void); //'fast clock'; maybe less inaccurate; intended
#define NTSTACK (1LL<<(AUDITEXECRESULTS?24:14)) // number of BYTES in an allocated block of tstack - pointers to allocated blocks - allocation is bigger to leave this many bytes on boundary
#define NTSTACKBLOCK 2048 // boundary for beginning of stack block

#define TPOPSLACK 1 // number of stacked blocks to allow before we tpop them (in jtxdefn) - 0 means tpop every time
#define TPOPSLACKB 1 // number of stacked blocks to allow before we tpop them (in jtxdefn) - 0 means tpop every time - for B blocks
#define TPOPSLACKT 2 // number of stacked blocks to allow before we tpop them (in jtxdefn) - 0 means tpop every time - for T blocks

#define CWMAX 32766 // max # control words in an explicit defn. Must fit in signed 15-bit value because we complement it in storage
#define SWMAX 32767 // max # words in a sentence
#define EXPWMAX 16777215 // max # words in an explicit defn

#define LOCALRA 0 // ra() local names during lookup - must be set, but perhaps we can make it an option in explicit def

// flags for jteformat
#define EMSGE 0xff // the error-code part
#define EMSGNOEVM 0x200 // set to suppress moving the terse message
Expand Down
12 changes: 6 additions & 6 deletions jsrc/jtype.h
Original file line number Diff line number Diff line change
Expand Up @@ -759,8 +759,8 @@ struct AD {
#define ARNAMED ((I)1<<ARNAMEDX) // set in the rank of a named locale table. This bit is passed in the return from jtsyrd1
// bit 1 not used
// the rest of the flags apply only to local symbol tables
#define ARLCLONEDX NMSHAREDX // 4 set if this is a cloned local symbol table (in which symbol numbers are invalid)
#define ARLCLONED (1LL<<ARLCLONEDX) // set if this is a cloned local symbol table (in which symbol numbers are invalid)
#define ARLCLONEDX NMSHAREDX // 4 set if this is a cloned local symbol table (in which symbol numbers are invalid); OR in a global table that suppresses the check for locally-defined names
#define ARLCLONED (1LL<<ARLCLONEDX)
#define ARHASACVX 3 // set if this local symbol table contains an ACV
#define ARHASACV ((I)1<<ARHASACVX)
#define ARLOCALTABLE 16 // Set in rank of all local symbol tables. This indicates that the first hashchain holds x/y info and should not be freed as a symbol
Expand Down Expand Up @@ -914,10 +914,10 @@ typedef DST* DC;
#define STKNAMEDX 0
#define STKNAMED ((I)1<<STKNAMEDX) // set if the address is the address of the arg (rather than of a tpop slot)
#define ISSTKNAMED(w) ((I)(w)&STKNAMED) // is fa() required?
#define STKFAOWEDX 1 // till we have !LOCALRA, STKFAOWED is the same as STKLOCAL
#define STKFAOWED ((I)1<<STKFAOWEDX) // set in parser stack if value needs to be freed
#define STKREFRESHRQDX 2 // till we have !LOCALRA, STKFAOWED is the same as STKLOCAL
#define STKREFRESHRQD ((I)1<<STKREFRESHRQDX) // set in verb of a line 1-3 exec to indicate that tpop[aw] are stale and must be refreshed from the stack
#define STKFAOWEDX 1 // set in parser stack if value had ra() performed when it was stacked (or if ra() was performed later while on the stack)
#define STKFAOWED ((I)1<<STKFAOWEDX)
#define STKREFRESHRQDX 2 // set in verb of a line 1-3 exec to indicate that tpop[aw] are stale and must be refreshed from the stack
#define STKREFRESHRQD ((I)1<<STKREFRESHRQDX)
#define SETSTKFAOWED(w) (A)((I)(w)|STKFAOWED)
#define CLRSTKFAOWED(w) (A)((I)(w)&~STKFAOWED)
#define ISSTKFAOWED(w) ((I)(w)&STKFAOWED) // is fa() required?
Expand Down
6 changes: 2 additions & 4 deletions jsrc/p.c
Original file line number Diff line number Diff line change
Expand Up @@ -621,16 +621,14 @@ rdglob: ; // here when we tried the buckets and failed
if((pt0ecam&(NAMEBYVALUE>>(NAMEBYVALUEX-NAMEFLAGSX)))|((I)y&QCNOUN)){ // use value if noun or special name, or name_:
if(unlikely((pt0ecam&(NAMEABANDON>>(NAMEBYVALUEX-NAMEFLAGSX))))){ // is name_:?
// if name_:, go delete the name, leaving the value to be deleted later.
#if !LOCALRA
// If the value is local, we must ra it and any other local pointers on the stack
if(!ISFAOWED(y)&&!ACISPERM(AC(QCWORD(y)))&&!(AFLAG(QCWORD(y))&AFSENTENCEWORD)){ // if the name has been raised already, all stacked copies have been protected. If PERMANENT or from the executing sentence, needs no protecting
rapos(QCWORD(y),y); // ra() the new value first so that all args to undco have been ra()d
PSTK *sk;
// scan the stack to see if it is at large in the stack, setting FAOWED when it is. We don't call protectlocals because we need to protect just the one value and speed might matter
// scan the stack to see if the new value is at large in the stack, setting FAOWED when it is. We don't call protectlocals because we need to protect just the one value and speed might matter
// the stacked value might have been an unflagged non-NAMED result, but after we ra() it we must call it STKNAMED because only STKNAMED values get fa()d when they leave execution
for(sk=stack;sk!=stackend1;++sk){if(QCWORD(y)==QCWORD(sk->a) && !ISSTKFAOWED(sk->a)){rapos(QCWORD(y),y); sk->a=SETSTKNAMEDFAOWED(sk->a);}} // if the value we want to use is stacked already, it must be marked non-abondoned
}
#endif
FPSZSUFF(y=nameundco(jtinplace, QCWORD(*(volatile A*)queue), y), fa(QCWORD(y));)
}else y=SYMVALTOFAOWED(y) ; // if global, mark to free later
}else if(unlikely(QCPTYPE(y)==VALTYPENAMELESS)){
Expand Down Expand Up @@ -760,7 +758,7 @@ endname: ;
if(likely((s=(L*)(I)(NAV(QCWORD(*(volatile A*)queue))->symx&~REPSGN4(SGNIF4(pt0ecam,LOCSYMFLGX+ARLCLONEDX))))!=0)){
zval=QCWORD((SYMORIGIN+(I)s)->fval); // get value of symbol in primary table. There may be no value; that's OK
}else{zval=QCWORD(jtprobelocal(jt,QCWORD(*(volatile A*)queue),jt->locsyms));}
targc=LOCALRA?ACUC2:ACUC1; // since local values are not ra()d, they will have AC=1 if inplaceable. This will miss sparse values (which have been ra()d. which is OK
targc=ACUC1; // since local values are not ra()d, they will have AC=1 if inplaceable. This will miss sparse values (which have been ra()d. which is OK
}else{zval=QCWORD(probequiet(QCWORD(*(volatile A*)queue))); targc=ACUC2;} // global assignment, get slot address. Global names have been ra()d and have AC=2
// to save time in the verbs (which execute more often than this assignment-parse), see if the assignment target is suitable for inplacing. Set zombieval to point to the value if so
// We require flags indicate not read-only, and correct usecount: 1 if local, 2 if global since we have raised the count of this block already if it is named and to be operated on inplace; +1 if NJA to account for the mapping reference.
Expand Down
2 changes: 1 addition & 1 deletion jsrc/pv.c
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ F1(jtvtrans){PROLOG(0053);A locsyms,y,z=0;I c,i,ttabi;TA ttab[NTTAB];
RZ(y=vtokens(w)); // return AM bit0=monad
I tmonad=AM(y);
ttabi=c;
RZ(locsyms=stcreate(2,40,0L,0L)); AR(locsyms)&=~ARLOCALTABLE; // not necessary to set global pointers; flag table so we don't switch to locsyms during assignment
RZ(locsyms=stcreate(2,40,0L,0L)); AR(locsyms)^=ARLOCALTABLE+ARLCLONED; // not necessary to set global pointers; flag table so we don't switch to locsyms during assignment, and suppress the check for local definitions
symbis(mnuvxynam[5],num(1),locsyms); if(!tmonad)symbis(mnuvxynam[4],num(1),locsyms);
WITHMSGSOFF(z=jttparse(jt,y,locsyms,tmonad,0==i,ttab,&ttabi,c);)
if(i&&!z)z=colon(num(4-tmonad),w);
Expand Down
16 changes: 9 additions & 7 deletions jsrc/s.c
Original file line number Diff line number Diff line change
Expand Up @@ -689,7 +689,8 @@ A jtprobequiet(J jt,A a){A g;
R res;
}

// assign symbol: assign name a in symbol table g to the value w (but g is ignored if a is a locative)
// assign symbol: assign name a in symbol table g to the value w
// g is always the current local or global symbol table (but g is ignored if a is a locative). If a is not a locative and g is a local table,
// Result is 0 if error, otherwise low 2 bits are x1 = final assignment, 1x = local assignment, others garbage
// flags set in jt: bit 0=this is a final assignment; bit 1 always 0
I jtsymbis(J jt,A a,A w,A g){F2PREFIP;
Expand All @@ -701,7 +702,7 @@ I jtsymbis(J jt,A a,A w,A g){F2PREFIP;
// It is safe to do the recursive-usecount change here as local, because the value cannot have been released to any other core. Similarly for
// virtuals.
// Find the internal code for the name to be assigned. Do this before we take the lock.
I wt=AT(w);
I wt=AT(w); I gr=AR(g); // type of w, rank-flags for g
rifv(w); // must realize any virtual
if(unlikely(((wt^AFLAG(w))&RECURSIBLE)!=0)){AFLAGORLOCAL(w,wt&RECURSIBLE) wt=(I)jtra(w,wt,(A)wt);} // make the block recursive (incr children if was nonrecursive). This does not affect the usecount of w itself.

Expand All @@ -711,7 +712,8 @@ I jtsymbis(J jt,A a,A w,A g){F2PREFIP;
C*s=1+m+NAV(a)->s; if(unlikely(anmf&NMILOC))g=locindirect(n-m-2,1+s,NAV(a)->bucketx);else g=stfindcre(n-m-2,s,NAV(a)->bucketx);
}else{ // not locative assignment

if(g==jt->global){ // global assignment.
// obsolete if(g==jt->global){ // global assignment.
if(!(gr&ARLOCALTABLE+ARLCLONED)){ // global assignment, and the symbol table does not suppress the check for local names
// check for non-locative global assignment to a locally-defined name. Give domain error and immediately eformat, since no one has a self for assignment
// this test will usually have a positive bucketx and will not call probelocal. Unlikely that symx is present
I localnexist=REPSGN(NAV(a)->bucketx|SGNIF(AR(jt->locsyms),ARNAMEADDEDX)); // 0 if bucketx nonneg (meaning name known but not locally assigned) AND no unknown name has been assigned: i. e. no local def ~0 otherwise
Expand All @@ -729,18 +731,18 @@ I jtsymbis(J jt,A a,A w,A g){F2PREFIP;

if(unlikely((((NAV(a)->flag&NMLOC+NMILOC+NMIMPLOC)-1)&SGNIF(FAV(w)->flag2,VF2NAMELESSX))<0))valtype=VALTYPENAMELESS; // nameless & non-locative, so indicate
if(unlikely(jt->glock!=0))if(likely(FAV(w)->fgh[0]!=0)){FAV(w)->flag|=VLOCK;} // fn created in locked function is also locked
if((AR(g)&ARLOCALTABLE)!=0)AR(g)|=ARHASACV; // if we assign a non-noun to a local table, note the fact so we will look them up
if(unlikely(gr&ARLOCALTABLE))AR(g)|=ARHASACV; // if we assign a non-noun to a local table, note the fact so we will look them up there
}

L *e; // the symbol we will use
// we don't have e, look it up.
// We reserve 1 symbol for the new name, in case the name is not defined. If the name is not new we won't need the symbol.
// convert valtype to QCSYMVAL semantics: NAMED always, RAREQD if global table or sparse
if((AR(g)&ARLOCALTABLE)!=0){ // if assignment to a local table (which might not be jt->locsyms)
if((gr&ARLOCALTABLE)!=0){ // if assignment to a local table (which might not be jt->locsyms)
I4 symx=NAV(a)->symx; // fetch the symbol slot assigned to this name (0 if none)
e=likely((SGNIF(AR(g),ARLCLONEDX)|(symx-1))>=0)?SYMORIGIN+(I)symx:probeislocal(a,g); // local symbol given and we are using the original table: use the symbol. Otherwise, look up and reserve 1 symbol
e=likely((SGNIF(gr,ARLCLONEDX)|(symx-1))>=0)?SYMORIGIN+(I)symx:probeislocal(a,g); // local symbol given and we are using the original table: use the symbol. Otherwise, look up and reserve 1 symbol
g=(A)((I)jtinplace|-JTASGNWASLOCAL); // indicate local assignment (we have no lock to clear), remember final assignment
valtype|=QCNAMED|(LOCALRA?QCRAREQD:REPSGN(wt)&QCRAREQD); // enter QCSYMVAL semantics; ra needed if sparse
valtype|=QCNAMED|(REPSGN(wt)&QCRAREQD); // enter QCSYMVAL semantics; ra needed if sparse
}else{ // global table
SYMRESERVE(1) // before we go into lock, make sure we have a symbol to assign to
C *bloombase=BLOOMBASE(g); I chainno=SYMHASH(NAV(a)->hash,AN(g)-SYMLINFOSIZE); // get addr of Bloom filter and the location we are storing to
Expand Down
5 changes: 3 additions & 2 deletions jsrc/va2.c
Original file line number Diff line number Diff line change
Expand Up @@ -1248,7 +1248,7 @@ DF2(jtfslashatg){A fs,gs,y,z;B b;C*av,*wv;I ak,an,ar,*as,at,m,
DF2(jtatomic2){A z;
F2PREFIP;ARGCHK2(a,w);
UI ar=AR(a), wr=AR(w); I at=AT(a), wt=AT(w); I af;
if((ar+wr+((at|wt)&((NOUN|SPARSE)&~(B01+INT+FL))))==0){af=0; goto forcess;} // if args are both atoms, verb rank is immaterial - run as singleton
if((ar+wr+((at|wt)&((NOUN|SPARSE)&~(B01+INT+FL))))==0){af=0; goto forcess;} // if args are both INT/FL/B01 atoms, verb rank is immaterial - run as singleton
A realself=FAV(self)->fgh[0]; // if rank operator, this is nonzero and points to the left arg of rank
RANK2T selfranks=FAV(self)->lrr; // get left & right rank from rank/primitive
self=realself?realself:self; // if this is a rank block, move to the primitive to get to the function pointers. u b. or any atomic primitive has f clear
Expand Down Expand Up @@ -1288,7 +1288,8 @@ forcess:; // branch point for rank-0 singletons from above, always with atomic
selfranks=jtranks==R2MAX?selfranks:jtranks;
}
// self, awr, and selfranks are needed in the retry
}
}
// not singleton, or singleton needing retry

ASSERTAGREE(AS(a),AS(w),af); // outermost (or only) agreement check
NOUNROLL while(1){
Expand Down
4 changes: 2 additions & 2 deletions jsrc/x.c
Original file line number Diff line number Diff line change
Expand Up @@ -380,8 +380,8 @@ MN(18,7) XPRIM(VERB, jtsetpermanent, 0, VFLAGNONE,VF2NONE,RMAX,RMAX,RM

// called at initialization after memory reset, to assign cocurrent_z_ and coclass_z_. The 18!:4 block is at the end of foreignA and is a read-only value
I jtforeignassigninit(J jt){A nm;L *e;
RZ(nm=nfs(12,"cocurrent_z_")); symbis(nm,(A)&foreignA[(sizeof(foreignA)/sizeof(foreignA[0]))-1],0); e=probeisres(nm, *JT(jt,zpath)); e->flag|=LREADONLY;
RZ(nm=nfs(10,"coclass_z_")); symbis(nm,(A)&foreignA[(sizeof(foreignA)/sizeof(foreignA[0]))-1],0); e=probeisres(nm, *JT(jt,zpath)); e->flag|=LREADONLY;
RZ(nm=nfs(12,"cocurrent_z_")); symbis(nm,(A)&foreignA[(sizeof(foreignA)/sizeof(foreignA[0]))-1],jt->global); e=probeisres(nm, *JT(jt,zpath)); e->flag|=LREADONLY; // the assignment is in z, but we need...
RZ(nm=nfs(10,"coclass_z_")); symbis(nm,(A)&foreignA[(sizeof(foreignA)/sizeof(foreignA[0]))-1],jt->global); e=probeisres(nm, *JT(jt,zpath)); e->flag|=LREADONLY; // ... a valid global table as an arg
R 1;
}

Expand Down
2 changes: 1 addition & 1 deletion jsrc/xt.c
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ foundsym:; // we found the symbol. Install its info. sym is the symbol, SYMNE
A *old=jt->tnextpushp;
t=qpc(); // start time
// We attempt to run as if under jtxdefn, so we check ATTN and jt->jerr as a replacement for reading from the word block; and we tpop like jtxdefn
DQ(n, z=PARSERVALUE(parsea(wv,wn)); if(unlikely(!z))break; ASSERT((__atomic_load_n((S*)JT(jt,adbreakr),__ATOMIC_ACQUIRE)&3)==0,EVATTN) RE(0) if((UI)jt->tnextpushp-(UI)old>TPOPSLACK*SZI)tpop(old););
DQ(n, z=PARSERVALUE(parsea(wv,wn)); if(unlikely(!z))break; ASSERT((__atomic_load_n((S*)JT(jt,adbreakr),__ATOMIC_ACQUIRE)&3)==0,EVATTN) RE(0) if((UI)jt->tnextpushp-(UI)old>TPOPSLACKB*SZI)tpop(old););
t=qpc()-t; // Run the sentence. No need to run as exec since the result doesn't escape. tpop like jtxdefn. no tpop on error.
if(unlikely(stackallo))debz();
RZ(z); // if error, fail the timing request
Expand Down
4 changes: 4 additions & 0 deletions test/g4x.ijs
Original file line number Diff line number Diff line change
Expand Up @@ -220,15 +220,18 @@ b =: 7!:0''
1e6 1e6 -: (# a_:) , # a NB. deleted, stack deferred
b > 2e6+7!:0''
'value error' -: ". etx 'a + 5'

1 -: 3 : 0 ''
a =. i. 1e6
b =. 7!:0''
assert. 1e6 -: # a_:
for. i. 6 do. b end.
assert. b > 2e6+7!:0''
assert. 'value error' -: ". etx 'a + 5'
a =. i. 1e6
b =. 7!:0''
assert. 1e6 -: ". '# a_:' NB. not deleted inside ".
for. i. 6 do. b end.
assert. b < 1e6+7!:0''
assert. 1e6 -: # a
a =. i. 1e6
Expand All @@ -240,6 +243,7 @@ assert. 2e6 -: # a_: , a NB. deleted, stack deferred
a =. i. 1e6
b =. 7!:0''
assert. 1e6 1e6 -: (# a_:) , , # a NB. deleted, stack deferred
for. i. 6 do. b end.
assert. b > 2e6+7!:0''
assert. 'value error' -: ". etx 'a + 5'
a =. 1
Expand Down
Loading

0 comments on commit abffee0

Please sign in to comment.