Nombas Homepage

Scripting

Products

Purchase

Download

Support

Company

Nombas > SE:ISDK DevSpace > Errata > Integration SDK 5.01x Errata

 

Integration SDK 5.01x Errata
Fixes Affecting Users of the ScriptEase ISDKs

API Errata, version 5.01b
  New, June 8, 2004

API Errata, version 5.01a
  New, March 19, 2004

The Details

for 5.01b -- (may apply to earlier version)

  • inner function may cause assertion in Call.jsrc
    (for ISDK/Java 5.01b)

Issue: A function containing an inner function may cause an assertion to be thrown around line 2153 (`SEVAR_GET_TYPE(wv)>=VReference').

Fix : In COM/Nombas/jse/Isdk/Call.jsrc around line 9619 there is a block of code like this:

   if( (flags&SE.START) != 0 )
      {
         EvalFuncStart start_info = new EvalFuncStart();

         if( start_info==null )

On the line just above that if statement, add this statement:

    SEVAR_INIT_UNDEFINED(CALL_NEWSCOPE(this));

  • string.replace() may get caught in near-infinite loop
    (for ISDK/Java 5.01b)

Issue: If string.replace() is called using the global flag and such that the result of the search expression replaces the null-patch at the end of the line, then replace may run for a long long while (until a memory object is returned). This is an example of a problem script.

   "a".replace( /a*/g, "stuff" );

Fix : In COM/Nombas/jse/libraries/ECMAString.jsrc make the following changes:

1) near line 872 replace the definition of the replace_string() method from this:

    private static void replace_string(... 

to this

   private static int replace_string(...

2) add the following return statement at the end of the replace_string() method (around line 1042):

   return replace_text.length();

3) in function string_search_helper(), near line 1272, follow this line:

   SEObject eval_ret = se.seGetObject(SE.RETURN,SE.VALUE);

with this additional line

   int replace_len = 0;

and about seven lines below that replace

   replace_string(se,se.seGetObject(eval_ret,SE.VALUE) ...

with

   replace_len = replace_string(se,se.seGetObject(eval_ret,SE.VALUE) ...

4) around line 3788 of the same function replace this block

   if( new_index==last_index )
   {
      new_index++;

with this

   if( new_index == (last_index+replace_len) )
   {
      new_index = 1 + (last_index+replace_len);

  • string.replace() incorrect if first arguments is not a RegExp object
    (for ISDK/Java 5.01b)

Bug: If the first parameter to String.prototype.replace() is not a RegExp object then it will be compiled into a RegExp object. This is incorrect behavior and based on an incomplete version of the EcmaScript specification. Instead, if the first arguments is not a RegExp object then it should be converted into a string and a direct string replacement should follow.

Fix : In COM/Nombas/jse/libraries/ECMAString.jsrc, replace the function Ecma_String_replace() at about line 1364 with both functions in the code at ftp://ftp.nombas.com/pub/isdkeval/se501/ecma_string_replace.jsrc

for 5.01a --

  • seGetSourceFunc() callback being called an extra time when script is missing a closing brace
    (for ISDK/Java 5.01a)

Issue: When a script that is missing a closing brace ('}') is being compiled by the ScriptEase engine, the seGetSourceFunc() method of the SEGetSourceFunc interface gets called by the engine with the SE.SOURCE_GETLINE flag one time too many. That is to say, after the seGetSourceFunc() has been called with the SE.SOURCE_GETLINE flag and has returned false once, on the next call to seGetSourceFunc() the ScriptEase engine should pass it the SE.SOURCE_CLOSE flag, but instead the engine calls it one more time passing it the SE.SOURCE_GETLINE flag before calling it a final time passing it the SE.SOURCE_CLOSE flag. This can be a source of error if the seGetSourceFunc()'s SE.SOURCE_GETLINE handler does not expect to be called anymore once it has returned false to the ScriptEase engine.

Fix: To fix this issue, go to the statement() method in COM/Nombas/jse/Isdk/SECompile.jsrc. Within the switch statement, there is a case statement for the character '{'. In that case statement (at approx. line 3915), add the following code inside the while() loop, before the code already in that loop:

   if ( tokType(this.token)==seTokEOF )
   {
      success = false;
      call.quit(TextCore.BAD_PRIMARY);
      break;
   }

So now your while() loop should look like this:

   while( tokType(this.token)!='}' )
   {
      if ( tokType(this.token)==seTokEOF )
      {
         success = false;
         call.quit(TextCore.BAD_PRIMARY);
         break;
      }

      if( !this.statement() )
      {
         success = false;
         break;
      }
   }

  • seMustPutXXX() and seMustPutDirectXXX() unsetting most variable attributes
    (for ISDK/Java 5.01a)

Bug: The seMustPutXXX() and seMustPutDirectXXX() functions strip variable attributes, such as SE.DONTENUM and SE.READONLY, from the variable on which they are called.

Fix: A simple workaround is to call seSetAttribs after calling seMustPutXXX() and seMustPutDirectXXX(). Or to fix the source code in COM/Nombas/jse/Isdk/Call.jsrc, method sePutMember(), at about line 7188 replace:

   obj.newMember(this,name,tmp,
                  SE.DEFAULT,SE_OBJECT.SE_NM_UPDATE);

with:

   obj.newMember(this,name,tmp,
                  attrib,SE_OBJECT.SE_NM_UPDATE);

Also, at about line 7251 replace:

   obj.newMember(this,name,tmp,
                  SE.DEFAULT,SE_OBJECT.SE_NM_UPDATE);

with:

   obj.newMember(this,name,tmp,
                  attrib,SE_OBJECT.SE_NM_UPDATE);

  • sePutWrapper() ignoring the variable attributes
    (for ISDK/Java 5.01a)

Bug: The sePutWrapper() variable attributes (such as SE.DONTENUM) are being ignored.

Fix: A simple workaround is to call seSetAttribs after calling sePutWrapper(). Or to fix the source code in COM/Nombas/jse/Isdk/Call.jsrc, method sePutWrapperEx(), at about line 9003 replace:

   ret = call.sePutMember(obj,memdesc,flags);

with:

   if ( !call.sePutMember(obj,memdesc,flags) || SE.DEFAULT != desc.VarAttrFlags )
      this.seSetAttribs(obj,memdesc,desc.VarAttrFlags);

  • Date parser not recognizing 12 AM or "UTC"
    (for ISDK/Java 5.01a)

Problem: When parsing a date/time with "12:00 AM UTC" the date parser is not recognizing this as midnight, but is instead registering that time as noon. Also, although the ECMAScript specification sets "GMT" as the tag for declaring universal time, it has become common to also use "UTC".

Change: In COM/Nombas/jse/libraries/SEDate.jsrc, method do_parse(String), at around line 632, just before the comment that begins "/* if there is a PM anywhere..." add this code:

   /* if it is 12, but 12 AM, then that time is really 0 */ 
   if ( (time[0] == 12) && (DateBuf.indexOf("am")!= -1) ) 
      time[0] = 0;

and then around line 758 change this code:

   gmt = DateBuf.indexOf("gmt"); 
   if ( gmt == -1 )

to this:

   if ( (-1 == (gmt = DateBuf.indexOf("gmt"))) 
     && (-1 == (gmt = DateBuf.indexOf("utc"))) )

  • Function constructor causes swapping for created functions
    (for ISDK/Java 5.01a)

Problem: When JSE_MULTIPLE_GLOBAL is defined (the default), any anonymous function created at runtime with the Function constructor will preserve the global from when the Function library was loaded (usually at program initialization). This will cause the global to change to the original global whenever that anonymous function is later called.

Change: To keep the Function constructor from restoring its own global replace add the SE_KEEP_GLOBAL line 2294 of COM/Nombas/jse/libraries/ECMAObject.jsrc so it becomes:

   SE.CLASS( JseStr.Function, WRAPPER_FUNC(Ecma_Function_construct), 0, -1,
             SE.SECURE|SE.KEEP_GLOBAL, SE.DONTENUM ),

  • String match function should return null on no match
    (for ISDK/Java 5.01a)

Issue: According to the commonly recognized ECMAScript Edition 3 Errata, string.match should return NULL if there are no items matched. This differs from the ECMAScript document, and from our 5.01a code, which would return a zero-length array.

Change: To get the return-null behavior, In COM/Nombas/jse/libraries/ECMAString.jsrc, near the end of string_which_search_helper() (at about line 1334) replace this code:

   if( mode==SE_MATCH_MODE )
   {
      se.sePutObject(SE.RETURN,SE.VALUE,ret);
   }

with

   if( mode==SE_MATCH_MODE )
   {
      if ( array_index == 0 )
      {
         /* this part of the code is a result of the ECMA-262 errata */
         se.sePutNull(SE.RETURN,SE.VALUE);
      }
      else
      {
         se.sePutObject(SE.RETURN,SE.VALUE,ret);
      }
   }

  • seGetSourceFunc(...seSourceGetLine...) called twice if first call returns False
    (for ISDK/Java 5.01a)

Bug: If seGetSourceFunc(...SE.SOURCE_GETLINE...) returns false the first time it is called, it will be called again a second time.

Fix: In COM/Nombas/jse/Isdk/Source.jsrc, method newFromFile(), change the code after !This.nextLine() (around line 190) from:

   This.MemoryPtr = new SourcePtr("\0");

to

   Success[0] = false; 

  • string.split returns undefined element 0 if no match
    (for ISDK/Java 5.01a)

Bug: If String.prototype.split(delimeter) is called, but there is no delimeter matched, then this function should return a 1-element array with the original string as element 0. Instead it is wrongly returning and undefined type as element 0.

Fix: In COM/Nombas/jse/libraries/ECMAString.jsrc, function Ecma_String_split, at about line 425 this statement:

   se.seAssign(ret,SE.NUM(se.seGetLong(ret,SE.STOCK(JseStrID.length))),
               SE.WRAPPER_TEMP, SE.MEM("temp"));

should be changed to:

   se.sePutString(ret,SE.NUM(se.seGetLong(ret,SE.STOCK(JseStrID.length))),str);

  • converting a recursive array to a string can crash
    (for ISDK/Java 5.01a)

Bug: In an array contains a recursive element that recursively refers back to the array, and if the array is then converted to a string, then the scriptease engine will crash. The following script demonstrates the problem:

   var a = new Array( "a", "b", "c" );
   a[1] = new Array( a, 2, 3 );
   var foo = "" + a; // will crash here from recursion

Fix: In COM/Nombas/jse/libraries/ECMAObject.jsrc, method Ecma_Array_join, after the declaration of variables (around line 624) add this block:

   /* if this object was already visited, then just return a blank string */
   if ( se.seExists(SE.THIS,SE.HIDDEN_MEM(PREVENT_RECURSION_NAME)) )
   {
      se.sePutString(SE.RETURN,SE.VALUE,"");
      return;
   }
   se.sePutBool(SE.THIS,SE.HIDDEN_MEM(PREVENT_RECURSION_NAME),true);

and add the following as the final line of function Ecma_Array_join:

   se.seDelete(SE.THIS, SE.HIDDEN_MEM(PREVENT_RECURSION_NAME));

Finally, add this line outside the of the Ecma_Array_join method:

   private static final String PREVENT_RECURSION_NAME = "join recursed";                                   

  • no flag provided to bypass dynamic callbacks, but allow for prototype chain
    (for ISDK/Java 5.01a)

Bug: SE.GF_DIRECT (as used by the seGetDirect and seGetEx calls) bypasses the dynamic callbacks and the prototype chain. SE.GF_NOPROTOTYPE bypasses the prototype chain but not the callbacks. There is no corresponding call to skip dynamic callbacks but still allow access via the prototype chain.

Fix: Add a new SE.GF_NOCALLBACKS option to bypass callbacks but still allow access via the prototype chain. This fix assumes that the HP_DIRECTCHECK errata has already been applied. In COM/Nombas/jse/Isdk/SE.jsrc at about line 113 replace this line:

   public final static int GF_DIRECT =             0x001;

with these two lines:

   public final static int GF_NOCALLBACKS =        0x001;
   public final static int GF_DIRECT =             (GF_NOPROTOTYPE|GF_NOCALLBACKS);

and in COM/Nombas/jse/Isdk/AbstractVar.jsrc near line 67 and in COM/Nombas/jse/Isdk/_SEVar.jsrc near line 279 change

   static final int GV_NO_PROTOTYPE = SE.GF_NOPROTOTYPE;
   static final int GV_NO_DYNAMIC =   SE.GF_NOCALLBACKS;

to

   static final int GV_NO_PROTOTYPE = SE.GF_NOPROTOTYPE;
   static final int GV_NO_DYNAMIC =   SE.GF_NOCALLBACKS;

and then in COM/Nombas/jse/Isdk/Call.jsrc and COM/Nombas/jse/Isdk/SEContext.jsrc change every reference from

   SE.GF_DIRECT

to

   SE.GF_NOCALLBACKS

and also in COM/Nombas/jse/Isdk/Call.jsrc, function notThere(), at around line 6593 change

   direct = true;

to

   flags |= SE.GF_NOCALLBACKS;

finally, about 17 lines later, replace this block:

 int f = ( ((flags & SE.GF_DIRECT) != 0) || direct )
    ? ( SE_VAR.GV_NO_PROTOTYPE | SE_VAR.GV_NO_DYNAMIC )
    : ( ( (flags & SE.GF_NOPROTOTYPE) != 0 ) ? SE_VAR.GV_NO_PROTOTYPE :
         SE_VAR.GV_DEFAULT );
    SEVAR_INIT_OBJECT(tmpobj,obj);

    ret = tmpobj.getValue(this,name,this.api_temp,f);

with this

   SEVAR_INIT_OBJECT(tmpobj,obj);
   ret = tmpobj.getValue(this,name,this.api_temp,flags);

  • calling byref function turns all local variables into references
    (for ISDK/Java 5.01a)

Bug: If a byref function is called from within another function, all of the local variables in the outer function will be turned into references.

Fix: In COM/Nombas/jse/Isdk/Secode.jsrc, method interpret(), near line 1002 this block of code:

 if( FUNCTION_PASSBYREF(function) ||
    (FUNCTION_IS_LOCAL(function) &&
    with_tmp < ((LocalFunction)function).localItems.InputParameterCount &&
    ((LocalFunction)function).localItems.items[with_tmp].VarAttrib != 0) )
 {
    /* In this case we have pass-by-reference */
    SEVAR_INIT_UNDEFINED(w_lhs);
    if( CALL_VAROBJ(call)==null )
       call.createVariableObject(null,0);
 }

 SEVAR_COPY(w_lhs,w_rhs);

 break;

should be changed to this code:

  if( FUNCTION_PASSBYREF(function) ||
     (FUNCTION_IS_LOCAL(function) &&
     with_tmp < ((LocalFunction)function).localItems.InputParameterCount &&
     ((LocalFunction)function).localItems.items[with_tmp].VarAttrib != 0) )
  {
     /* In this case we have pass-by-reference */
     SEVAR_INIT_UNDEFINED(w_lhs);
     if( CALL_VAROBJ(call)==null )
        call.createVariableObject(null,0);

     SEVAR_COPY(w_lhs,w_rhs);

  }
  else
  {
     /* The local variable could be a reference into the variable object.
      * If this is true, it will be passed by reference even though it
      * should not be. To avoid this, we now copy the variable to the stack
      * and dereference it.
      */
      SEVAR_COPY(w_lhs,w_rhs);
      SEVAR_DEREFERENCE(call,w_lhs);
  }

  break;

  • too many callbacks for global get and for hasprop returning HP_DIRECTCHECK
    (for ISDK/Java 5.01a)

Bug: If the global object has a get callback, then get is called too often while initializing code. Also, if any hasProp callback is returning HP_DIRECTCHECK then the get callback is being called, although it shouldn't.

Fix: In COM/Nombas/jse/Isdk/Call.jsrc, method function(), near line 2122 this block of code:

   SE_VAR wLoc = STACK_PUSH(this);
   SE_VAR wTmp = STACK_PUSH(this);

   SEVAR_INIT_UNDEFINED(wTmp);
   SEVAR_INIT_OBJECT(wLoc,CALL_VAROBJ(this));
   wLoc.getDotNamedVar(this,this.GetStringTableEntry(ourname),
                       SE.DEFAULT);

   if( hif_func!=null )
   {
      SEVAR_INIT_OBJECT(wTmp,hif_func);
  
      if ( VObject == SEVAR_GET_TYPE(CALL_NEWSCOPE(this)) )
      {
         SE_OBJECT hobj;
      
         hobj = SEVAR_GET_OBJECT(CALL_NEWSCOPE(this));
         assert( null != hobj );
         if( 0<hobj.used )
         {
            wTmp.data = hobj;
         }
      }
   }
   else
   {
      SEVAR_INIT_UNDEFINED(wTmp);
   }

should be changed to this code:

   SE_VAR wLoc = STACK_PUSH(this);
   SE_VAR wTmp = STACK_PUSH(this);
   
   if( hif_func!=null )
   {
      SEVAR_INIT_OBJECT(wTmp,hif_func);
      SEVAR_INIT_OBJECT(wLoc,CALL_VAROBJ(this));
      wLoc.getDotNamedVar(this,this.GetStringTableEntry(ourname),
                          SE.DEFAULT);
      if ( VObject == SEVAR_GET_TYPE(CALL_NEWSCOPE(this)) )
      {
         SE_OBJECT hobj;
         
         hobj = SEVAR_GET_OBJECT(CALL_NEWSCOPE(this));
         assert( null != hobj );
         if( 0<hobj.used )
         {
            wTmp.data = hobj;
         }
      }
   }
   else
   {
      SEVAR_INIT_UNDEFINED(wTmp);
      SEVAR_INIT_REFERENCE(wLoc,CALL_VAROBJ(this),ourname);
   }

Then in COM/Nombas/jse/Isdk/Call.jsrc method notThere(), near line 6566 replace the else block that begins with this line:

   SE_VAR tmpobj = STACK_PUSH(this);

with this block

   SE_VAR tmpobj = STACK_PUSH(this);
   direct = false;
   
#  if JSE_DYNAMIC_CALLBACKS==1
   ret = true;
   SEVAR_INIT_UNDEFINED(tmpobj);
   /* If the object says it does not have the property,
    * believe it. Return false with the undefined value.
    */
   if( (flags&SE.GF_NOCALLBACKS)==0
       && SEOBJ_IS_DYNAMIC_PROP(this,obj,SEHasPropCallback)
       && !this.Global.stringTable.isHiddenProp(name) )
   {
      if( obj.callDynamicProperty(this,SE.HASPROP_CALLBACK,
                                  name,null,tmpobj) )
      {
         if ( SE.HP_HASNOT == SEVAR_GET_SLONG(tmpobj) )
         {
            ret = false;
            SEVAR_INIT_UNDEFINED(this.api_temp);
         }
      }
      else
      {
         if ( VNumber == SEVAR_GET_TYPE(tmpobj) )
         {
            if ( SE.HP_DIRECTCHECK == SEVAR_GET_SLONG(tmpobj) )
               direct = true;
         }
      }
   }
   
   if( ret )
      
#  endif
   {
      int f = ( ((flags & SE.GF_DIRECT) != 0) || direct )
         ? ( SE_VAR.GV_NO_PROTOTYPE | SE_VAR.GV_NO_DYNAMIC )
         : ( ( (flags & SE.GF_NOPROTOTYPE) != 0 ) ? SE_VAR.GV_NO_PROTOTYPE :
             SE_VAR.GV_DEFAULT );
      SEVAR_INIT_OBJECT(tmpobj,obj);
      
      ret = tmpobj.getValue(this,name,this.api_temp,f);
   }
   
   
   STACK_POP(this);

And in COM/Nombas/jse/Isdk/_SEObject.jsrc, method seobjCallDynamicProperty(), replace "case SE.HASPROP_CALLBACK:" around line 1097 with this code:

   case SE.HASPROP_CALLBACK:
   {
      int cp = DYNA_CALLBACK1(((SEHasPropCallback)cb).hasProp,prop_name);
      
      if ( cp < 0 )
      {
         assert( cp==SE.HP_CHECK || cp==SE.HP_DIRECTCHECK );
         done = false;
      }
      else
      {
         assert( cp==SE.HP_HAS || cp==SE.HP_HASNOT );
      }
      assert( result!=null );
      SEVAR_INIT_SLONG(result_tmp,cp);
      break;
   }

then around line 1354 replace these lines (in the hasProperty()) method:

   STACK_POP(this);
   
   /* Call the 'get' to get the property */

with this block

   else
   {
      /* that hasprop callback may have returned HP_DIRECTCHECK which means we act as
       * if there were no callbacks at all
       */
      if ( VNumber == SEVAR_GET_TYPE(value) )
      {
         if ( SE.HP_DIRECTCHECK == SEVAR_GET_SLONG(value) )
         {
            //STACK_POP(call); /* value */
            goto_standard_directcheck = true;
         }
      }
   }
   
   STACK_POP(call); /* value */

   /* Call the 'get' to get the property */

next, around line 1380 find this code

   /* Call the 'get' to get the property */
   
   /* either no dynamic _hasProperty (!handled) or
    * _hasProperty says 'yes it has the property' and
    * dest is not NULL, so we need to retrieve the property
    * In either case, we have to do a dynamic get because we
    * need the value
    */
   if ( (rhs=dest)==null )
   {
      rhs = STACK_PUSH(call);
      SEVAR_INIT_OBJECT(rhs,this);
   }
   /* can't use SEVAR_DEREFERENCE because this
    * could be a real dynamic object
    */
   
#  if JSE_ALWAYS_COLLECT==1
   /* on some occasions calldyna will happen and GC may happen, so force it always */
   Garbage.garbageCollect(call);
#  endif
   
   if( this.callDynamicProperty(call,SE.GET_CALLBACK,propname,null,rhs) )
   {
      /* If hasProperty says yes, then undefined means undefined. Otherwise,
       * Undefined is the only way to differentiate a has it from does not
       * have it.
       */
      boolean ret = (SEVAR_GET_TYPE(rhs)!=VUndefined) || handled;
      if( ret && (flags&HP_REFERENCE)!=0 )
      {
         SEVAR_INIT_REFERENCE(rhs,this,propname);
      }
      if ( dest==null )
      {
         STACK_POP(call);
      }
      return ret;
   }
   if ( dest==null )
   {
      STACK_POP(call);
   }

and change it to this (wrap it in an if-block):

   if ( !goto_standard_directcheck )
   {

      /* Call the 'get' to get the property */
            
      /* either no dynamic _hasProperty (!handled) or
       * _hasProperty says 'yes it has the property' and
       * dest is not NULL, so we need to retrieve the property
       * In either case, we have to do a dynamic get because we
       * need the value
       */
      if ( (rhs=dest)==null )
      {
         rhs = STACK_PUSH(call);
         SEVAR_INIT_OBJECT(rhs,this);
      }
      /* can't use SEVAR_DEREFERENCE because this
       * could be a real dynamic object
       */

#     if JSE_ALWAYS_COLLECT==1
      /* on some occasions calldyna will happen and GC may happen, so force it always */
      Garbage.garbageCollect(call);
#     endif

      if( this.callDynamicProperty(call,SE.GET_CALLBACK,propname,null,rhs) )
      {
         /* If hasProperty says yes, then undefined means undefined. Otherwise,
          * Undefined is the only way to differentiate a has it from does not
          * have it.
          */
         boolean ret = (SEVAR_GET_TYPE(rhs)!=VUndefined) || handled;
         if( ret && (flags&HP_REFERENCE)!=0 )
         {
            SEVAR_INIT_REFERENCE(rhs,this,propname);
         }
         if ( dest==null )
         {
            STACK_POP(call);
         }
         return ret;
      }
      if ( dest==null )
      {
         STACK_POP(call);
      }
   }

finally, add this line at the top of the hasProperty() method

   boolean goto_standard_directcheck = false;
                                 
      

 
   

Home | Scripting | Products | Purchase | Download | Support | Company

Copyright ©2001, Nombas, Inc. All Rights Reserved.
Questions? Visit
http://support.nombas.com/