[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: Lua 5.1 Token Filters
- From: Andreas Stenius <kaos@...>
- Date: Wed, 06 Sep 2006 17:32:55 +0200
I'm feeling evil too.. so here goes a type check implementation with
token filters ;o)
Attached is type_check.lua which does the work -- needs the
dsilver-token-filter-patch -- and a type_test.lua to demonstrate it's
use.. sample output follows:
./lua -ltype_check -ltype_test
Test... true
I now know this is a number: 123
OK
Test... false
OK ./type_test.lua:3: bad argument #1 to 'basic_number' (number
expected, got string)
Test... true
Oh, it's not nil anyway: 45.6
OK
Test... true
Oh, it's not nil anyway: not a number either
OK
Test... false
OK ./type_test.lua:7: bad argument #1 to 'num_or_string' (number or
string expected, got table)
Test... true
Alot of options here, in order: still a string nil
function: 0x52aec0 nil
OK
Test... true
Alot of options here, in order: table: 0x52b0a0 333
function: 0x52a0e0 nil
OK
Test... false
OK ./type_test.lua:11: bad argument #4 to 'a_bit_more_complex'
(userdata or nil expected, got function)
Test... true
I now have exactly two args passed.. oh well, the third could be an
attempted arg as well, but it was nil any way
OK
Test... false
OK ./type_test.lua:15: bad argument #3 to 'enforce_num_args' (nil
expected, got string)
Test... false
OK ./type_test.lua:15: bad argument #2 to 'enforce_num_args'
(string expected, got nil)
I'm not feeling guilty enough yet to be sorry..
enjoy!
//Andreas
Ps.
And thanks to the Organizers and all other Oh-Six participants for a
great workshop! (no names, or I'd feel I left ppl out)
askok@dnainternet.net skrev:
Me, too :) Not as productive as Daniel, but I did finish this late
last night, so here goes...
Ref: checking Lua function usage, and return values.
-asko
On Tue, 05 Sep 2006 22:38:39 +0200
Daniel Silverstone <dsilvers@digital-scurf.org> wrote:
As per my agreement with lhf and various others at the Lua workshop this
year, I hereby confess my sins:
http://blog.digital-scurf.org/tech/lua-with-macros.html
I'm sorry.
D.
--[[
Syntax:
function [name]( [type [:type]*] argName [, ...] )
end
Valid type's are:
number
string
table
userdata
function
nil
Written under heavy inspiration by Andreas Stenius
Parts copied from pump.lua that came with Daniel Silverstone's
token filter patch.
--]]
local function debug_put(put)
return function( l, t, v )
print("< ", l, t, v)
put(l, t, v)
end
end
local function debug_get(get)
return function()
local l, t, v = get()
print(" >", l, t, v)
return l, t, v
end
end
local function consume_func_args(get,put)
local types = {}
local curr_type
local function add_type(line, v)
if not curr_type then
curr_type = {
line = line,
type = { v }
}
else
table.insert( curr_type.type, v )
end
end
while true do
local line, tok, val = get()
if tok == ")" then
if curr_type then
table.insert( types, curr_type )
end
put( line, tok, val )
return types
end
if tok == "<name>" then
if val == "number" or
val == "string" or
val == "table" or
val == "userdata"
then
add_type( line, val )
else
if curr_type then
curr_type.name = val
end
put( line, tok, val )
end
elseif
tok == "function" or
tok == "nil"
then
add_type( line, tok )
elseif tok ~= ":" then
if curr_type and tok == "," then
table.insert( types, curr_type )
curr_type = nil
end
put( line, tok, val )
end
end
end
local function intercept_function_def(get,put)
local func_name = ""
while true do
local line, tok, val = get()
put( line, tok, val )
if tok == "(" then
local type_asserts = consume_func_args(get,put)
for argn, argv in ipairs(type_asserts) do
local type_string = ""
local multiple_types = false
put( argv.line, "<name>", "assert" )
put( argv.line, "(" )
for idx_t, t in ipairs(argv.type) do
if multiple_types then
put( argv.line, "or" )
type_string = type_string .. " or "
end
type_string = type_string .. t
put( argv.line, "<name>", "type" )
put( argv.line, "(" )
put( argv.line, "<name>", argv.name )
put( argv.line, ")" )
put( argv.line, "==" )
put( argv.line, "<string>", t )
multiple_types = true
end
put( argv.line, ",")
put( argv.line, "<string>", string.format(
"bad argument #%d to '%s' (%s expected, got ",
argn, #func_name > 0 and func_name or "(anonymous)",
type_string )
)
put( argv.line, ".." )
put( argv.line, "<name>", "type" )
put( argv.line, "(" )
put( argv.line, "<name>", argv.name )
put( argv.line, ")" )
put( argv.line, ".." )
put( argv.line, "<string>", ")" )
put( argv.line, ")" )
end
break
else
func_name = func_name .. (tok ~= "<name>" and tok or val)
end
end
end
local function type_check(get,put)
put("type_check init") -- Eaten during the pipe setup
while true do
local line, tok, val = get()
put( line, tok, val )
if tok == "function" then
intercept_function_def(get,put)
end
end
end
local function pipe(f,get,put)
put = put or coroutine.yield
local F=coroutine.wrap(f)
--F(debug_get(get),debug_put(put))
F(get,put)
return F
end
local pipeline
local getter
function _TOKEN_PUMP(_getter, source)
if _getter then
getter = _getter
pipeline = pipe(type_check, getter)
else
return pipeline()
end
end
-- this file requires that type_check.lua has already been loaded
function basic_number( number i )
print( "I now know this is a number: ", i )
end
function num_or_string( number:string val )
print( "Oh, it's not nil anyway: ", val )
end
function a_bit_more_complex( table:string opt, number:nil foo, function func, userdata:nil ud )
print( "Alot of options here, in order: ", opt, foo, func, ud )
end
function enforce_num_args( number a, string b, nil _ )
print( "I now have exactly two args passed.. oh well, the third could be an attempted arg as well, but it was nil any way" )
end
function test_call( expected, f, ...)
print( "Test...", expected )
local ok, msg = pcall( f, ... )
if ok == expected then
print( "OK ", msg or "")
else
print( "FAILED ", msg )
end
end
test_call( true, basic_number, 123 )
test_call( false, basic_number, "not a number" )
test_call( true, num_or_string, 45.6 )
test_call( true, num_or_string, "not a number either" )
test_call( false, num_or_string, { "bogus" } )
test_call( true, a_bit_more_complex, "still a string", nil, print )
test_call( true, a_bit_more_complex, table, 333, pairs, nil )
test_call( false, a_bit_more_complex, "another string", 222, io.open, io.close )
test_call( true, enforce_num_args, 456, "qwerty" )
test_call( false, enforce_num_args, 456, "qwerty", "aha!" )
test_call( false, enforce_num_args, 456 )