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. 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. 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. error | `(error "invalid value")` | `error: invalid value` | Throw an exception with message as argument.
### Collection functions ### Collection functions

View File

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

View File

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

View File

@ -3,21 +3,21 @@ namespace MadLisp;
class Printer 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) { if ($a instanceof Func) {
return '<function>'; return '<function>';
} elseif ($a instanceof MList) { } 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) { } 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) { } 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()))) . '}'; array_keys($a->getData()), array_values($a->getData()))) . '}';
} elseif ($a instanceof Symbol) { } elseif ($a instanceof Symbol) {
return $a->getName(); return $a->getName();
@ -28,7 +28,15 @@ class Printer
} elseif ($a === null) { } elseif ($a === null) {
return 'null'; return 'null';
} elseif (is_string($a)) { } 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 { } else {
return $a; return $a;
} }