handle special characters correctly in printing

This commit is contained in:
Pekka Laiho 2020-06-16 20:38:46 +07:00
parent ad70c6dbd0
commit 427327003d
4 changed files with 24 additions and 16 deletions

View File

@ -135,7 +135,7 @@ Name | Example | Example result | Description
----- | ------- | -------------- | -----------
doc | `(doc +)` | `"Return the sum of all arguments."` | Show description of a built-in function.
read | `(read "(+ 1 2 3)")` | `(+ 1 2 3)` | Read a string as code and return the expression.
print | `(print "hello world")` | `"hello world"null` | Print expression on the screen. Print returns null (which is shown due to the extra print in repl).
print | `(print "hello world")` | `"hello world"null` | Print expression on the screen. Print returns null (which is shown due to the extra print in repl). Give optional second argument as `true` to show strings in readable format.
error | `(error "invalid value")` | `error: invalid value` | Throw an exception with message as argument.
### Collection functions

View File

@ -17,7 +17,7 @@ function ml_repl($lisp, $env)
$input = readline('> ');
try {
$lisp->rep($input, $env);
$lisp->rep($input, $env, true);
if ($input) {
readline_add_history($input);
@ -42,10 +42,10 @@ function ml_run()
list($lisp, $env) = ml_get_lisp($debug);
if (array_key_exists('e', $args)) {
$lisp->rep($args['e'], $env);
$lisp->rep($args['e'], $env, false);
} elseif (array_key_exists('f', $args)) {
$input = "(load \"{$args['f']}\")";
$lisp->rep($input, $env);
$lisp->rep($input, $env, false);
} elseif (array_key_exists('r', $args)) {
ml_repl($lisp, $env);
} else {

View File

@ -16,7 +16,7 @@ class Lisp
$this->printer = $printer;
}
public function rep(string $input, Env $env): void
public function rep(string $input, Env $env, bool $printReadable): void
{
$tokens = $this->tokenizer->tokenize($input);
@ -24,7 +24,7 @@ class Lisp
$result = $this->eval->eval($expr, $env);
$this->printer->print($result);
$this->printer->print($result, $printReadable);
}
public function register(Env $env): void
@ -43,9 +43,9 @@ class Lisp
fn (string $a) => $this->reader->read($this->tokenizer->tokenize($a))
));
$env->set('print', new CoreFunc('print', 'Print argument.', 1, 1,
function ($a) {
$this->printer->print($a);
$env->set('print', new CoreFunc('print', 'Print argument. Give second argument as true to show strings in readable format.', 1, 2,
function ($a, bool $readable = false) {
$this->printer->print($a, $readable);
return null;
}
));

View File

@ -3,21 +3,21 @@ namespace MadLisp;
class Printer
{
public function print($ast): void
public function print($ast, bool $readable = true): void
{
print($this->doPrint($ast));
print($this->doPrint($ast, $readable));
}
private function doPrint($a): string
private function doPrint($a, bool $readable): string
{
if ($a instanceof Func) {
return '<function>';
} elseif ($a instanceof MList) {
return '(' . implode(' ', array_map(fn ($b) => $this->doPrint($b), $a->getData())) . ')';
return '(' . implode(' ', array_map(fn ($b) => $this->doPrint($b, $readable), $a->getData())) . ')';
} elseif ($a instanceof Vector) {
return '[' . implode(' ', array_map(fn ($b) => $this->doPrint($b), $a->getData())) . ']';
return '[' . implode(' ', array_map(fn ($b) => $this->doPrint($b, $readable), $a->getData())) . ']';
} elseif ($a instanceof Hash) {
return '{' . implode(' ', array_map(fn ($key, $val) => $this->doPrint($key) . ':' . $this->doPrint($val),
return '{' . implode(' ', array_map(fn ($key, $val) => $this->doPrint($key, $readable) . ':' . $this->doPrint($val, $readable),
array_keys($a->getData()), array_values($a->getData()))) . '}';
} elseif ($a instanceof Symbol) {
return $a->getName();
@ -28,7 +28,15 @@ class Printer
} elseif ($a === null) {
return 'null';
} elseif (is_string($a)) {
return '"' . $a . '"';
if ($readable) {
$a = str_replace("\\", "\\\\", $a);
$a = str_replace("\n", "\\n", $a);
$a = str_replace("\r", "\\r", $a);
$a = str_replace("\"", "\\\"", $a);
return '"' . $a . '"';
} else {
return $a;
}
} else {
return $a;
}