Created
September 9, 2015 23:03
-
-
Save enko/aea9b5739d61b100e6cb to your computer and use it in GitHub Desktop.
lisp in php, based on http://danthedev.com/2015/09/09/lisp-in-your-language/
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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