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 or false otherwise. If this field evaluates to false then boolean values are compared for equality only. The default value for this field is nil.
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 function getfenv 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 to false 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 is true.
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 or false otherwise. If this field evaluates to false then meta-tables are ignored during matching. The default value for this field is method match 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 or false otherwise. If this field evaluates to false then function values are compared for equality only. The default value for this field is method matchfunction 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 or false otherwise. If this field evaluates to false then number values are compared for equality only. The default value for this field is nil.
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 or false otherwise. If this field evaluates to false then string values are compared for equality only. The default value for this field is nil.
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 or false otherwise. If this field evaluates to false then table values are compared for equality only. The default value for this field is method matchtable 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 or false otherwise. If this field evaluates to false then thread values are compared for equality only. The default value for this field is nil.
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 function debug.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 or false otherwise. If this field evaluates to false then userdata values are compared for equality only. The default value for this field is nil.

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 parameters other and value that are passed to method match. Fields metakey and envkey 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 and other. If they match then it returns true. Otherwise, it return false and an error message. The error message format is created by method error. 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 if value is a table which field func is a function which upvalue up differ then the path informed will be value.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 and other according to their bytecodes and the criteria defined by fields environment, upvalue and metatable. If the two values matches, then it returns true, otherwise it returns false and an error message.
matchtable(value, other)
Method that compares two different tables informed as parameters value and other according to their contents and the criteria defined by field metatable. If the two values matches, then it returns true, otherwise it returns false 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

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.