diff options
Diffstat (limited to 'src/lanes.lua')
-rw-r--r-- | src/lanes.lua | 187 |
1 files changed, 104 insertions, 83 deletions
diff --git a/src/lanes.lua b/src/lanes.lua index 5dfe41d..57aa0fe 100644 --- a/src/lanes.lua +++ b/src/lanes.lua | |||
@@ -56,8 +56,9 @@ lanes.configure = function( settings_) | |||
56 | -- | 56 | -- |
57 | -- Cache globals for code that might run under sandboxing | 57 | -- Cache globals for code that might run under sandboxing |
58 | -- | 58 | -- |
59 | local assert = assert | 59 | local assert = assert( assert) |
60 | local string_gmatch = assert( string.gmatch) | 60 | local string_gmatch = assert( string.gmatch) |
61 | local string_format = assert( string.format) | ||
61 | local select = assert( select) | 62 | local select = assert( select) |
62 | local type = assert( type) | 63 | local type = assert( type) |
63 | local pairs = assert( pairs) | 64 | local pairs = assert( pairs) |
@@ -127,7 +128,7 @@ lanes.configure = function( settings_) | |||
127 | return settings | 128 | return settings |
128 | end | 129 | end |
129 | local settings = core.configure and core.configure( params_checker( settings_)) or core.settings | 130 | local settings = core.configure and core.configure( params_checker( settings_)) or core.settings |
130 | local thread_new = assert( core.thread_new) | 131 | local core_lane_new = assert( core.lane_new) |
131 | local max_prio = assert( core.max_prio) | 132 | local max_prio = assert( core.max_prio) |
132 | 133 | ||
133 | lanes.ABOUT = | 134 | lanes.ABOUT = |
@@ -203,11 +204,9 @@ end | |||
203 | -- ... (more options may be introduced later) ... | 204 | -- ... (more options may be introduced later) ... |
204 | -- | 205 | -- |
205 | -- Calling with a function parameter ('lane_func') ends the string/table | 206 | -- Calling with a function parameter ('lane_func') ends the string/table |
206 | -- modifiers, and prepares a lane generator. One can either finish here, | 207 | -- modifiers, and prepares a lane generator. |
207 | -- and call the generator later (maybe multiple times, with different parameters) | ||
208 | -- or add on actual thread arguments to also ignite the thread on the same call. | ||
209 | 208 | ||
210 | local valid_libs= | 209 | local valid_libs = |
211 | { | 210 | { |
212 | ["package"] = true, | 211 | ["package"] = true, |
213 | ["table"] = true, | 212 | ["table"] = true, |
@@ -223,88 +222,110 @@ local valid_libs= | |||
223 | ["lanes.core"] = true | 222 | ["lanes.core"] = true |
224 | } | 223 | } |
225 | 224 | ||
225 | local raise_option_error = function( name_, tv_, v_) | ||
226 | error( "Bad '" .. name_ .. "' option: " .. tv_ .. " " .. string_format( "%q", tostring( v_)), 4) | ||
227 | end | ||
228 | |||
229 | local opt_validators = | ||
230 | { | ||
231 | priority = function( v_) | ||
232 | local tv = type( v_) | ||
233 | return (tv == "number") and v_ or raise_option_error( "priority", tv, v_) | ||
234 | end, | ||
235 | cancelstep = function( v_) | ||
236 | local tv = type( v_) | ||
237 | return (tv == "number") and v_ or (v_ == true) and 100 or (v_ == false) and 0 or raise_option_error( "cancelstep", tv, v_) | ||
238 | end, | ||
239 | globals = function( v_) | ||
240 | local tv = type( v_) | ||
241 | return (tv == "table") and v_ or raise_option_error( "globals", tv, v_) | ||
242 | end, | ||
243 | package = function( v_) | ||
244 | local tv = type( v_) | ||
245 | return (tv == "table") and v_ or raise_option_error( "package", tv, v_) | ||
246 | end, | ||
247 | required = function( v_) | ||
248 | local tv = type( v_) | ||
249 | return (tv == "table") and v_ or raise_option_error( "required", tv, v_) | ||
250 | end, | ||
251 | gc_cb = function( v_) | ||
252 | local tv = type( v_) | ||
253 | return (tv == "function") and v_ or raise_option_error( "gc_cb", tv, v_) | ||
254 | end | ||
255 | } | ||
256 | |||
226 | -- PUBLIC LANES API | 257 | -- PUBLIC LANES API |
227 | local function gen( ... ) | 258 | -- receives a sequence of strings and tables, plus a function |
228 | local opt= {} | 259 | local gen = function( ...) |
229 | local libs= nil | 260 | -- aggregrate all strings together, separated by "," as well as tables |
230 | local lev= 2 -- level for errors | 261 | -- the strings are a list of libraries to open |
231 | 262 | -- the tables contain the lane options | |
232 | local n= select('#',...) | 263 | local opt = {} |
233 | 264 | local libs = nil | |
234 | if n==0 then | 265 | |
235 | error( "No parameters!" ) | 266 | local n = select( '#', ...) |
236 | end | 267 | |
268 | -- we need at least a function | ||
269 | if n == 0 then | ||
270 | error( "No parameters!", 2) | ||
271 | end | ||
237 | 272 | ||
238 | for i=1,n-1 do | 273 | -- all arguments but the last must be nil, strings, or tables |
239 | local v= select(i,...) | 274 | for i = 1, n - 1 do |
240 | if type(v)=="string" then | 275 | local v = select( i, ...) |
241 | libs= libs and libs..","..v or v | 276 | local tv = type( v) |
242 | elseif type(v)=="table" then | 277 | if tv == "string" then |
243 | for k,vv in pairs(v) do | 278 | libs = libs and libs .. "," .. v or v |
244 | opt[k]= vv | 279 | elseif tv == "table" then |
245 | end | 280 | for k, vv in pairs( v) do |
246 | elseif v==nil then | 281 | opt[k]= vv |
247 | -- skip | 282 | end |
248 | else | 283 | elseif v == nil then |
249 | error( "Bad parameter: "..tostring(v) ) | 284 | -- skip |
250 | end | 285 | else |
251 | end | 286 | error( "Bad parameter " .. i .. ": " .. tv .. " " .. string_format( "%q", tostring( v)), 2) |
287 | end | ||
288 | end | ||
252 | 289 | ||
253 | local func= select(n,...) | 290 | -- the last argument should be a function or a string |
254 | local functype = type(func) | 291 | local func = select( n, ...) |
255 | if functype ~= "function" and functype ~= "string" then | 292 | local functype = type( func) |
256 | error( "Last parameter not function or string: "..tostring(func)) | 293 | if functype ~= "function" and functype ~= "string" then |
257 | end | 294 | error( "Last parameter not function or string: " .. functype .. " " .. string_format( "%q", tostring( func)), 2) |
295 | end | ||
258 | 296 | ||
259 | -- Check 'libs' already here, so the error goes in the right place | 297 | -- check that the caller only provides reserved library names, and those only once |
260 | -- (otherwise will be noticed only once the generator is called) | 298 | -- "*" is a special case that doesn't require individual checking |
261 | -- "*" is a special case that doesn't require individual checking | 299 | if libs and libs ~= "*" then |
262 | -- | 300 | local found = {} |
263 | if libs and libs ~= "*" then | 301 | for s in string_gmatch(libs, "[%a%d.]+") do |
264 | local found = {} | 302 | if not valid_libs[s] then |
265 | -- check that the caller only provides reserved library names | 303 | error( "Bad library name: " .. s, 2) |
266 | for s in string_gmatch(libs, "[%a%d.]+") do | 304 | else |
267 | if not valid_libs[s] then | 305 | found[s] = (found[s] or 0) + 1 |
268 | error( "Bad library name: " .. s) | 306 | if found[s] > 1 then |
269 | else | 307 | error( "libs specification contains '" .. s .. "' more than once", 2) |
270 | found[s] = (found[s] or 0) + 1 | 308 | end |
271 | if found[s] > 1 then | 309 | end |
272 | error( "libs specification contains '" .. s .. "' more than once") | 310 | end |
273 | end | 311 | end |
274 | end | ||
275 | end | ||
276 | end | ||
277 | |||
278 | local prio, cs, g_tbl, package_tbl, required, gc_cb | ||
279 | |||
280 | for k,v in pairs(opt) do | ||
281 | if k == "priority" then | ||
282 | prio = (type( v) == "number") and v or error( "Bad 'prio' option: expecting number, got " .. type( v), lev) | ||
283 | elseif k=="cancelstep" then | ||
284 | cs = (v==true) and 100 or | ||
285 | (v==false) and 0 or | ||
286 | type(v)=="number" and v or | ||
287 | error( "Bad cancelstep: "..tostring(v), lev ) | ||
288 | elseif k=="globals" then g_tbl= v | ||
289 | elseif k=="package" then | ||
290 | package_tbl = (type( v) == "table") and v or error( "Bad package: " .. tostring( v), lev) | ||
291 | elseif k=="required" then | ||
292 | required= (type( v) == "table") and v or error( "Bad 'required' option: expecting table, got " .. type( v), lev) | ||
293 | elseif k == "gc_cb" then | ||
294 | gc_cb = (type( v) == "function") and v or error( "Bad 'gc_cb' option: expecting function, got " .. type( v), lev) | ||
295 | --.. | ||
296 | elseif k==1 then error( "unkeyed option: ".. tostring(v), lev ) | ||
297 | else error( "Bad option: ".. tostring(k), lev ) | ||
298 | end | ||
299 | end | ||
300 | 312 | ||
301 | if not package_tbl then package_tbl = package end | 313 | -- validate that each option is known and properly valued |
302 | -- Lane generator | 314 | for k, v in pairs( opt) do |
303 | -- | 315 | local validator = opt_validators[k] |
304 | return function(...) | 316 | if not validator then |
305 | return thread_new( func, libs, cs, prio, g_tbl, package_tbl, required, gc_cb, ...) -- args | 317 | error( (type( k) == "number" and "Unkeyed option: " .. type( v) .. " " .. string_format( "%q", tostring( v)) or "Bad '" .. tostring( k) .. "' option"), 2) |
306 | end | 318 | else |
307 | end | 319 | opt[k] = validator( v) |
320 | end | ||
321 | end | ||
322 | |||
323 | local cancelstep, priority, globals, package, required, gc_cb = opt.cancelstep, opt.priority, opt.globals, opt.package or package, opt.required, opt.gc_cb | ||
324 | return function( ...) | ||
325 | -- must pass functions args last else they will be truncated to the first one | ||
326 | return core_lane_new( func, libs, cancelstep, priority, globals, package, required, gc_cb, ...) | ||
327 | end | ||
328 | end -- gen() | ||
308 | 329 | ||
309 | ---=== Timers ===--- | 330 | ---=== Timers ===--- |
310 | 331 | ||