new API for file operations
File operations now always return a channel (or nil on error or permission denied). When start_reading() from a filename, you can repeatedly :recv() from the channel it returns. When :recv() returns nil, you're at the end of the file. Stop. When you start_writing() to a filename, you can repeatedly :send() to the channel it returns. When you're done writing, :close() the channel. Writes to the file won't be externally visible until you do. To make this work I'm now always starting up the scheduler, so I need to fix sieve.tlv. Transparently running the scheduler is an abstraction, and whenever I create an abstraction I always worry about how it might fail. There's a hopefully-clear error when you read past end of a file.
This commit is contained in:
parent
2d6b88204b
commit
52ae23784b
62
sieve.tlv
62
sieve.tlv
|
@ -265,18 +265,9 @@
|
||||||
>
|
>
|
||||||
>You can also override the default big picture screen entirely by creating a buffer called 'doc:main'.
|
>You can also override the default big picture screen entirely by creating a buffer called 'doc:main'.
|
||||||
- __teliva_timestamp:
|
- __teliva_timestamp:
|
||||||
>Sat Feb 26 21:49:00 2022
|
>Sat Feb 26 21:50:11 2022
|
||||||
main:
|
main:
|
||||||
>function main()
|
>function main()
|
||||||
> task.spawn(main_task)
|
|
||||||
> task.scheduler()
|
|
||||||
> print('out of scheduler')
|
|
||||||
> Window:getch()
|
|
||||||
>end
|
|
||||||
- __teliva_timestamp:
|
|
||||||
>Sat Feb 26 21:50:11 2022
|
|
||||||
main_task:
|
|
||||||
>function main_task()
|
|
||||||
> local c = task.Channel:new()
|
> local c = task.Channel:new()
|
||||||
> task.spawn(counter, c)
|
> task.spawn(counter, c)
|
||||||
> for i=1,10 do
|
> for i=1,10 do
|
||||||
|
@ -308,8 +299,8 @@
|
||||||
>end
|
>end
|
||||||
- __teliva_timestamp:
|
- __teliva_timestamp:
|
||||||
>Sat Feb 26 21:55:46 2022
|
>Sat Feb 26 21:55:46 2022
|
||||||
main_task:
|
main:
|
||||||
>function main_task()
|
>function main()
|
||||||
> local primes = task.Channel:new()
|
> local primes = task.Channel:new()
|
||||||
> task.spawn(sieve, primes)
|
> task.spawn(sieve, primes)
|
||||||
> for i=1,10 do
|
> for i=1,10 do
|
||||||
|
@ -346,29 +337,17 @@
|
||||||
>end
|
>end
|
||||||
- __teliva_timestamp:
|
- __teliva_timestamp:
|
||||||
>Sat Feb 26 22:09:47 2022
|
>Sat Feb 26 22:09:47 2022
|
||||||
main_task:
|
|
||||||
>function main_task(window)
|
|
||||||
> local primes = task.Channel:new()
|
|
||||||
> task.spawn(sieve, primes)
|
|
||||||
> while true do
|
|
||||||
> window:addstr(primes:recv())
|
|
||||||
> window:addstr(' ')
|
|
||||||
> window:refresh()
|
|
||||||
> end
|
|
||||||
>end
|
|
||||||
- __teliva_timestamp:
|
|
||||||
>Sat Feb 26 22:08:52 2022
|
|
||||||
__teliva_note:
|
__teliva_note:
|
||||||
>infinite primes
|
>infinite primes
|
||||||
main:
|
main:
|
||||||
>function main()
|
>function main()
|
||||||
> Window:nodelay(true)
|
> local primes = task.Channel:new()
|
||||||
> Window:clear()
|
> task.spawn(sieve, primes)
|
||||||
> task.spawn(main_task, Window)
|
> while true do
|
||||||
> task.scheduler()
|
> Window:addstr(primes:recv())
|
||||||
> print('key pressed; done')
|
> Window:addstr(' ')
|
||||||
> Window:nodelay(false)
|
> Window:refresh()
|
||||||
> Window:getch()
|
> end
|
||||||
>end
|
>end
|
||||||
- __teliva_timestamp:
|
- __teliva_timestamp:
|
||||||
>Sat Feb 26 22:09:47 2022
|
>Sat Feb 26 22:09:47 2022
|
||||||
|
@ -376,21 +355,26 @@
|
||||||
>clear screen when it fills up; pause on keypress
|
>clear screen when it fills up; pause on keypress
|
||||||
>
|
>
|
||||||
>In Teliva getch() implicitly refreshes the screen.
|
>In Teliva getch() implicitly refreshes the screen.
|
||||||
main_task:
|
main:
|
||||||
>function main_task(window)
|
>function main()
|
||||||
|
> Window:nodelay(true)
|
||||||
|
> Window:clear()
|
||||||
> local primes = task.Channel:new()
|
> local primes = task.Channel:new()
|
||||||
> task.spawn(sieve, primes)
|
> task.spawn(sieve, primes)
|
||||||
> local h, w = window:getmaxyx()
|
> local h, w = Window:getmaxyx()
|
||||||
> while true do
|
> while true do
|
||||||
> window:addstr(primes:recv())
|
> Window:addstr(primes:recv())
|
||||||
> window:addstr(' ')
|
> Window:addstr(' ')
|
||||||
> local c = window:getch()
|
> local c = Window:getch()
|
||||||
> if c then break end -- key pressed
|
> if c then break end -- key pressed
|
||||||
> local y, x = window:getyx()
|
> local y, x = Window:getyx()
|
||||||
> if y > h-1 then
|
> if y > h-1 then
|
||||||
> window:clear()
|
> Window:clear()
|
||||||
> end
|
> end
|
||||||
> end
|
> end
|
||||||
|
> print('key pressed; done')
|
||||||
|
> Window:nodelay(false)
|
||||||
|
> Window:getch()
|
||||||
>end
|
>end
|
||||||
- __teliva_timestamp:
|
- __teliva_timestamp:
|
||||||
>Sat Feb 26 22:27:25 2022
|
>Sat Feb 26 22:27:25 2022
|
||||||
|
|
11
src/task.lua
11
src/task.lua
|
@ -380,6 +380,17 @@ _M.RECV = RECV
|
||||||
_M.SEND = SEND
|
_M.SEND = SEND
|
||||||
_M.NOP = NOP
|
_M.NOP = NOP
|
||||||
|
|
||||||
|
-- Specific to Teliva
|
||||||
|
function spawn_main()
|
||||||
|
task.spawn(main)
|
||||||
|
task.scheduler()
|
||||||
|
assert(false, "Teliva's scheduler ran out of work; this shouldn't happen.\n"..
|
||||||
|
"Either a channel is blocked forever or you're reading past\n"..
|
||||||
|
"the end of a file (after recv() returned nil).\n")
|
||||||
|
curses.nodelay(true)
|
||||||
|
curses.getch()
|
||||||
|
end
|
||||||
|
|
||||||
----------------------------------------------------------------------------
|
----------------------------------------------------------------------------
|
||||||
----------------------------------------------------------------------------
|
----------------------------------------------------------------------------
|
||||||
-- Tests
|
-- Tests
|
||||||
|
|
|
@ -1794,7 +1794,7 @@ int handle_image(lua_State* L, char** argv, int n) {
|
||||||
/* initialize permissions */
|
/* initialize permissions */
|
||||||
load_permissions_from_user_configuration(L);
|
load_permissions_from_user_configuration(L);
|
||||||
/* call main() */
|
/* call main() */
|
||||||
lua_getglobal(L, "main");
|
lua_getglobal(L, "spawn_main");
|
||||||
status = docall(L, 0, 1);
|
status = docall(L, 0, 1);
|
||||||
if (status != 0) return report_in_developer_mode(L, status);
|
if (status != 0) return report_in_developer_mode(L, status);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
48
template.tlv
48
template.tlv
|
@ -385,3 +385,51 @@
|
||||||
> '123 ',
|
> '123 ',
|
||||||
> 'test_check_screen')
|
> 'test_check_screen')
|
||||||
>end
|
>end
|
||||||
|
- __teliva_timestamp: original
|
||||||
|
start_reading:
|
||||||
|
>-- primitive for reading files from a file system (or, later, network)
|
||||||
|
>-- returns a channel or nil on error
|
||||||
|
>-- read lines from the channel using :recv()
|
||||||
|
>-- recv() on the channel will indicate end of file.
|
||||||
|
>function start_reading(fs, filename)
|
||||||
|
> local result = task.Channel:new()
|
||||||
|
> local infile = io.open(filename)
|
||||||
|
> if infile == nil then return nil end
|
||||||
|
> task.spawn(reading_task, infile, result)
|
||||||
|
> return result
|
||||||
|
>end
|
||||||
|
>
|
||||||
|
>function reading_task(infile, chanout)
|
||||||
|
> for line in infile:lines() do
|
||||||
|
> chanout:send(line)
|
||||||
|
> end
|
||||||
|
> chanout:send(nil) -- eof
|
||||||
|
>end
|
||||||
|
- __teliva_timestamp: original
|
||||||
|
start_writing:
|
||||||
|
>-- primitive for writing files to a file system (or, later, network)
|
||||||
|
>-- returns a channel or nil on error
|
||||||
|
>-- write to the channel using :send()
|
||||||
|
>-- indicate you're done writing by calling :close()
|
||||||
|
>-- file will not be externally visible until :close()
|
||||||
|
>function start_writing(fs, filename)
|
||||||
|
> local result = task.Channel:new()
|
||||||
|
> local initial_filename = os.tmpname()
|
||||||
|
> local outfile = io.open(initial_filename, 'w')
|
||||||
|
> if outfile == nil then return nil end
|
||||||
|
> result.close = function()
|
||||||
|
> result:send(nil) -- end of file
|
||||||
|
> outfile:close()
|
||||||
|
> os.rename(initial_filename, filename)
|
||||||
|
> end
|
||||||
|
> task.spawn(writing_task, outfile, result)
|
||||||
|
> return result
|
||||||
|
>end
|
||||||
|
>
|
||||||
|
>function writing_task(outfile, chanin)
|
||||||
|
> while true do
|
||||||
|
> local line = chanin:recv()
|
||||||
|
> if line == nil then break end -- end of file
|
||||||
|
> outfile:write(line)
|
||||||
|
> end
|
||||||
|
>end
|
||||||
|
|
Loading…
Reference in New Issue