Last active
August 29, 2015 14:01
-
-
Save igorw/8a170a98b4c737317b35 to your computer and use it in GitHub Desktop.
Playing with concatenative programming.
This file contains 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
<?hh | |
// concatenative programming | |
// based on this paper: | |
// http://mitarbeiter.hs-heilbronn.de/~herzberg/Publications/ICSOFT.2009.pdf | |
namespace igorw\concat; | |
class OpenQuotation { | |
var $words; | |
function __construct($words = []) { | |
$this->words = $words; | |
} | |
function push($word) { | |
$words = $this->words; | |
array_push($words, $word); | |
return new OpenQuotation($words); | |
} | |
function close() { | |
return new Quotation($this->words); | |
} | |
} | |
class Quotation { | |
var $words; | |
function __construct($words = []) { | |
$this->words = $words; | |
} | |
function unquote() { | |
return $this->words; | |
} | |
} | |
function word($word, array $stack) { | |
$top = end($stack); | |
if ($top instanceof OpenQuotation && !in_array($word, ['[', ']'])) { | |
$s = quote($word, $stack); | |
return $s; | |
} | |
if (is_numeric($word)) { | |
return number($word, $stack); | |
} | |
$fns = [ | |
'dup' => $stack ==> { | |
$val = array_pop($stack); | |
array_push($stack, $val); | |
array_push($stack, $val); | |
return $stack; | |
}, | |
'[' => $stack ==> { | |
array_push($stack, new OpenQuotation()); | |
return $stack; | |
}, | |
']' => $stack ==> { | |
$quot = array_pop($stack); | |
array_push($stack, $quot->close()); | |
return $stack; | |
}, | |
'>' => $stack ==> { | |
$b = array_pop($stack); | |
$a = array_pop($stack); | |
array_push($stack, $a > $b); | |
return $stack; | |
}, | |
'call' => $stack ==> { | |
$quot = array_pop($stack); | |
return call($quot, $stack); | |
}, | |
'if' => $stack ==> { | |
$quot_false = array_pop($stack); | |
$quot_true = array_pop($stack); | |
$val = array_pop($stack); | |
$quot = $val ? $quot_true : $quot_false; | |
return call($quot, $stack); | |
}, | |
'+' => $stack ==> { | |
$b = array_pop($stack); | |
$a = array_pop($stack); | |
array_push($stack, $a + $b); | |
return $stack; | |
}, | |
]; | |
if (isset($fns[$word])) { | |
return $fns[$word]($stack); | |
} | |
throw new \InvalidArgumentException("Unknown word $word"); | |
} | |
function quote($word, array $stack) { | |
$quot = array_pop($stack); | |
array_push($stack, $quot->push($word)); | |
return $stack; | |
} | |
function number($word, array $stack) { | |
array_push($stack, (int) $word); | |
return $stack; | |
} | |
function call(Quotation $quot, array $stack) { | |
$words = $quot->unquote(); | |
return evaluate($words, $stack); | |
} | |
function evaluate(array $words, array $stack = []) { | |
foreach ($words as $word) { | |
var_dump($stack); | |
$stack = word($word, $stack); | |
} | |
return $stack; | |
} | |
$code = '6 5 dup [ 3 > ] call [ + ] [ * ] if'; | |
$words = explode(' ', $code); | |
var_dump(evaluate($words)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment