Permalink
Browse files

Merge branch 'master' of github.com:dahlia/lisphp

  • Loading branch information...
2 parents 398b66b + ac133f2 commit 41e9623b3f509af47ecf03f1c17235bc9185ec1f @dahlia dahlia committed Dec 1, 2009
View
@@ -45,6 +45,7 @@ static function sandbox() {
$scope['*'] = new Lisphp_Runtime_Arithmetic_Multiplication;
$scope['/'] = new Lisphp_Runtime_Arithmetic_Division;
$scope['%'] = $scope['mod'] =new Lisphp_Runtime_Arithmetic_Modulus;
+ $scope['string'] = new Lisphp_Runtime_PHPFunction('strval');
$scope['.'] = $scope['concat'] =new Lisphp_Runtime_String_Concat;
$scope['string-join'] = new Lisphp_Runtime_String_StringJoin;
$scope['substring'] = new Lisphp_Runtime_PHPFunction('substr');
View
@@ -5,7 +5,9 @@
final class Lisphp_Runtime_Eval implements Lisphp_Applicable {
function apply(Lisphp_Scope $scope, Lisphp_List $args) {
- return $args[0]->evaluate(isset($args[1]) ? $args[1] : $scope);
+ $form = $args[0]->evaluate($scope);
+ return $form->evaluate(isset($args[1]) ? $args[1]->evaluate($scope)
+ : $scope);
}
}
@@ -13,8 +13,8 @@ function __construct(Lisphp_Scope $scope, Lisphp_List $body) {
function apply(Lisphp_Scope $scope, Lisphp_List $arguments) {
$call = new Lisphp_Scope($this->scope);
- $call['#scope'] = $scope;
- $call['#arguments'] = $arguments;
+ $call->let('#scope', $scope);
+ $call->let('#arguments', $arguments);
foreach ($this->body as $form) {
$retval = $form->evaluate($call);
}
@@ -66,6 +66,8 @@ function testSandbox($scope = null) {
$this->assertType('Lisphp_Runtime_Arithmetic_Division', $scope['/']);
$this->assertType('Lisphp_Runtime_Arithmetic_Modulus', $scope['%']);
$this->assertType('Lisphp_Runtime_Arithmetic_Modulus', $scope['mod']);
+ $this->assertType('Lisphp_Runtime_PHPFunction', $scope['string']);
+ $this->assertEquals('strval', $scope['string']->callback);
$this->assertType('Lisphp_Runtime_String_Concat', $scope['.']);
$this->assertType('Lisphp_Runtime_String_Concat', $scope['concat']);
$this->assertType('Lisphp_Runtime_String_StringJoin',
@@ -23,12 +23,14 @@ static function b() {
class Lisphp_Test_RuntimeTest extends PHPUnit_Framework_TestCase {
function testEval() {
$eval = new Lisphp_Runtime_Eval;
- $form = Lisphp_Parser::parseForm('(+ 1 2 [- 4 3])', $_);
+ $form = Lisphp_Parser::parseForm(':(+ 1 2 [- 4 3])', $_);
$scope = Lisphp_Environment::sandbox();
$args = new Lisphp_List(array($form));
$this->assertEquals(4, $eval->apply($scope, $args));
- $args = new Lisphp_List(array($form, $scope));
- $this->assertEquals(4, $eval->apply(new Lisphp_Scope, $args));
+ $args = new Lisphp_List(array($form, Lisphp_Symbol::get('scope')));
+ $names = new Lisphp_Scope;
+ $names['scope'] = $scope;
+ $this->assertEquals(4, $eval->apply($names, $args));
}
function testDefine() {
View
@@ -29,13 +29,42 @@ If there is no filename in arguments to `lis.php`, it enters REPL mode.
Similarly you can specify `-s` to restrict it sandbox.
- $ php -s lis.php
+ $ php lis.php -s
- `>>>` is a prompt.
- `==>` is a returned value of evaluation.
- `!!!` is a thrown exception.
+Simple tutorial
+---------------
+
+ >>> (+ 12 34)
+ ==> 46
+ >>> (- 1 2)
+ ==> -1
+ >>> (* 5 6)
+ ==> 30
+ >>> (/ 30 5)
+ ==> 6
+ >>> (/ 30 4)
+ ==> 7.5
+ >>> (% 30 4)
+ ==> 2
+ >>> (. "hello" "world")
+ ==> 'helloworld'
+ >>> (define pi 3.14)
+ ==> 3.14
+ >>> pi
+ ==> 3.14
+ >>> (float? pi)
+ ==> true
+ >>> (string? "abc")
+ ==> true
+ >>> (* pi 10 10)
+ ==> 314
+
+
Embed in your app
-----------------
@@ -127,6 +156,39 @@ Function body can contain one or more forms. All forms are evaluated
sequentially then the evaluated value of last form is returned.
+Define custom macros
+--------------------
+
+Macros do not evaluate arguments forms. There are some built-in macros in
+Lisphp e.g. `eval`, `define`, `lambda`, `let`, `if`, `and`, `or`. For example,
+`define` takes the name to define as its first argument, but the name is not
+evaluated. In the same way, `if` takes three forms as arguments, but always
+only two arguments are evaluated and the other is ignored. It is impossible
+to implement `if` as function, because all arguments are evaluated. In a case
+like this, `macro` helps you.
+
+ (define if*
+ {macro [let {(cond (eval (car #arguments)
+ #scope))}
+ (eval (at #arguments (or (and cond 1) 2))
+ #scope)]})
+
+ (define quote*
+ [macro (car #arguments)])
+
+
+Quote
+-----
+
+There are two ways to quote a form in Lisphp. First is the macro `quote`, and
+the other is quote syntax `:`. Single quotations is used as string literal.
+
+ (quote abc)
+ :abc
+ (quote (+ a b))
+ :(+ a b)
+
+
About lists and `nil`
---------------------
View
11 lis.php
@@ -3,6 +3,8 @@
define('LISPHP_COLUMN', 80);
define('LISPHP_REPL_PROMPT', '>>> ');
+define('LISPHP_REPL_VALUE_PROMPT', '==> ');
+define('LISPHP_REPL_EXCEPTION_PROMPT', '!!! ');
function Lisphp_usage() {
static $commands = array(
@@ -87,25 +89,30 @@ class Lisphp_EnterREPL extends Exception {}
'));
$readline = 'readline';
$add_history = 'readline_add_history';
+ $exit = false;
} else {
$readline = create_function('$prompt', '
echo $prompt;
return fread(STDIN, 8192);
');
$add_history = create_function('', '');
+ $exit = '';
}
while (true) {
$code = $readline(LISPHP_REPL_PROMPT);
- if ($code == '') die("\n");
+ if ($code === $exit) die("\n");
else if (trim($code) == '') continue;
try {
$form = Lisphp_Parser::parseForm($code, $_);
+ echo LISPHP_REPL_VALUE_PROMPT;
var_export($form->evaluate($scope));
echo "\n";
} catch (Lisphp_ParsingException $e) {
Lisphp_printParsingError($e);
} catch (Exception $e) {
- echo $e->getMessage();
+ echo LISPHP_REPL_EXCEPTION_PROMPT, $e->getMessage(), "\n",
+ preg_replace('/^|\n/', '\\0 ', $e->getTraceAsString()),
+ "\n";
}
$add_history($code);
}

0 comments on commit 41e9623

Please sign in to comment.