
Value Matcher
loop.debug.Matcher
Class of objects used to compare pairs of values according to some criteria of similarity. By default, it matches pairs of same values or structurally isomorphic tables (including their meta-tables). Functions with same bytecodes, upvalue contents and isomorphic environments also match. However, such matching criteria may be redefined. This class is useful for implementing automated test mechanisms for Lua applications.
Each object provides a set of methods for comparison of values passed as parameters. The function must return true
if the values match or false
otherwise. When a pair of distinct values are matched their correspondence is stored in the object instance. Therefore, such correspondence is maintained in all further comparisons made by the same instance.
Behavior
Fields
boolean
- Field that defines the method implementation used to compare two different boolean values passed as parameters. The function must return
true
if the values match orfalse
otherwise. If this field evaluates tofalse
then boolean values are compared for equality only. The default value for this field isnil
. envkey
- Special value used to identify a function environment retrieval. See method
error
for further information. environment
- Field that defines the function used to retrieve the environment of a function. If this field evaluates to
false
then function environments are ignored during matching. The default value for this field is functiongetfenv
of the Lua library. isomorphic
- If this field evaluates to
true
then table matching should be isomorphic, i.e. there is a one to one relation of each field of the first table to the second. However, if its value evaluates tofalse
then table matching just guarantee that all fields of the first table have a matching field in the second. The default value for this field istrue
. metakey
- Special value used to identify a meta-table retrieval. See method
error
for further information. metatable
- Field that defines the method implementation used to compare meta-tables of matching values passed as parameters. The function must return
true
if the values match orfalse
otherwise. If this field evaluates tofalse
then meta-tables are ignored during matching. The default value for this field is methodmatch
provided by the class. function
- Field that defines the method implementation used to compare two different function values passed as parameters. The function must return
true
if the values match orfalse
otherwise. If this field evaluates tofalse
then function values are compared for equality only. The default value for this field is methodmatchfunction
provided by the class. number
- Field that defines the method implementation used to compare two different number values passed as parameters. The function must return
true
if the values match orfalse
otherwise. If this field evaluates tofalse
then number values are compared for equality only. The default value for this field isnil
. string
- Field that defines the method implementation used to compare two different string values passed as parameters. The function must return
true
if the values match orfalse
otherwise. If this field evaluates tofalse
then string values are compared for equality only. The default value for this field isnil
. table
- Field that defines the method implementation used to compare two different table values passed as parameters. The function must return
true
if the values match orfalse
otherwise. If this field evaluates tofalse
then table values are compared for equality only. The default value for this field is methodmatchtable
provided by the class. thread
- Field that defines the method implementation used to compare two different thread values passed as parameters. The function must return
true
if the values match orfalse
otherwise. If this field evaluates tofalse
then thread values are compared for equality only. The default value for this field isnil
. upvalue
- Field that defines the function used to retrieve the contents of function upvalues. If this field evaluates to
false
then upvalues contents are ignored during matching. The default value for this field is functiondebug.getupvalue
of the Lua debug library if it is loaded at the moment this class is required. userdata
- Field that defines the method implementation used to compare two different userdata values passed as parameters. The function must return
true
if the values match orfalse
otherwise. If this field evaluates tofalse
then userdata values are compared for equality only. The default value for this field isnil
.
Methods
error(reason)
- Method that creates a matching error message. The parameter
reason
is a string with a message describing the error reason. Whenever this method is called, the object instance stores as an array (i.e. using integer keys) the sequence of values that identifies the path to the mismatched field. However, indexes 0 and 1 are used to store the values being compared, that are respectively the values of parametersother
andvalue
that are passed to methodmatch
. Fieldsmetakey
andenvkey
hold special values that are used to identify a meta-table or function environment retrival, respectively. match(value, other)
- Method that tries to match values
value
andother
. If they match then it returnstrue
. Otherwise, it returnfalse
and an error message. The error message format is created by methoderror
. The default format is "<path>: <reason>", where <path> is a string identifying which part doesn't match. Upvalues are represented as table fields, for example ifvalue
is a table which fieldfunc
is a function which upvalueup
differ then the path informed will bevalue.func.up
. The <reason> is one of the following messages:"no match found"
no similar field key found "missing"
missing field found in other
table"bytecodes not matched"
bytecodes of two different function differ "wrong match"
other value (e.g. previously bound) was expected "not matched"
different objects found matchfunction(value, other)
- Method that compares two different functions informed as parameters
value
andother
according to their bytecodes and the criteria defined by fieldsenvironment
,upvalue
andmetatable
. If the two values matches, then it returnstrue
, otherwise it returnsfalse
and an error message. matchtable(value, other)
- Method that compares two different tables informed as parameters
value
andother
according to their contents and the criteria defined by fieldmetatable
. If the two values matches, then it returnstrue
, otherwise it returnsfalse
and an error message.
Meta-Fields
__mode = "k"
- Defines that matched values are weak references thus if other references to those values are lost then they becomes garbage.
Remarks
- Each object instance keeps a mapping of the matched objects, therefore to restart comparisons without previous mapping you should create another object instance.
- Since it is only possible to check upvalue contents, matched functions are not guaranteed to produce the same effects since the upvalue variables may be actually different even though they store the same value.
- Since
string.dump
produces an error instead of returning an error message silently, values with unmatched C functions raises the error produced bystring.dump
. To handle such situation, you should use apcall
. But be warned that this function is somewhat restricted since it can't be used with yielding co-routines. - Methods used to compare two different values (i.e. fields
boolean
,number
,string
,function
,thread
anduserdata
) may store in the object instance a mapping of each machted pairs so thatself[value] == other and self[other] == value
in order to avoid further evaluation of the same pair and that they are matched to other values. However, for positive integer numbers this should be avoided because these values are used to store the sequence of values that identifies the current path of the values being compared. - Non-isomorphic comparisions of tables that have other tables as key values does not work well due to ambiguities when trying to find the corresponding match for each key-value pair.
Examples
Feedback-loop test suite for pull-parsers.
local Viewer = require "loop.debug.Viewer" local Matcher = require "loop.debug.Matcher" local message = "Testcase %d failed: %s\n" function compare(file, cases) local previous = io.open(file) if previous then previous:close() previous = dofile(file) else previous = {} end local results = {} for index, source in ipairs(cases) do local expected = previous[index] local actual = parser:evaluate(source) if expected then local matcher = Matcher{ metatable = false } local success, errmsg = matcher:match(expected, actual) if not success then io.stderr:write(message:format(index, errmsg)) end else expected = actual end results[index] = expected end local serializer = Viewer{ output = assert(io.open(file, "w")), maxdepth = -1, } serializer.output:write("return ") serializer:write(results) end local oo = require "loop.base" local Expression = require "loop.compiler.Expression" List = oo.class() Label = oo.class() Lambda = oo.class() Apply = oo.class() parser = Expression{ values = { number = "(%-?%d+)", variable = "([%a_][%w_]*)", }, operators = { list = " , ", label = "' = ", lambda = "\ . ", apply = " ", }, precedence = { {"list"},{"label"},{"lambda"},{"apply"} }, } function parser:number(value) return tonumber(value) end function parser:variable(value) return value end function parser:label(name, def) return Label{ name = name, def = def } end function parser:lambda(args, body) return Lambda{ args = args, body = body } end function parser:apply(func, args) return Apply{ func = func, args = args } end function parser:list(a, d) if oo.classof(a) == List then a[#a+1] = d return a else return List{ a, d } end end compare("results.lua", { "'fat=\x.if(eq(x,0),1,mul(x,fat(sub(x,-1))))", "'addto=\(x,y).cons(sum(car x,y),addto(cdr x,y))", -- TODO: add more testcases here })
Copyright (C) 2004-2008 Tecgraf, PUC-RioThis project is currently being maintained by Tecgraf at PUC-Rio.