Does Factor have an equivalent to the Python idiom if __name__=="__main__": main()? - program-entry-point

Factor appears to have a main method like any C-based language:
#! /usr/bin/env factor -script
USE: io
IN: hello
: hello ( -- ) "Hello World!" print ;
MAIN: hello
But Factor does not execute the main function automatically; if you run ./hello.factor in a terminal, nothing happens because main isn't called.
Does anyone know if Factor has syntax like Python, so that hello is actually called on ./hello.py?
def hello():
print "Hello World!"
if __name__=="__main__":
main()

Factor will now execute a main function if one is specified. You'll still have to edit ~/.factor-rc to add the INCLUDING/IN macros so that Factor will search for code in the current directory.
~/.factor-rc:
! Andrew Pennebaker
! INCLUDING macro that imports source code files in the current directory
USING: kernel vocabs.loader parser sequences lexer vocabs.parser ;
IN: syntax
: include-vocab ( vocab -- ) dup ".factor" append parse-file append use-vocab ;
SYNTAX: INCLUDING: ";" [ include-vocab ] each-token ;
scriptedmain.factor:
#! /usr/bin/env factor
USING: io math.parser ;
IN: scriptedmain
: meaning-of-life ( -- n ) 42 ;
: main ( -- ) meaning-of-life "Main: The meaning of life is " write number>string print ;
MAIN: main
test.factor:
#! /usr/bin/env factor
INCLUDING: scriptedmain ;
USING: io math.parser ;
IN: test
: main ( -- ) meaning-of-life "Test: The meaning of life is " write number>string print ;
MAIN: main
Example:
$ ./scriptedmain.factor
Main: The meaning of life is 42
$ ./test.factor
Test: The meaning of life is 42
As posted on RosettaCode.

Related

Generate a random integer in Idris

How can one generate a random integer in Idris 1.3.3?
Example program that doesn't work:
module Random
import Effect.Random --This gets me access to the rndInt function
I run the program as follows:
idris random.idr -p effects
Trying the rndInt function in the REPL, I get the following error message:
*random> rndInt 1 10
(input):Can't infer argument m to rndInt
Please include the full source code in your answer. Thank you.
Elaborating on Alissa Tung's answer, here's the full working source code, including setting the random seed (srand) with the system time:
module Random
import Effect.Random
import Effects
import System
main : IO ()
main = do
t <- time
n <- run $ do
srand t
rndInt 1 100
putStrLn $ show n
Run with:
idris random.idr -p effects
Output:
*random> :exec main
88
*random> :exec main
96
*random> :exec main
19

Alternative to Perl's <> in Raku?

Here learning my way around Raku (neé Perl 6), very nice all around. But I sorely miss the magic <> from Perl 5, where you can just:
my $x = <>;
print $x;
while(<>) {
print join(':', split);
}
(read next input line into $x, loop over the rest; input is from the files named as input or standard input if no file given). The "Perl 5 to 6" tutorials/migration guides/... just talk about slurping the whole file, or opening individual files by name. No magic "take input from named files in sequence" I can find.
I want the magic back!
The functionality you're looking for largely exists. This script:
my $x = get();
say "First: $x";
for lines() {
.say
}
Given these inputs files:
$ cat foo
foo line 1
foo line 2
$ cat bar
bar line 1
bar line 2
Will, when invoked as:
raku script.p6 foo bar
Produce the output:
First: foo line 1
foo line 2
bar line 1
bar line 2
It will also take output from $*IN if there aren't files. The only thing that doesn't exist is a single replacement for <>, since that would depend on wantarray-like functionality, which is incompatible with multiple dispatch (and Raku considers multiple dispatch is far more useful).
The zero-arg candidates for get and lines are implemented in terms of $*ARGFILES, a file handle that provides the functionality of taking the files from the argument list or from $*IN - meaning one can pass it to any code that expects a file handle.
Enough magic for you?
sub MAIN( Str $file where *.IO.f )
{
.say for $file.IO.lines.map: *.comb.join(':');
}

Perl 6 $*ARGFILES.handles in binary mode?

I'm trying out $*ARGFILES.handles and it seems that it opens the files in binary mode.
I'm writing a zip-merge program, that prints one line from each file until there are no more lines to read.
#! /usr/bin/env perl6
my #handles = $*ARGFILES.handles;
# say $_.encoding for #handles;
while #handles
{
my $handle = #handles.shift;
say $handle.get;
#handles.push($handle) unless $handle.eof;
}
I invoke it like this: zip-merge person-say3 repeat repeat2
It fails with: Cannot do 'get' on a handle in binary mode in block at ./zip-merge line 7
The specified files are text files (encoded in utf8), and I get the error message for non-executable files as well as executable ones (with perl6 code).
The commented out line says utf8 for every file I give it, so they should not be binary,
perl6 -v: This is Rakudo version 2018.10 built on MoarVM version 2018.10
Have I done something wrong, or have I uncovered an error?
The IO::Handle objects that .handles returns are closed.
my #*ARGS = 'test.p6';
my #handles = $*ARGFILES.handles;
for #handles { say $_ }
# IO::Handle<"test.p6".IO>(closed)
If you just want get your code to work, add the following line after assigning to #handles.
.open for #handles;
The reason for this is the iterator for .handles is written in terms of IO::CatHandle.next-handle which opens the current handle, and closes the previous handle.
The problem is that all of them get a chance to be both the current handle, and the previous handle before you get a chance to do any work on them.
(Perhaps .next-handle and/or .handles needs a :!close parameter.)
Assuming you want it to work like roundrobin I would actually write it more like this:
# /usr/bin/env perl6
use v6.d;
my #handles = $*ARGFILES.handles;
# a sequence of line sequences
my $line-seqs = #handles.map(*.open.lines);
# Seq.new(
# Seq.new( '# /usr/bin/env perl6', 'use v6.d' ), # first file
# Seq.new( 'foo', 'bar', 'baz' ), # second file
# )
for flat roundrobin $line-seqs {
.say
}
# `roundrobin` without `flat` would give the following result
# ('# /usr/bin/env perl6', 'foo'),
# ('use v6.d', 'bar'),
# ('baz')
If you used an array for $line-seqs, you will need to de-itemize (.<>) the values before passing them to roundrobin.
for flat roundrobin #line-seqs.map(*.<>) {
.say
}
Actually I personally would be more likely to write something similar to this (long) one-liner.
$*ARGFILES.handles.eager».open».lines.&roundrobin.flat.map: *.put
:bin is always set in this type of objects. Since you are working on the handles, you should either read line by line as instructed on the example, or reset the handle so that it's not in binary mode.

4.1 ANTLR accepts illegal input for palindrome grammar

Given the following simple palindrome grammar,
the resulting parser seems to accept any combination
of a's and b's rather than just palindromes.
[well, that was true when I incorrectly specified the start symbol; now I've revised to fix that but still don't get the desired behavior, so I'm adding my exact commands to run as well]
[and revised again, displaying suggested changes and resulting problems.]
// test1.g4
grammar test1;
palindrome
: 'z' entry EOF ;
entry
: 'a' entry 'a'
| 'b' entry 'b'
| 'a'
| 'b'
|
;
WS : [ \t\r\n]+ -> skip ;
Given this exact test1.g, I then execute the following shell script:
#!bash
# script for running ANTLR tests
ANTLR4="java -jar /usr/local/lib/antlr-4.1-complete.jar"
$ANTLR4 test1.g4
echo "grammar compiled"
x=/usr/local/lib/antlr-4.1-complete.jar
javac -classpath $x *.java 2>&1
echo "parser compiled"
#java -cp $x:. org.antlr.v4.runtime.misc.TestRig test1 start -tokens -trace -diagnost
java -cp $x:. org.antlr.v4.runtime.misc.TestRig test1 palindrome -tokens
And then running it on input "aab" gives:
aab
[#0,0:0='a',<2>,1:0]
[#1,1:1='a',<2>,1:1]
[#2,2:2='b',<1>,1:2]
[#3,4:3='<EOF>',<-1>,2:0]
No method for rule palindrome or it has arguments
If I pass aab to it, I get the following output:
line 1:3 no viable alternative at input 'b'
Are you sure you're telling it to start with entry instead of start now? If you start with entry, the generated code literally does not contain a code flow path that will not produce a syntax error for the input aab. You could hide the message by overriding the output listener, piping stdout somewhere you can't see, or terminating the process before parsing completes, but the syntax error will happen otherwise.

Forth as an interactive C program tester

I'm willing to use an interactive language to test some C code from a legacy project. I know a little Forth, but I haven't ever used it in a real world project. I'm looking at pForth right now.
Is it reasonable to use an interactive Forth interpreter to test the behavior of some function in a C program? This C code has lots of structs, pointers to structs, handles and other common structures found in C.
I suppose I'll have to write some glue code to handle the parameter passing and maybe some struct allocation in the Forth side. I want an estimate from someone with experience in this field. Is it worth it?
If you want interactive testing and are targeting embedded platforms, then Forth is definitely a good candidate. You'll always find a Forth implementation that runs on your target platform. Writing one is not even hard either if need be.
Instead of writing glue code specific to your immediate needs, go for a generic purpose Forth to C interface. I use gforth's generic C interface which is very easy to use. For structure handling in Forth, I use an MPE style implementation which is very flexible when it comes to interfacing with C (watch out for proper alignment though, see gforth %align / %allot / nalign).
The definition of generic purpose structure handling words takes about 20 lines of Forth code, same for single linked lists handling or hash tables.
Since you cannot use gforth (POSIX only), write an extension module for your Forth of choice that implements a similar C interface. Just make sure that your Forth and your C interface module uses the same malloc() and free() than the C code you want to test.
With such an interface, you can do everything in Forth by just defining stub words (i.e. map Forth words to C functions and structures).
Here's a sample test session where I call libc's gettimeofday using gforth's C interface.
s" structs.fs" included also structs \ load structure handling code
clear-libs
s" libc" add-lib \ load libc.so. Not really needed for this particular library
c-library libc \ stubs for C functions
\c #include <sys/time.h>
c-function gettimeofday gettimeofday a a -- n ( struct timeval *, struct timezone * -- int )
end-c-library
struct timeval \ stub for struct timeval
8 field: ->tv_sec \ sizeof(time_t) == 8 bytes on my 64bits system
8 field: ->tv_usec
end-struct
timeval buffer: tv
\ now call it (the 0 is for passing NULL for struct timezone *)
tv 0 gettimeofday . \ Return value on the stack. output : 0
tv ->tv_sec # . \ output : 1369841953
Note that tv ->tv_sec is in fact the equivalent of (void *)&tv + offsetof(struct timeval, tv_sec) in C, so it gives you the address of the structure member, so you have to fetch the value with #. Another issue here: since I use a 64 bits Forth where the cell size is 8 bytes, storing/fetching an 8 bytes long is straightforward, but fetching/storing a 4 bytes int will require some special handling. Anyhow, Forth makes this easy: just define special purpose int# and int! words for that.
As you can see, with a good generic purpose C interface you do not need to write any glue code in C, only the Forth stubs for your C functions and structures are needed, but this is really straightforward (and most of it could be automatically generated from your C headers).
Once you're happy with your interactive tests, you can move on to automated tests:
Copy/paste the whole input/output from your interactive test session to a file named testXYZ.log
strip the output (keeping only the input) from your session log and write this to a file named testXYZ.fs
To run the test, pipe testXYZ.fs to your forth interpreter, capture the output and diff it with testXYZ.log.
Since removing output from an interactive session log can be somewhat tedious, you could also start by writing the test script testXYZ.fs then run it and capture the output testXYZ.log, but I prefer starting from an interactive session log.
Et voilà !
For reference, here's the structure handling code that I used in the above example :
\ *****************************************************************************
\ structures handling
\ *****************************************************************************
\ Simple structure definition words. Structure instances are zero initialized.
\
\ usage :
\ struct foo
\ int: ->refCount
\ int: ->value
\ end-struct
\ struct bar
\ int: ->id
\ foo struct: ->foo
\ 16 chars: ->name
\ end-struct
\
\ bar buffer: myBar
\ foo buffer: myFoo
\ 42 myBar ->id !
\ myFoo myBar ->foo !
\ myBar ->name count type
\ 1 myBar ->foo # ->refCount +! \ accessing members of members could use a helper word
: struct ( "name" -- addr 0 ; named structure header )
create here 0 , 0
does>
# ;
\ <field-size> FIELD <field-name>
\ Given a field size on the stack, compiles a word <field-name> that adds the
\ field size to the number on the stack.
: field: ( u1 u2 "name" -- u1+u2 ; u -- u+u2 )
over >r \ save current struct size
: r> ?dup if
postpone literal postpone +
then
postpone ;
+ \ add field size to struct size
; immediate
: end-struct ( addr u -- ; end of structure definition )
swap ! ;
: naligned ( addr1 u -- addr2 ; aligns addr1 to alignment u )
1- tuck + swap invert and ;
\ Typed field helpers
: int: cell naligned cell postpone field: ; immediate
: struct: >r cell naligned r> postpone field: ; immediate
: chars: >r cell naligned r> postpone field: ; immediate
\ with C style alignment
4 constant C_INT_ALIGN
8 constant C_PTR_ALIGN
4 constant C_INT_SIZE
: cint: C_INT_ALIGN naligned C_INT_SIZE postpone field: ; immediate
: cstruct: >r C_PTR_ALIGN naligned r> postpone field: ; immediate
: cchars: >r C_INT_ALIGN naligned r> postpone field: ; immediate
: buffer: ( u -- ; creates a zero-ed buffer of size u )
create here over erase allot ;