mthom / scryer-prolog

A modern Prolog implementation written mostly in Rust.
BSD 3-Clause "New" or "Revised" License
2.06k stars 123 forks source link

#! prolog #2170

Open mhemery opened 1 year ago

mhemery commented 1 year ago

The rather typical shebang kills scryer prolog.

my minimal example is a file with just : #! prolog

hemery@portablepret:prolog$ ~/scryer-prolog shebang.pl 
   error(syntax_error(incomplete_reduction),read_term/3:1).
UWN commented 1 year ago

Invalid syntax. What else to expect?

infogulch commented 12 months ago

Sometimes languages will add an exception to allow shebang syntax on the first line. Mechanically, this would mean ignoring the first line of the file if it starts with #!, treating it as a comment. With this feature, users on the terminal could mark the file as executable with chmod +x program.pl and execute it directly like ./program.pl without having to name the interpreter explicitly every time. Shells that execute a file that starts with a shebang will start the identified interpreter with the filename as the first argument instead.

This can be nice for integrating into unix-y systems. While it works out of the box with the many scripting languages that use # as a comment symbol (python, perl, ruby) some languages that use different comment symbols will allow shebang on the first line as a specific exception. RosettaCode.org lists a number of examples of this: https://rosettacode.org/wiki/Native_shebang

This may or may not be a good fit for scryer-prolog, but it would certainly be useful for interacting with scryer-prolog in a shell environment.


I played around with it and actually found a very hacky way to do this with scryer-prolog in bash today:

$ cat test.pl
/*usr/bin/env scryer-prolog "$0" "$@" ; exit #*/

run :- write(hello),nl,halt.
:- initialization(run).
$ chmod +x test.pl
$ ./test.pl
hello

The way this works is that this test.pl is both a valid shell file and prolog file. So when executing as a shell file the first line finds and executes /usr/bin/env after searching for the glob pattern /*usr/bin/env. env then executes scryer-prolog "test.pl" which runs the prolog file as a module and halts; of course it ignores the first line as a comment /* ... */. Then the shell continues and executes the next command after ;, which is exit which stops execution so the rest of the file (which is not valid shell) is ignored. The # makes the shell evaluator ignore the */ that closes the comment for prolog. (Thanks to the comment from johannesloetzsch for this last tweak!)

I don't know what to think about this.

triska commented 12 months ago

As far as I can tell, that's ingenious!

It remains valid Prolog syntax, and can also be used as a shell file.

friedrich commented 10 months ago

Great summary, @infogulch. I would much prefer a non-hacky solution, like having scryer-prolog ignore the shebang, similar to what SWI-Prolog does.

UWN commented 10 months ago

@infogulch, one minor improvement: Instead of /*/bin/env rather use /*usr/bin/env which should reduce the search overhead.

UWN commented 10 months ago

... and avoids exploits with /tmp/bin/env ...

johannesloetzsch commented 3 weeks ago

/usr/bin/env scryer-prolog "$0" "$@" ; exit /

Nice polyglot hack :+1:

When I run it, it works, but also shows an error at the end:

./test.pl
hello
./test.pl: line 1: exit: */: numeric argument required

It can be simply fixed, by adding an additional # behind the exit to prevent sh from evaluating the */. The fixed shebang line than looks like this:

/*usr/bin/env scryer-prolog "$0" "$@" ; exit #*/