Skip to content

Instantly share code, notes, and snippets.

@guregu

guregu/post.md Secret

Created January 23, 2023 09:14
Show Gist options
  • Save guregu/4e5508db7d1321d57aec2a63a164ebc7 to your computer and use it in GitHub Desktop.
Save guregu/4e5508db7d1321d57aec2a63a164ebc7 to your computer and use it in GitHub Desktop.
cohost bug

Recently I've been hacking on php (Prolog Home Page). It started because I thought calling a Prolog thing PHP would be funny, but I've found it to be weirdly fun to use. It's basically PHP syntax with Prolog code.

I was curious if this had been done before, and turns it out that it has. I've found 3 implementations that call themselves "Prolog Server Pages", some eerily similar to mine.

PSP (Alin S., et al. 2006)

The first I found was Prolog Server Pages by Alin Suciu, Kalman Pusztai, and Andrei Vancea. It uses an Apache module to call into SWI Prolog's FFI interface.

Here's a "Hello World" example from the paper:

<html>
<head>
<title>Hello World example</title>
</head>
<body>
<?psp
msg('Hello, World!').
?-msg(X), write(X).
?>
</body>
</html>

They have only one flavor of <? ... ?> brackets. Inside of them, statements that begin with ?- are processed as queries, and the rest are processed as assertions. I think this is quite an elegant choice of syntax, as the meaning of ?- will be obvious to anyone familiar with a Prolog toplevel (REPL).

Here's an example from the paper of code to display the results of submitting a form:

<body>
<?psp
?-arg('firstname', FIRSTNAME),
write('First name : '),
write(FIRSTNAME),
write('<br>'). 
?>
</body>

The downside of this approach is that it is difficult to work with HTML within queries. You have to output unescaped HTML manually. The example above is an XSS attack waiting to happen.

Prolog Server Pages (Benjamin J., 2005?)

This one is by Benjamin Johnston, and its homepage is archived here. It mentions prior art by Jan Wielemaker of SWI (2004) and a system called MINERVA that has ASP-like syntax. It uses SWI.

Let's take a look at the hello world:

greeting_noun(Noun) :-
	Noun = 'world'.

/*<html>
<body>
<?, greeting_noun(X) ,?>

Hello <?= X ?>

</body>
</html>*/

This one's bracket syntax is almost the same as mine, with <?, Goal ,?> to execute queries and <?= Term ?> to print terms. It uses a preprocessor to convert the HTML within the /* */ comments to write/1 statements. The upshot of this comment hack is that you can execute the scripts directly from a Prolog REPL and test your stuff, which is very cool.

A more complex example is available here which shows off the ability to insert HTML within a query just like elephant PHP, and a session system for persisting user data.

/* another <?, once(?> simple <?), ?> example */
becomes
write(' another '), once(write(' simple ')), write(' example ')

I'm glad I found this one because it makes me feel a little better about my syntax choices.

PSP (Mauro D., 2006?)

Here's another one called PSP by Mauro Di Nuzzo. It works similarly to Benjamin's, with templates that are converted to write/1 goals. This also uses SWI.

Here's a relatively complex example:

<html>
<body>
<?,
	( 	consult ('my_db .pl') % here are defs for my_db_pred/2
	->
?>
<form>
<select>
<?,
		( 	my_db_pred (Name , Value ),
?>
<option value ="<?= Value ?>"><?= Name ?></option>
<?,
			fail % failure - driven loop
		; true
		),
?>
</select>
</form>
<?
	;
?>
Cannot open my_database .pl<br>
<?
	),
?>
</body>

This PSP also allows you to insert HTML within a query. We can see it uses a failure-driven loop to walk through solutions for a query. Failure-driven loops aren't my cup of tea, but it demonstrates that it is quite powerful. There are also facilities to switch from 'query mode' to 'assert mode', and a handful of useful web-related predicates.

PHP (2022)

And then we have mine. It has nearly identical syntax to the above two (great minds think alike?). PHP works a bit differently in that it does not preprocess the code to turn it into write/1 statements but instead executes it directly from the (extremely simplistic) AST generated by a DCG.

One disadvantage is that you can't interrupt queries in arbitrary spots to insert HTML in places. Instead you can use <?if (should probably be called <?once) and <?findall.

<h3>Query params</h3>
	<table>
		<tr><th>Key</th><th>Value</th></tr>
	<?findall query_param(K, V). ?>
		<tr><td><?=K ?></td><td><?=V ?></td></tr>
	<?end ?>
	</table>

I am not very happy with this syntax, but it works for now. Queries within these block tags inherit the variable bindings of its parent.

In PHP, <?- Goal ?> executes a query and <? Clauses... ?> asserts clauses. You can also use <?=Var ?> to echo variables.

It's definitely a bit rough, but I enjoy hacking on it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment