(Part 1)
-------------------
4.6 visibility and upvalue
-------------------
A function body can reference its own local variables (including its parameters) and global variables, as long as they are not hidden by local variables with the same name in the function (shadowed ). A local variable that cannot contain the function, because such a variable may no longer exist when the function is called. However, a function can use the local variables in its functions through upvalue. Upvalue Syntax:
Upvalue: = '%' name
A upvalue is somewhat like a variable expression, but its value is frozen (frozen) when its function is instantiated. The name used in upvalue can be the name of any variable, as long as the variable is visible when the function is defined, that is, the global variables and local variables in its function are directly included. Note that when upvalue is a table, only the reference of the table (that is, the value of upvalue) is frozen. The table content can be modified at will. Using the table value as upvalue allows the function to be writable but private.
The following are some examples:
a,b,c = 1,2,3 -- global variables local d function f (x) local b = {} -- x and b are local to f; b shadows the global b local g = function (a) local y -- a and y are local to g p = a -- OK, access local `a‘ p = c -- OK, access global `c‘ p = b -- ERROR: cannot access a variable in outer scope p = %b -- OK, access frozen value of `b‘ (local to `f‘) %b = 3 -- ERROR: cannot change an upvalue %b.x = 3 -- OK, change the table contents p = %c -- OK, access frozen value of global `c‘ p = %y -- ERROR: `y‘ is not visible where `g‘ is defined p = %d -- ERROR: `d‘ is not visible where `g‘ is defined end -- g end -- f
-------------------
4.7 handle errors
-------------------
Because Lua is an extension language, all Lua Actions start from the C code in the Host Program Calling a function in the Lua library. Every time an error occurs during Lua compilation or execution, function _ errormessage will be called (if it is not nil), and then functions in the corresponding Library (lua_dofile, lua_dostring, lua_dobuffer and lua_call) terminated and an error is returned.
Memory Allocation Error is an exception of the above rule. When memory allocation fails, Lua may not be able to execute the _ errormessage function. Therefore, for this error, Lua does not call the _ errormessage function. Instead, the corresponding function in the library immediately returns a special error code (errmem. This and other error codes are defined in Lua. H. See section 5.8.
The unique parameter _ errormessage is a string with an incorrect description. The default definition of this function is _ alert, which prints information to stderr (see section 6.1 ). The standard I/O Library redefined _ errormessage and used the debugging mechanism (see section 7) to print some additional information, such as calling stack backtracking.
The Lua code may generate an error by explicitly calling the function error (see section 6.1. The Lua code can capture an error using the function call (see section 6.1.
-------------------
4.8 Tag Method
-------------------
Lua provides a powerful mechanism to expand its semantics, called Tag Method ). A tag method is a function defined by a programmer to call at a specific key point in Lua program execution. It allows the programmer to change the standard Lua behavior at these key points. Every such point is called an event.
The Tag Method of a specific event is called Based on the tag of the value involved in the event (see section 3 ). The settagmethod function changes the TAG method associated with a given pair (TAG, event. Its first parameter is the tag, the second parameter is the event name (a string, see below), and the third parameter is the new method (a function ), or nil is used to restore the default behavior of a pair (TAG event pair. The settagmethod function returns the previous Tag Method for the tag event. The corresponding function gettagmethod receives a tag and an event name and returns the associated current method.
The label method is called in the following events, which are differentiated by the given name. The semantics of the label method can be better interpreted by the Lua function to describe the interpreter's behavior in each event. This function not only shows when the label method will be called, but also shows its parameters, return values, and default behavior. The code shown here is only used to illustrate the purpose; the real behavior in the interpreter is hard-coded, and it is more efficient than this simulation. All the functions used in these interpretations (rawget, tonumber, call, etc.) are described in section 6.1.
''Add '':
It is called when the + operation is applied to non-numeric operands.
The following function getbinmethod defines how Lua selects a label method for a binary operation. First, Lua tries the first operand. If its label does not define the label method for the operation, Lua tries the second operand. If it still fails, then a TAG method is obtained from tag 0.
function getbinmethod (op1, op2, event) return gettagmethod(tag(op1), event) or gettagmethod(tag(op2), event) or gettagmethod(0, event) end
Using this function, the TAG method of the ''add'' event is:
function add_event (op1, op2) local o1, o2 = tonumber(op1), tonumber(op2) if o1 and o2 then -- both operands are numeric return o1+o2 -- ‘+‘ here is the primitive ‘add‘ else -- at least one of the operands is not numeric local tm = getbinmethod(op1, op2, "add") if tm then -- call the method with both operands and an extra -- argument with the event name return tm(op1, op2, "add") else -- no tag method available: default behavior error("unexpected type at arithmetic operation") end end end
''Sub '':
This operation is called when it is applied to non-numeric operands. Its behavior is similar to the ''add'' event.
''Mul '':
This operation is called when * is applied to non-numeric operands. Its behavior is similar to the ''add'' event.
''Div '':
It is called when the/operation is applied to non-numeric operands. Its behavior is similar to the ''add'' event.
''Pow '':
When a ^ (Power) operation is called, even for numeric operands.
function pow_event (op1, op2) local tm = getbinmethod(op1, op2, "pow") if tm then -- call the method with both operands and an extra -- argument with the event name return tm(op1, op2, "pow") else -- no tag method available: default behavior error("unexpected type at arithmetic operation") end end
''Unm '':
It is called when the unary operation is applied to non-numeric operands.
function unm_event (op) local o = tonumber(op) if o then -- operand is numeric return -o -- ‘-‘ here is the primitive ‘unm‘ else -- the operand is not numeric. -- Try to get a tag method from the operand; -- if it does not have one, try a "global" one (tag 0) local tm = gettagmethod(tag(op), "unm") or gettagmethod(0, "unm") if tm then -- call the method with the operand, nil, and an extra -- argument with the event name return tm(op, nil, "unm") else -- no tag method available: default behavior error("unexpected type at arithmetic operation") end end end
''Lt '':
When a comparison operation is applied to non-numeric or non-string-type operands, it is called. It is equivalent to the <operator.
function lt_event (op1, op2) if type(op1) == "number" and type(op2) == "number" then return op1 < op2 -- numeric comparison elseif type(op1) == "string" and type(op2) == "string" then return op1 < op2 -- lexicographic comparison else local tm = getbinmethod(op1, op2, "lt") if tm then return tm(op1, op2, "lt") else error("unexpected type at comparison"); end end end
Other comparison operators use this label method based on common adequacy:
A> B <=> B <
A <= B <=> not (B <)
A> = B <=> not (a <B)
''Concat '':
It is called when the join operation is applied to non-string-type operands.
function concat_event (op1, op2) if (type(op1) == "string" or type(op1) == "number") and (type(op2) == "string" or type(op2) == "number") then return op1..op2 -- primitive string concatenation else local tm = getbinmethod(op1, op2, "concat") if tm then return tm(op1, op2, "concat") else error("unexpected type for concatenation") end end end
''Index '':
When Lua tries to return an index that is not in the table, it is called. For the semantics, see the ''gettable'' event.
''Getglobal '':
When Lua needs a value of a global variable, it is called. This method can be set only for nil, and only for the tag created by newtag. Note that the label is the current value of the global variable.
function getglobal (varname) -- access the table of globals local value = rawget(globals(), varname) local tm = gettagmethod(tag(value), "getglobal") if not tm then return value else return tm(varname, value) end end
The getglobal function is defined in the basic library (see section 6.1 ).
''Setglobal '':
When Lua assigns a value to a global variable, it is called. This method cannot be set for values, strings, tables, and userdata with default tags.
function setglobal (varname, newvalue) local oldvalue = rawget(globals(), varname) local tm = gettagmethod(tag(oldvalue), "setglobal") if not tm then rawset(globals(), varname, newvalue) else tm(varname, oldvalue, newvalue) end end
The setglobal function is defined in the basic library (see section 6.1 ).
''Gettable '':
When Lua calls an index variable, it is called. This method cannot be set for tables with default labels.
function gettable_event (table, index) local tm = gettagmethod(tag(table), "gettable") if tm then return tm(table, index) elseif type(table) ~= "table" then error("indexed expression not a table"); else local v = rawget(table, index) tm = gettagmethod(tag(table), "index") if v == nil and tm then return tm(table, index) else return v end end end
''Settable '':
It is called when Lua sets an index variable. This method cannot be set for tables with default labels.
function settable_event (table, index, value) local tm = gettagmethod(tag(table), "settable") if tm then tm(table, index, value) elseif type(table) ~= "table" then error("indexed expression not a table") else rawset(table, index, value) end end
''Function '':
When Lua tries to call a value that is not a function, it is called.
function function_event (func, ...) if type(func) == "function" then return call(func, arg) else local tm = gettagmethod(tag(func), "function") if tm then for i=arg.n,1,-1 do arg[i+1] = arg[i] end arg.n = arg.n+1 arg[1] = func return call(tm, arg) else error("call expression not a function") end end end
''Gc '':
When Lua recycles a userdata, it is called. This label method can only be set in C and cannot be set to userdata with default labels. For each userdata recycled by garbage collection, Lua is equivalent to the following function:
function gc_event (obj) local tm = gettagmethod(tag(obj), "gc") if tm then tm(obj) end end
In a garbage collection cycle, the TAG method of userdata is called in the reverse order of tag creation. That is to say, the first Tag Method to be called is associated with the last tag created in the program. In addition, at the end of the cycle, Lua is equivalent to a gc_event (NiL) Call.
(To be continued)
Lua4.0 Reference Manual (iv) 4.6-4.8