README.md

Lisphp

Lisphp is a Lisp dialect written in PHP. It was created to be embedded in
web services or to be distributed within web applications. For that reason,
it implements sandbox environment for security issues and multiple
environment instances.

Requirements

It requires PHP 5.3.0 or higher version. It also requires SPL which is
available and compiled by default.

Standalone command line interface

There is bin/lisphp, a standalone command line interface. It can take one
parameter, the filename of the Lisphp program to be executed.

$ bin/lisphp program.lisphp

You can run the program in sandbox with the option -s.

$ bin/lisphp -s program.lisphp

REPL

If there is no filename in arguments to bin/lisphp, it enters REPL mode.

Embed in your app

In order to execute a Lisphp program, an environment instance is required.
Environment represents a global state for the program. It includes global
symbols, built-in functions and macros. A program to be executed starts from the
initialized environment. You can initialize the environment with
Lisphp_Environment class.

There are two given environment sets in Lisphp_Environment. One is the
sandbox, which is created with the method Lisphp_Environment::sandbox().
In the sandbox mode, programs cannot access the file system, IO, etc.
The other set is the full environment of Lisphp, which is initialized with
Lisphp_Environment::full(). This environment provides use macro for
importing native PHP functions and classes. File system, IO, socket, etc.
can be accessed in this full environment. Following code touches file a.txt and
writes some text.

Macro use and from

The full environment of Lisphp provides use macro. It can import native PHP
functions and classes.

(use strrev array_sum array-product [substr substring])

It imports by taking function identifiers. Hyphens in identifiers are replaced
by underscores. If you supply a list as an argument to use macro, the second
symbol becomes the alias of the first function identifier.

Function body can contain one or more forms. All forms are evaluated
sequentially then the evaluated value of the last form is returned.

Plus, of course, it implements lexical scope (that is also known as closure)
also.

(define (adder n)
{lambda [x]
(setf! n (+ n x))
n})

Special form define defines global variables (and functions),
but setf! modifies local variables. See also let form.

Define custom macros

The built-in macros in Lisphp such as eval, define, lambda, let, if,
and, or do not evaluate the form of their arguments'. For example, define
takes the name to define as its first argument, but it does not evaluate the
name. In the same way, if takes three forms as arguments, but always
evaluates only two of those arguments and ignores the other. It is impossible
to implement if as a function, because then every argument would have to be
evaluated. If you have a case like this, you can try defining a macro.

Quote

There are two ways to quote a form in Lisphp. First is the macro quote, and
the other is quote syntax :. (You cannot use the traditional single quotation
because it is already being used as a string literal.)

(quote abc)
:abc
(quote (+ a b))
:(+ a b)

Playing with objects

In order to get an attribute of an object, use -> macro. It takes an object as
its first argument, and the name of the attribute follows.

Because -> does not call but gets method as a function object, the expression
above is equivalent to the following code.

call_user_func(array($object, 'method'), $method, $arguments)

About lists and nil

Lisphp implements lists in primitive, but it has some differences between
original Lisp. In original Lisp, lists are made from cons pairs. But lists
in Lisphp is just an instance of Lisphp_List class, a subclass of
ArrayObject. So it is not exactly a linked list but is similar
to an array. In the same manner, nil is also not an empty list in Lisphp
unlike in the original Lisp. It is a just synonym for PHP null value.

About value types and reference types

In PHP, primitive types such as boolean, integer, float, string, and array
behave as value types. They are always copied when they are passed as arguments
or returned from a called function. For example, arr is empty from the
beginning to the end in the following code.

(define arr (array))
(set-at! arr "element")

Such behavior is not a problem for scalar types like boolean, integer, float,
and string because they are immutable. Yet this can be problematic for native
arrays.

In PHP, objects behave as reference types, and there exists class ArrayObject
which has the same interface as PHP's native array. Lisphp_List is a subclass
of ArrayObject and you can use these classes instead of arrays.