Does Perl 6's eof give up too quickly? - raku

In Perl 5 I can check if standard input is open and read one line from it.
for (;;) {
last if eof(STDIN);
print "Got line " . readline(STDIN);
}
When I run it an enter a line of input it reads that line and does its work before moving on. The program does not care if there are long pauses:
$ perl print-stdin.pl
this
Got line this
is
Got line is
a
Got line a
line
Got line line
If I do the same thing in Perl 6 (Rakudo 2017.07) the program stops right away:
use v6;
loop {
last if $*IN.eof;
put "Got line " ~ $*IN.get;
}
I'm really after a Supply that can give me one line of input as it arrives (perhaps from a program that slowly outputs line with long pauses) but I backed up all the way to this simple problem. I didn't find a builtin way to do this (which is a bit surprising for such a common task).

It seems to work better on latest.
Although what you wrote has a race condition as the input can be closed after the call to .eof. Which means it can happen while .get is blocked, so it will return Nil. This would cause a warning to be thrown, and an extra Got line  to be printed.
It's better to just use the Iterator from .lines
for $*IN.lines { put "Got line $_" }
or use the return value of .get to determine when the input is closed.
loop {
with $*IN.get {
put "Got line $_"
} else {
last
}
}
If you want a Supply from the input lines:
$*IN.lines.Supply
react {
start whenever $*IN.lines.Supply {
put "Got line $_";
LAST done; # finish the outer 「react」 block when this closes
}
whenever Supply.interval(1) {
put DateTime.now.hh-mm-ss
}
}
22:46:33
22:46:34
a
Got line a
22:46:35
22:46:36
b
Got line b
22:46:37
22:46:38
c
Got line c
22:46:39
22:46:40
d
Got line d
22:46:41
22:46:42
^D # represents Ctrl+D
The start is needed above so it doesn't block the Supply.interval(1) supply from starting properly.
If the above wasn't possible for some reason you could create a Supply like this:
my \in-supply = supply {
# 「await start」 needed so this won't block other things on this thread.
await start loop {
with $*IN.get { # defined (so still open)
emit $_
} else { # not defined (closed)
done; # stop the Supply
# last # stop this loop (never reached)
}
}
}
react {
whenever in-supply {
put "Got line $_";
LAST done # finish the outer 「react」 block when this closes
}
whenever Supply.interval(1) {
put DateTime.now.hh-mm-ss
}
}

Related

Can you retry a Zig function call when it returns an error?

Zig's documentation shows different methods of error handling including bubbling the error value up the call stack, catching the error and using a default value, panicking, etc.
I'm trying to figure out how to retry functions which provide error values.
For example, in the below snippet from ziglearn, is there a way to retry the nextLine function in the event that a user enters greater than 100 characters?
fn nextLine(reader: anytype, buffer: []u8) !?[]const u8 {
var line = (try reader.readUntilDelimiterOrEof(
buffer,
'\n',
)) orelse return null;
// trim annoying windows-only carriage return character
if (#import("builtin").os.tag == .windows) {
return std.mem.trimRight(u8, line, "\r");
} else {
return line;
}
}
test "read until next line" {
const stdout = std.io.getStdOut();
const stdin = std.io.getStdIn();
try stdout.writeAll(
\\ Enter your name:
);
var buffer: [100]u8 = undefined;
const input = (try nextLine(stdin.reader(), &buffer)).?;
try stdout.writer().print(
"Your name is: \"{s}\"\n",
.{input},
);
}
This should do what you want.
const input = while (true) {
const x = nextLine(stdin.reader(), &buffer) catch continue;
break x;
} else unreachable; // (see comment) fallback value could be an empty string maybe?
To break it down:
instead of try, you can use catch to do something in the case of an error, and we're restarting the loop in this case.
while loops can also be used as expressions and you can break from them with a value. they also need an else branch, in case the loop ends without breaking away from it. in our case this is impossible since we're going to loop forever until nextLine suceeds, but if we had another exit condition (like a limit on the number of retries), then we would need to provide a "fallback" value, instead of unreachable.
You can also make it a one-liner:
const input = while (true) break nextLine(stdin.reader(), &buffer) catch continue else unreachable;
Hopefully the new self-hosted compiler will be able to pick up on the fact that the else branch is not necessary, since we're going to either break with a value loop forever.

After first "once {next}" block, other same-scoped "once" blocks fail to execute

My original plan was to use two once {next} blocks to skip the first two lines in a file (here emulating a as a multiline string):
for "A\nB\nC\n".lines() -> $line {
once {next}
once {next}
put $line;
}
But it only skipped one iteration instead of two, outputting the following:
B
C
Instead of what I expected:
C
Apparently a single once {next} somehow cancels all remaining once blocks in the same scope:
my $guard = 3;
loop {
last if $guard-- <= 0;
once { next };
once { put 'A: once ' };
once { put 'A: once again' };
put 'A: many ';
}
$guard = 3;
loop {
last if $guard-- <= 0;
once { put 'B: once ' };
once { next };
once { put 'B: once again' };
put 'B: many ';
}
$guard = 3;
loop {
last if $guard-- <= 0;
once { put 'C: once ' };
once { put 'C: once again' };
once { next };
put 'C: many ';
}
Outputting:
A: many
A: many
B: once
B: many
B: many
C: once
C: once again
C: many
C: many
(Example code here is a modified version of code at https://docs.raku.org/language/control#once).
Is this a bug or am I misunderstanding once {next} ?
The once construct semantics are associated with closure clones; since for is defined in terms of map, we can think of the block of the for loop being like a closure that is cloned once per loop, and that clone used for all iterations of the loop. The running of once blocks is done only on the first invocation of that closure clone. That is to say, it's a property at the level of the closure, not one of the once block itself.
The very same semantics apply to state variable initializers, which are defined in the same way (that is, they have once semantics). Therefore, this this also exhibits the same behavior:
for "A\nB\nC\n".lines() -> $line {
state $throwaway-a = next;
state $throwaway-b = next; # this `next` never runs
put $line;
}
Alternative semantics could have been chosen, however a per-once (and so per-state variable) indicator would imply an extra piece of state is needed for each of them.
So far as the original problem goes, a clearer solution would be:
for "A\nB\nC\n".lines().skip(2) -> $line {
put $line;
}

How can I use the perl6 regex metasyntax, <foo regex>?

In perl6 grammars, as explained here (note, the design documents are not guaranteed to be up-to-date as the implementation is finished), if an opening angle bracket is followed by an identifier then the construct is a call to a subrule, method or function.
If the character following the identifier is an opening paren, then it's a call to a method or function eg: <foo('bar')>. As explained further down the page, if the first char after the identifier is a space, then the rest of the string up to the closing angle will be interpreted as a regex argument to the method - to quote:
<foo bar>
is more or less equivalent to
<foo(/bar/)>
What's the proper way to use this feature? In my case, I'm parsing line oriented data and I'm trying to declare a rule that will instigate a seperate search on the current line being parsed:
#!/usr/bin/env perl6
# use Grammar::Tracer ;
grammar G {
my $SOLpos = -1 ; # Start-of-line pos
regex TOP { <line>+ }
method SOLscan($regex) {
# Start a new cursor
my $cur = self."!cursor_start_cur"() ;
# Set pos and from to start of the current line
$cur.from($SOLpos) ;
$cur.pos($SOLpos) ;
# Run the given regex on the cursor
$cur = $regex($cur) ;
# If pos is >= 0, we found what we were looking for
if $cur.pos >= 0 {
$cur."!cursor_pass"(self.pos, 'SOLscan')
}
self
}
token line {
{ $SOLpos = self.pos ; say '$SOLpos = ' ~ $SOLpos }
[
|| <word> <ws> 'two' { say 'matched two' } <SOLscan \w+> <ws> <word>
|| <word>+ %% <ws> { say 'matched words' }
]
\n
}
token word { \S+ }
token ws { \h+ }
}
my $mo = G.subparse: q:to/END/ ;
hello world
one two three
END
As it is, this code produces:
$ ./h.pl
$SOLpos = 0
matched words
$SOLpos = 12
matched two
Too many positionals passed; expected 1 argument but got 2
in method SOLscan at ./h.pl line 14
in regex line at ./h.pl line 32
in regex TOP at ./h.pl line 7
in block <unit> at ./h.pl line 41
$
Line 14 is $cur.from($SOLpos). If commented out, line 15 produces the same error. It appears as though .pos and .from are read only... (maybe :-)
Any ideas what the proper incantation is?
Note, any proposed solution can be a long way from what I've done here - all I'm really wanting to do is understand how the mechanism is supposed to be used.
It does not seem to be in the corresponding directory in roast, so that would make it a "Not Yet Implemented" feature, I'm afraid.

Perl6: is there a phaser that runs only when you fall out of a loop?

Take this sample code:
#!/usr/bin/env perl6
use v6.c;
ROLL:
for 1..10 -> $r {
given (1..6).roll {
when 6 {
say "Roll $r: you win!";
last ROLL;
}
default {
say "Roll $r: sorry...";
}
}
LAST {
say "You either won or lost - this runs either way";
}
}
I'd like to be able to distinguish falling out of the loop from explicitly saying last.
Ideally, there'd be a phaser for this, but as far as I can find, there is only LAST which runs in either case.
Is there an elegant way to do this? (Elegant, so without adding a $won variable.)
We're dealing with Perl, so There's More Than One Way To Do It; one of them is using the topic variable $_ to keep the value so we can easily match against it repeatedly:
constant N = 5;
for flat (1..6).roll xx * Z 1..N -> $_, $n {
print "roll $n: $_ ";
when 6 {
put "(won)";
last;
}
default {
put "(lost)";
}
LAST {
print "result: ";
when 6 { put "winner :)" }
default { put "loser :(" }
}
}
Here's another way to do it. Elegant? I think reasonably so. I wish there were a separate phaser for this, though.
#!/usr/bin/env perl6
use v6.c;
constant MAX_ROLLS = 10;
ROLL:
for 1..MAX_ROLLS+1 -> $r {
last ROLL if $r > MAX_ROLLS;
given (1..6).roll {
when 6 {
say "Roll $r: you win!";
last ROLL;
}
default {
say "Roll $r: sorry...";
}
}
LAST {
say "You lost, better luck next time!" if $r > MAX_ROLLS;
}
}

TCL: While no key is pressed loop

I would like to run a while loop until the stdin is filled with a character.
puts "Press x + <enter> to stop."
while {[gets stdin] != "x"} {
puts "lalal"
}
The problem with the code above that it will wait for stdin and I don't want it to wait. I want the code to be executed all the time.
Edit 8th September 2011 - 8.55am
The code is used inside a FPGA tool called System Console (Altera). This does work with TCL Commands, but unfortunately I don't know which it can handle and which it doesn't.
You should use a fileevent on stdin to set a function to be called once the channel becomes readable then use vwait to run the event loop. Your other tasks can be launched using after chains to have work done in pieces without halting the event processing for too long.
proc do_work {args} {...}
proc onRead {chan} {
set data [read $chan]
if {[eof $chan]} {
fileevent $chan readable {}
set ::forever eof
}
... do something with the data ...
}
after idle [list do_work $arg1]
fconfigure stdin -blocking 0 -buffering line
fileevent stdin readable [list onRead stdin]
vwait forever
If you put the stdin channel into non-block mode, the gets stdin will return the empty string (and fblocked stdin will then be able to return 1) when input is not available, instead of waiting for something to happen.
# Enable magic mode!
fconfigure stdin -blocking 0
puts "Press x + <enter> to stop."
while {[gets stdin] != "x"} {
puts "lalal"
after 20; # Slow the loop down!
}
# Set it back to normal
fconfigure stdin -blocking 1
In fact, you can also use the system stty program to do even more fancy things.