Menu

No more non-speaking "Attempt to call nil" messages :)

2015-03-22
2016-02-29
  • Stefan Reich

    Stefan Reich - 2015-03-22

    Another little idea for LuaJ that I like a lot - "named nils". Don't
    you hate those non-speaking "attempt to call nil" messages, too? =)

    Add to Lua.java:

        /** disable for more speed */
        public static final boolean useNamedNil = true;
    
        public static LuaValue namedNil(LuaValue name) {
                return useNamedNil ? new NamedNil(name) : NIL;
        }
    

    Create this class:

    package org.luaj.vm2;
    
    public class NamedNil extends LuaNil {
      public LuaValue name;
    
      public NamedNil(LuaValue name) {
        this.name = name;
      }
    }
    

    Change 2 functions in LuaTable:

        public LuaValue rawget( LuaValue key ) {
                if ( key.isinttype() ) {
                        int ikey = key.toint();
                        if ( ikey>0 && ikey<=array.length ) {
                                LuaValue v = m_metatable == null
                                                ? array[ikey-1] : m_metatable.arrayget(array, ikey-1);
                                return v != null ? v : Lua.namedNil(key);
                        }
                }
                return hashget( key );
        }
    
        protected LuaValue hashget(LuaValue key) {
                if ( hashEntries > 0 ) {
                        for ( Slot slot = hash[ hashSlot(key) ]; slot != null; slot = slot.rest() ) {
                                StrongSlot foundSlot;
                                if ( ( foundSlot = slot.find(key) ) != null ) {
                                        return foundSlot.value();
                                }
                        }
                }
                return Lua.namedNil(key);
        }
    

    Change LuaValue.checkmetatag:

        protected LuaValue checkmetatag(LuaValue tag, String reason) {
                LuaValue h = this.metatag(tag);
                if ( h.isnil() ) {
                        String errorText = reason + typename();
                        if (this instanceof NamedNil)
                                errorText += " (" + ((NamedNil) this).name.tojstring() + ")";
                        throw new LuaError(errorText);
                }
                return h;
        }
    

    And, voila, when running scripts with undefined functions (let's say
    loadURL is undefined):

    _, _, url = snippetText:find("(http://.*)")
    create {type='nt', text=loadURL(url), title='Contents of '..url..' for '..snippetID}
    

    ...you get very nice error messages like this:

    org.luaj.vm2.LuaError: #546:2 attempt to call nil (loadURL)
    

    Performance hit should be small when turned on - and zero when turned
    off and HotSpot-optimized.

    Cheers,
    Stefan

     

    Last edit: Stefan Reich 2015-03-22
    • gmeqiminfo

      gmeqiminfo - 2016-02-29

      Thank you for this help.

      But in our environnement we needed to modify LuaScriptEngine BindingsMetatable class and put this ack to show which function is not defined :

      this.rawset(LuaValue.INDEX, new TwoArgFunction() {
          public LuaValue call(LuaValue table, LuaValue key) {
      
              if (key.isstring()) {
                  Object o = bindings.get(key.tojstring());
                  if(o == null){
                      return Lua.namedNil( key );
                  } else {
                      return toLua(o);
                  }
              }
              else
                  return this.rawget(key);
          }
      });
      
       

Log in to post a comment.