Skip to content

Instantly share code, notes, and snippets.

@enko
Created September 9, 2015 23:03
Show Gist options
  • Save enko/aea9b5739d61b100e6cb to your computer and use it in GitHub Desktop.
Save enko/aea9b5739d61b100e6cb to your computer and use it in GitHub Desktop.
<?php
class SpecialForm {
private $function = null;
private $callback = null;
public function __construct($function,$callback) {
$this->function = $function;
$this->callback = $callback;
}
public function __invoke() {
$args = func_get_args();
return call_user_func_array($this->callback,$args);
}
}
function lispEval($rawExpression,$localScope = []) {
if (is_null($rawExpression)) {
return;
}
if (is_scalar($rawExpression)) {
return $rawExpression;
}
static $globalScope = [];
$scope = array_merge($globalScope,$localScope);
$natives = [
'+' => function($a,$b) use($localScope) {
return lispEval($a,$localScope)+lispEval($b,$localScope);
},
'-' => function($a,$b) {
return $a+$b;
},
'*' => function($a,$b) {
return $a*$b;
},
'/' => function($a,$b) {
return $a/$b;
},
'=' => function($a,$b) {
return $a === $b;
},
'>' => function($a,$b) {
return $a > $b;
},
'<' => function($a,$b) {
return $a < $b;
},
'.' => function($a,$b) {
return $a . $b;
},
'def' => function($name,$value) use(&$globalScope) {
$globalScope[$name] = $value;
},
'do' => new SpecialForm('do',function() use ($localScope){
$args = func_get_args();
$retval = array_reduce($args,function($retval,$arg) use ($localScope) {
return lispEval($arg,$localScope);
});
return $retval;
}),
'if' => new SpecialForm('if',function($condition,$success,$failure) use ($localScope){
$passed = lispEval($condition,$localScope);
if ($passed && (!is_null($success))) {
return lispEval($success,$localScope);
} else if((!$passed) && (!is_null($failure))) {
return lispEval($failure,$localScope);
}
}),
'fn' => new SpecialForm('fn',function($defArgs,$code) use ($localScope){
$func = function() use($defArgs,$code,$localScope){
$args = [];
$_args = func_get_args();
foreach($defArgs as $index => $defArg) {
$args[$defArg] = lispEval($_args[$index],$localScope);
}
var_dump($args);
return lispEval($code,array_merge($args,$localScope));
};
return $func;
}),
'defn' => new SpecialForm('defn',function($name,$defArgs,$code) use($localScope){
$code = ['def',$name,['fn',$defArgs,$code]];
return lispEval($code,$localScope);
}),
];
$expression = array_map(function($symbol) use($scope){
if ((!is_array($symbol)) && (array_key_exists($symbol,$scope))) {
return $scope[$symbol];
} else {
return $symbol;
}
},$rawExpression);
if ((is_array($expression)) && (count($expression) > 0)) {
if (is_array($expression[0])) {
$fn = lispEval($expression[0]);
} elseif (array_key_exists($expression[0],$natives)) {
$fn = $natives[$expression[0]];
} else {
$fn = $expression[0];
}
$args = array_map(function($arg) use($fn,$localScope){
if (is_array($arg) && (!is_object($fn))) {
return lispEval($arg,$localScope);
} else {
return $arg;
}
},array_slice($expression,1));
return call_user_func_array($fn,$args);
} else {
return $expression;
}
}
$code = ["defn", "fib", ["n"],
["if", [">", "n", 1],
["+",
["fib", ["-", "n", 1]],
["fib", ["-", "n", 2]]],
1]];
lispEval($code);
$code = ["sprintf", ["fib", 8]];
var_dump(lispEval($code));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment