lua-users home
lua-l archive

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


  I will try a quick explanation. I hope that will be enough for a start.


  + new, general syntax for constructors {[exp] = exp, ... }
      *** Self-explanatory (or are there implications?).

No implications. Just now you can write constructors like:

 a = {f(x), g(y); [h(z)] = u(w)-9, [0] = "hello", ["a b"] = 89}

with the obvious(?) semantics. The old case a = {k = x} is handled as
a syntatic sugar for a = {["k"] = x}, as it was already in normal use
(a.k for a["k"]).


  + userdata can now handle arbitrary binary data
      *** Not of immediate interest to me, but maybe others...

This is still under some internal discussion, but the idea is that you
can store any data (with any size) in a userdata. The operations for that
are:

void           lua_pushbindata          (void *buff, int size, int tag);

-- Gives to Lua a userdata (Lua makes a copy of it, like it does with
strings).

void          *lua_getbindata           (lua_Object object);
int            lua_getbindatasize       (lua_Object object);

-- Get contents and size of a userdata. Again like strings, Lua gives
a pointer to its internal copy, so the program *cannot* change this
data. Notice that userdatas are values, not memory. You cannot use
them like arrays, for instance (i.e. they are immutable). But they
can store any binary information you want.


  + support for conditional compilation ($if ... $else ... $end)
      *** Self-explanatory.

Some details: in "$if x", x can be "1", "nil" or the name of a global
variable. $ifs can be nested. You also have "$ifnot". There is an
extra pragma, $endinput, with the obvious(?) meaning.


  + NEW CONCEPT: internal methods based on tags replace fallbacks
    (but fully compatible with 2.5)
      *** I've tested the backwards compatibility (no problem) but I'd
      *** be interested to try out the new concept, given a few hints...

This is the hardest part. The general idea: internal methods (or tag
methods, or just fallbacks :-) is mainly the old concept of fallbacks,
with one big, and some small differences:

+ instead of being globally defined, each tag can have its own set of methods. 
- like userdata, tables can have different tags.
- to use tag methods, tags must be explicitly created with "newtag".
- tables now also have tag methods for gettable and settable.

  Well, see example below :-)

tt = newtag()
t1 = {5,6,"noite"}
settag(t1, tt)    -- table t1 now has tag tt

function f(t, i)
   return rawgettable(t, i)+3   -- rawgettable is a way to index a table
                                -- without calling tag methods.
end

settagmethod(tt, 'gettable', f)   -- change the method associated with
                                  -- tag 'tt'

assert(t1[1] == 8)  -- since t1 has tag tt, t1[1] will call the
-- internal method for the event 'gettable' associated with 'tt',
-- like an old fallback. Other tables (with other tags) work without changes.


Other details:

- fallback 'arith' has been splited in many tag methods: 'add', 'sub',
'mul', etc. The same for 'order'.

- since userdata are immutable, you cannot use "settag" for them. Instead,
they must be created with their final tag.

- old tags (user defined, without using newtag) can still be used, but
you cannot associate a tag method to them.

- the old function "setfallback" uses the new tag methods in some
complex ways to fully simullate its old behavior.

- the tag methods for getglobal and setglobal (new) are more powerful.
"a = b" calls the tag method of event "setglobal" of "a", it its has one.
An access to a global variable 'b' calls the tag method of event
"getglobal" of "b", it its has one. Notice that setglobal gets its
tag from the original value of the variable, not the new one. This may
sounds strange, but it is very powerful. After you set a proper value
in a global variable, you can have complete control over all accesses
and assignments to it (see example(?) below).

  For more information, look at the file below. It is a test file for
this mechanism. It is far from self-explanatory, but it is not completely
criptographic. But please notice that some things may still change till
final version 3.0.

-- Roberto


$debug
print('testando tags e internal methods')

assert(tag(2) == tag(0) and tag{} == tag{})

tt = newtag()
tt2 = newtag()

t1 = {5,6,"noite"}
settag(t1, tt)
assert(type(t1) == 'table' and tag(t1) == tt)

t2 = {1,2,"alo"}
settag(t2, tt2)

t3 = {10,2,3}

function f(t, i) return rawgettable(t, i)+3 end
assert(gettagmethod(tt, 'gettable') == nil)
assert(settagmethod(tt, 'gettable', f) == nil)
assert(gettagmethod(tt, 'gettable') == f)
assert(settagmethod(tt, 'gettable', f) == f)

function f(t, i, v) rawsettable(t, i, v-3) end
settagmethod(tt, 'settable', f)


assert(t1[1] == 8)
assert(rawgettable(t1, 1) == 5)
assert(t2[3] == 'alo')
assert(rawgettable(t1, 3) == "noite")
assert(rawgettable(t2, 1) == 1)

t1.x = 10
assert(rawgettable(t1, 'x') == 7)
assert(t1.x == 10)
settagmethod(tt, 'gettable', nil)
assert(t1.x == 7)

t2.x = 10
assert(rawgettable(t2, 'x') == t3[1])
assert(t2.x == 10)
print('+')

function f(t, p1) return rawgettable(t, p1) end
settagmethod(tt, 'function', f)

assert(t1(3) == 'noite')

t2.x = 'alo'
function f (s1, s2)
  if type(s1) == 'table' then s1 = s1.x end
  if type(s2) == 'table' then s2 = s2.x end
  return s1..s2
end
settagmethod(tt2, 'concat', f)
assert(t2..'x' == 'alox')
assert('a'..t2 == 'aalo')

tt = newtag()
x = {realvalue = 0}
settag(x, tt)
assert(tag(x) == tt)

function fs (name, oldvalue, newvalue)
  oldvalue.realvalue = newvalue   -- modifica o realvalue
  y = newvalue
end
settagmethod(tt, 'setglobal', fs)

function fg (name, value)
  return value.realvalue   -- retorna valor 'real' de x
end
settagmethod(tt, 'getglobal', fg)

x = 10
assert(x == 10 and y == 10 and getglobal('x') == 10 and
       type(rawgetglobal('x')) == 'table')

setglobal('x', print)
assert(x == print and y == print and getglobal('x') == print and
       type(rawgetglobal('x')) == 'table')

rawsetglobal('x', 4)
x = 12
assert(x == 12 and y == print)

print('+')

tt = newtag()
x = userdata({0, 1, 2}, tt)
assert(type(x) == 'userdata' and tag(x) == tt and
getbyte(x) == 3 and getbyte(x, 3) == 2)

function fs (name, oldvalue, newvalue)
  local u = userdata({newvalue}, tag(oldvalue))
  rawsetglobal(name, u)
end
settagmethod(tt, 'setglobal', fs)

function fg (name, value)
  return getbyte(value, 1)
end
settagmethod(tt, 'getglobal', fg)

x = 10
assert(x == 10 and getglobal('x') == 10)
assert(type(rawgetglobal('x')) == 'userdata' and
       tag(rawgetglobal('x')) == tt)

x = 13
assert(x == 13 and getglobal('x') == 13)
assert(type(rawgetglobal('x')) == 'userdata' and
       tag(rawgetglobal('x')) == tt)

rawsetglobal('x', nil); fs = nil; fg = nil;
assert(x == nil)

print('OK')

return 12