lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


As an experiment, I'd like to patch Lua with what I'd call "lexical
metamethods," where if a lexical function named after a metamethod is
defined, then all corresponding operations in the lexical scope go
through that function.  For example,

  $ cat test.lua
  local function __index(...)
    print("debug:",...)
    return 2
  end

  print(_G.y.z)
  -- expected output:
  -- debug: table: _G y
  -- debug: 2 z
  -- 2

Here's an initial patch for the __index metamethod.  It doesn't quite
work in general.  Ideas solicited.  (BTW, dearth of comments in the
source leads to needing to infer a lot of stuff from usage patterns.)

diff -ur ../o/lua-5.1.4//src/lparser.c ./src/lparser.c
--- ../o/lua-5.1.4//src/lparser.c       2007-12-28 10:32:23.000000000 -0500
+++ ./src/lparser.c     2010-06-26 17:29:16.710882800 -0400
@@ -408,9 +408,30 @@
   /* field -> ['.' | ':'] NAME */
   FuncState *fs = ls->fs;
   expdesc key;
+
+  TString * indexname = G(ls->L)->tmname[TM_INDEX];
+  expdesc func;
+  if (singlevaraux(fs, indexname, &func, 1) != VGLOBAL) {
+    int base = fs->freereg;
+    luaK_exp2nextreg(fs, &func);
+    luaK_exp2nextreg(fs, v);
+
+    luaX_next(ls);  /* skip the dot or colon */
+    checkname(ls, &key);
+    luaK_exp2nextreg(fs, &key);
+
+    luaK_codeABC(fs, OP_CALL, base, 1+2, 1+1);
+    init_exp(v, VNONRELOC, base);
+    fs->freereg = base+1;
+
+    return;
+  }
+
   luaK_exp2anyreg(fs, v);
   luaX_next(ls);  /* skip the dot or colon */
   checkname(ls, &key);
+
+
   luaK_indexed(fs, v, &key);
 }


================



$ ./src/lua test.lua
debug:  table: 0x690728 y
./src/lua: test.lua:6: attempt to call a number value
stack traceback:
        test.lua:6: in main chunk
        [C]: ?



$ ./src/luac -p -l  test.lua

main <test.lua:0,0> (12 instructions, 48 bytes at 0x6b90f0)
0+ params, 5 slots, 0 upvalues, 1 local, 4 constants, 1 function
        1       [4]     CLOSURE         0 0     ; 0x6b9260
        2       [6]     GETGLOBAL       1 -1    ; print
        3       [6]     MOVE            2 0
        4       [6]     GETGLOBAL       3 -2    ; _G
        5       [6]     LOADK           4 -3    ; "y"
        6       [6]     CALL            2 3 2
        7       [6]     MOVE            3 0  <------------ problem
        8       [6]     MOVE            3 2  <------------
        9       [6]     LOADK           4 -4    ; "z"
        10      [6]     CALL            3 3 2
        11      [6]     CALL            1 3 1
        12      [6]     RETURN          0 1

function <test.lua:1,4> (7 instructions, 28 bytes at 0x6b9260)
0+ params, 4 slots, 0 upvalues, 1 local, 3 constants, 0 functions
        1       [2]     GETGLOBAL       1 -1    ; print
        2       [2]     LOADK           2 -2    ; "debug:"
        3       [2]     VARARG          3 0
        4       [2]     CALL            1 0 1
        5       [3]     LOADK           1 -3    ; 2
        6       [3]     RETURN          1 2
        7       [4]     RETURN          0 1