improve exceptions, add type for user exceptions

This commit is contained in:
Pekka Laiho 2020-12-09 08:09:12 +07:00
parent e455fd76eb
commit 6077dc135c
5 changed files with 39 additions and 14 deletions

View File

@ -287,13 +287,13 @@ Name | Safe-mode | Example | Example result | Description
debug | no | `(debug)` | `true` | Toggle debug output.
doc | yes | `(doc +)` | `"Return the sum of all arguments."` | Show the documentation string for a function.
| yes | `(doc myfn "Documentation string.")` | `"Documentation string."` | Set the documentation string for a function.
error | yes | `(error "invalid value")` | `error: invalid value` | Throw an exception with message as argument.
exit | no | `(exit 1)` | | Terminate the script with given exit code using [exit](https://www.php.net/manual/en/function.exit.php).
loop | yes | `(loop (fn (a) (do (print a) (coinflip))) "hello ")` | `hello hello hello false` | Call the given function repeatedly in a loop until it returns false.
print | no | `(print "hello world")` | `hello world` | Print expression on the screen. Give optional second argument as `true` to show strings in readable format. Print returns null (shown in REPL).
pstr | yes | `(pstr {"a":"b"})` | `"{\"a\":\"b\"}"` | Print expression to string.
read | yes | `(read "(+ 1 2 3)")` | `(+ 1 2 3)` | Read a string as code and return the expression.
sleep | no | `(sleep 2000)` | `null` | Sleep for the given period given in milliseconds using [usleep](https://www.php.net/manual/en/function.usleep).
throw | yes | `(throw "invalid value")` | `error: "invalid value"` | Throw an exception. The given value is passed to catch.
timer | no | `(timer (fn (d) (sleep d)) 200)` | `0.20010209` | Measure the execution time of a function and return it in seconds.
### Collection functions
@ -431,7 +431,7 @@ rand | `(rand 5 10)` | `8` | Return a random integer between given min and max
Name | Example | Example result | Description
------------- | ------- | -------------- | -----------
re-match | `(re-match "/^[a-z]{4}[0-9]{4}$/" "test1234")` | `true` | Match subject to regular expression using [preg_match](https://www.php.net/manual/en/function.preg-match.php).
re-match | `(re-match "/[a-z]{5}/" "one three five" true)` | `"three"` | Give true as third argument to return the matched text.
| `(re-match "/[a-z]{5}/" "one three five" true)` | `"three"` | Give true as third argument to return the matched text.
re-match-all | `(re-match-all "/[A-Z][a-z]{2}[0-9]/" "One1 Two2 Three3")` | `["One1" "Two2"]` | Find multiple matches to regular expression using [preg_match_all](https://www.php.net/manual/en/function.preg-match-all.php).
re-replace | `(re-replace "/year ([0-9]{4}) month ([0-9]{2})/" "$1-$2-01" "year 2020 month 10")` | `"2020-10-01"` | Perform search and replace with regular expression using [preg_replace](https://www.php.net/manual/en/function.preg-replace.php).
re-split | `(re-split "/\\s+/" "aa bb cc ")` | `["aa" "bb" "cc"]` | Split the subject by regular expression using [preg_split](https://www.php.net/manual/en/function.preg-split.php). The flag `PREG_SPLIT_NO_EMPTY` is enabled.

View File

@ -18,6 +18,9 @@ function ml_repl($lisp)
try {
$lisp->rep($input, true);
} catch (MadLisp\MadLispUserException $ex) {
print('error: ');
$lisp->print($ex->getValue(), true);
} catch (MadLisp\MadLispException $ex) {
print('error: ' . $ex->getMessage());
} catch (TypeError $ex) {

View File

@ -6,7 +6,7 @@ use MadLisp\CoreFunc;
use MadLisp\Env;
use MadLisp\Evaller;
use MadLisp\Func;
use MadLisp\MadLispException;
use MadLisp\MadLispUserException;
use MadLisp\MList;
use MadLisp\Printer;
use MadLisp\Reader;
@ -60,14 +60,6 @@ class Core implements ILib
}
));
// This is allowed in safe-mode, because the evaluation should be wrapped in a try-catch in embedded use.
$env->set('error', new CoreFunc('error', 'Throw an exception using argument (string) as message.', 1, 1,
function (string $error) {
// We should probably use another exception type to distinguish user-thrown errors from built-in errors.
throw new MadLispException($error);
}
));
if (!$this->safemode) {
$env->set('exit', new CoreFunc('exit', 'Terminate the script with given exit code.', 0, 1,
function (int $status = 0) {
@ -113,6 +105,12 @@ class Core implements ILib
));
}
$env->set('throw', new CoreFunc('throw', 'Throw an exception. Takes one argument which is passed to catch.', 1, 1,
function ($error) {
throw new MadLispUserException($error);
}
));
if (!$this->safemode) {
$env->set('timer', new CoreFunc('timer', 'Measure the execution time of a function and return it in seconds.', 1, -1,
function (Func $f, ...$args) {

View File

@ -18,6 +18,11 @@ class Lisp
$this->env = $env;
}
public function print($value, bool $printReadable): void
{
$this->printer->print($value, $printReadable);
}
public function readEval(string $input)
{
$tokens = $this->tokenizer->tokenize($input);
@ -30,9 +35,7 @@ class Lisp
// read, eval, print
public function rep(string $input, bool $printReadable): void
{
$result = $this->readEval($input);
$this->printer->print($result, $printReadable);
$this->print($this->readEval($input), $printReadable);
}
public function setEnv(Env $env): void

View File

@ -0,0 +1,21 @@
<?php
namespace MadLisp;
class MadLispUserException extends \Exception
{
protected $value;
public function __construct($value)
{
if (is_string($value)) {
parent::__construct($value);
}
$this->value = $value;
}
public function getValue()
{
return $this->value;
}
}