mirror of
https://github.com/peklaiho/madlisp.git
synced 2024-11-26 07:04:27 +00:00
improvements
This commit is contained in:
parent
766b162bc4
commit
56c80b9aaf
10
classes.php
10
classes.php
@ -49,11 +49,6 @@ class MLHash extends MLCollection
|
||||
|
||||
throw new MadLispException("hash does not contain key $key");
|
||||
}
|
||||
|
||||
public function set(string $key, $value): void
|
||||
{
|
||||
$this->data[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
class MLEnv extends MLHash
|
||||
@ -75,6 +70,11 @@ class MLEnv extends MLHash
|
||||
|
||||
throw new MadLispException("symbol $key not defined");
|
||||
}
|
||||
|
||||
public function set(string $key, $value): void
|
||||
{
|
||||
$this->data[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
class MLSymbol
|
||||
|
92
lib.php
92
lib.php
@ -6,7 +6,35 @@ function ml_get_env(): MLEnv
|
||||
{
|
||||
$env = new MLEnv();
|
||||
|
||||
// basic arithmetic
|
||||
// logic
|
||||
|
||||
$env->set('or', function (...$args) {
|
||||
// return first true
|
||||
for ($i = 0; $i < count($args) - 1; $i++) {
|
||||
if ($args[$i] == true) {
|
||||
return $args[$i];
|
||||
}
|
||||
}
|
||||
|
||||
// return last
|
||||
return $args[count($args) - 1];
|
||||
});
|
||||
|
||||
$env->set('and', function (...$args) {
|
||||
// return first false
|
||||
for ($i = 0; $i < count($args) - 1; $i++) {
|
||||
if ($args[$i] == false) {
|
||||
return $args[$i];
|
||||
}
|
||||
}
|
||||
|
||||
// return last
|
||||
return $args[count($args) - 1];
|
||||
});
|
||||
|
||||
$env->set('not', fn ($a) => !$a);
|
||||
|
||||
// arithmetic
|
||||
|
||||
$env->set('+', function (...$args) {
|
||||
return array_sum($args);
|
||||
@ -56,8 +84,68 @@ function ml_get_env(): MLEnv
|
||||
// types
|
||||
|
||||
$env->set('type?', function ($a) {
|
||||
return gettype($a);
|
||||
if ($a instanceof Closure) {
|
||||
return 'function';
|
||||
} elseif ($a instanceof MLList) {
|
||||
return 'list';
|
||||
} elseif ($a instanceof MLHash) {
|
||||
return 'hash';
|
||||
} elseif ($a instanceof MLSymbol) {
|
||||
return 'symbol';
|
||||
} elseif ($a === true || $a === false) {
|
||||
return 'bool';
|
||||
} elseif ($a === null) {
|
||||
return 'null';
|
||||
} elseif (is_int($a)) {
|
||||
return 'int';
|
||||
} elseif (is_float($a)) {
|
||||
return 'float';
|
||||
} else {
|
||||
return 'string';
|
||||
}
|
||||
});
|
||||
|
||||
$env->set('fn?', fn ($a) => $a instanceof Closure);
|
||||
$env->set('list?', fn ($a) => $a instanceof MLList);
|
||||
$env->set('hash?', fn ($a) => $a instanceof MLHash);
|
||||
$env->set('sym?', fn ($a) => $a instanceof MLSymbol);
|
||||
$env->set('bool?', fn ($a) => $a === true || $a === false);
|
||||
$env->set('true?', fn ($a) => $a == true); // not strict
|
||||
$env->set('false?', fn ($a) => $a == false); // not strict
|
||||
$env->set('null?', fn ($a) => $a === null);
|
||||
$env->set('int?', fn ($a) => is_int($a));
|
||||
$env->set('float?', fn ($a) => is_float($a));
|
||||
$env->set('str?', fn ($a) => is_string($a));
|
||||
|
||||
// collections
|
||||
|
||||
$env->set('list', function (...$args) {
|
||||
return new MLList($args);
|
||||
});
|
||||
|
||||
$env->set('hash', function (...$args) {
|
||||
if (count($args) % 2 == 1) {
|
||||
throw new MadLispException('uneven number of arguments for hash');
|
||||
}
|
||||
|
||||
$data = [];
|
||||
|
||||
for ($i = 0; $i < count($args) - 1; $i += 2) {
|
||||
$key = $args[$i];
|
||||
$val = $args[$i + 1];
|
||||
|
||||
if (!is_string($key)) {
|
||||
throw new MadLispException('invalid key for hash (not string)');
|
||||
}
|
||||
|
||||
$data[$key] = $val;
|
||||
}
|
||||
|
||||
return new MLHash($data);
|
||||
});
|
||||
|
||||
// for debugging!
|
||||
$env->set('eval', fn ($a) => ml_eval($a, $env));
|
||||
|
||||
return $env;
|
||||
}
|
||||
|
19
lisp.php
19
lisp.php
@ -149,14 +149,23 @@ function ml_eval($expr, MLEnv $env)
|
||||
// Evaluate list contents
|
||||
$results = array_map(fn ($a) => ml_eval($a, $env), $expr->getData());
|
||||
|
||||
if ($results[0] instanceof Closure) {
|
||||
$fn = $results[0];
|
||||
|
||||
if ($fn instanceof Closure) {
|
||||
// If the first item is a function, call it
|
||||
$args = array_slice($results, 1);
|
||||
return ($results[0])(...$args);
|
||||
return $fn(...$args);
|
||||
} else {
|
||||
// Otherwise return new list with evaluated contents
|
||||
return new MLList($results);
|
||||
}
|
||||
} elseif ($expr instanceof MLHash) {
|
||||
// Hash: return new hash with all items evaluated
|
||||
$items = [];
|
||||
foreach ($expr->getData() as $key => $val) {
|
||||
$items[$key] = ml_eval($val, $env);
|
||||
}
|
||||
return new MLHash($items);
|
||||
} elseif ($expr instanceof MLSymbol) {
|
||||
return $env->get($expr->name());
|
||||
}
|
||||
@ -170,6 +179,12 @@ function ml_print($a): string
|
||||
return '<function>';
|
||||
} elseif ($a instanceof MLList) {
|
||||
return '(' . implode(' ', array_map('ml_print', $a->getData())) . ')';
|
||||
} elseif ($a instanceof MLHash) {
|
||||
$items = [];
|
||||
foreach ($a->getData() as $key => $val) {
|
||||
$items[] = ml_print($key) . ':' . ml_print($val);
|
||||
}
|
||||
return '{' . implode(' ', $items) . '}';
|
||||
} elseif ($a instanceof MLSymbol) {
|
||||
return $a->name();
|
||||
} elseif ($a === true) {
|
||||
|
Loading…
Reference in New Issue
Block a user