A lisp-like language for php.
This is a sample Hello World code of it.
PHP Code:
<?php
require_once "vendor/autoload.php";
$pisp = new PispPisp;
$code = file_get_contents("code.pisp");
$pisp->define("print", function ($args, $vm) {
foreach ($args as $v) {
if (is_string($v) || method_exists($v, "__toString")) {
echo $v;
} else {
var_dump($v);
}
}
});
$pisp->execute($code);Content of code.pisp:
(print "Hello World" "n")Result:
Hello World
composer require xtlsoft/pispWe have built a facade for you. You can use it easily.
<?php
$pisp = new PispPisp();Right, The PispPisp class is the facade.
It extends the PispVMVM class and have an execute method to execute code directly.
For example:
<?php
$code = '(print ["Hello World"] ["n"])';
$pisp->execute($code);This is the main VM class.
We have a define and a delete method which are used to define and delete functions.
Yes! Variables are also functions in Pisp because it is purely functional.
<?php
$vm = new PispPisp; // Also can be $vm = new PispVMVM;
$vm->define("abc", 123);
$vm->define("+", function ($args, $vm) {
return $args[0] + $args[1];
});
$vm->delete("abc");
echo $vm->execute("(+ 1 2)"); // 3Have you noticed? When defining a function, it must a valid callback with 2 parameters. The first one is the array of the real arguments, and the second one is the instance of the PispVMVM class.
You can dynamically add functions.
This is for parsing code.
<?php
$parser = new PispParserParser;
$rslt = $parser->parse('(print ["Hello Worldn"])');
var_export($rslt instanceof PispParserASTRoot); // trueThis is for walking the AST.
<?php
$walker = new PispParserASTWalker($rslt);
$walker->walk(function (PispParserASTNode $node) {
echo $node->name, PHP_EOL;
});A function call starts with a ( and ends with a ) .
Function name and arguments are separated by any blank characters.
Arguments are optional.
For example:
(+ 1 2)
(+
1
2
)
( + 1 2 )
(a_function_call_without_arguments)The literals are not surrounded by [ and ] now.
For example:
(+ 1 2)
(print "a string")
(+ 1.2 1.4)Moreover, Pisp supports lazy calls.
Just add an @ before the function name and the arguments will be their ASTs.
(@print (undefined_function))This will outputs the var_dump result of the PispParserASTCallingNode class.
Pisp doesn't include any functions by default. This means, if you runs the examples above, you will get a NoFunctionException. You must define them by yourself.
However, there's a useful StdLib, just:
PispStdLibStandardLibrary::register($vm);Pisp only supports block comments starting with #| and ending with |#.
#| This is the function comment |#
(do_something (some_function) ["literal"]) #| ok too |#Pisp supports nested comments.
Example:
#| comment some code
(print "Hello World") #| This prints "Hello World" |#
|#You can also use a little trick to let it support it:
<?php
$pisp = new PispPisp;
$pisp->define("rem", function ($args, $vm) {
return;
});Then, you can just use:
(@rem "This is a comment")And this won't be executed.
Pisp now support many literals.
Literals are not surrounded by [ and ] now.
There are currently three types of literals: numeric, string and list.
Numeric is an integer or float.
Example:
(print 123 123.456 1e10 0x3f3f3f3f)Strings are surrounded by quotes. Supports muiltiple quotes.
n or other things are not fully supported at the moment.
Example:
(print "Hello World" 'Another 'test' Hello World')List is a collection of values.
It is surrounded with [ and ], each value is separated with a ,.
Example:
(print [1, 2, [3, 4]] ["Hello", 234, "World", 'you'])