add while, remove loop

This commit is contained in:
Pekka Laiho 2020-12-12 14:53:48 +07:00
parent a808ba8d4f
commit cf75c6eefd
4 changed files with 35 additions and 21 deletions

View File

@ -29,7 +29,7 @@ The core project does not have any dependencies to external [Composer](https://g
## Usage
Use the **run.php** file to invoke the interpreter from the command line. You can start the Repl with the -r switch:
Use the **run.php** file to invoke the interpreter from the command line. You can start the REPL with the -r switch:
```
$ php run.php -r
@ -260,7 +260,7 @@ The value of the whole expression is the value of the last expression.
### If
Conditional evaluation is accomplished with the `if` expression that is of the form `(if test consequent alternate)`. If *test* evaluates to truthy value, *consequent* is evaluated and returned. If *test* evaluates to falsy value, *alternate* is evaluated and returned:
Conditional evaluation is accomplished with the `if` expression which is of the form `(if test consequent alternate)`. If *test* evaluates to truthy value, *consequent* is evaluated and returned. If *test* evaluates to falsy value, *alternate* is evaluated and returned:
```text
> (if (< 1 2) "yes" "no")
@ -360,6 +360,17 @@ The arguments to `cond` and `case` can be also be given as vectors:
If no match is found, and `else` is not defined, `cond` and `case` return null.
### While
Looping is accomplished with the `while` expression which is of the form `(while test expr1 expr2 ...)`. The *test* is evaluated at the beginning of each iteration and if it returns truthy value, the remaining expressions are evaluated. The value of the whole expression is the value of the last evaluated sub-expression.
```text
> (let (i 5) (while (> i 0) (print i) (def i (dec i))))
543210
```
Although the above example illustrates how to use `while`, this type of code is discouraged. Generally it is recommended to use recursion instead of iteration in these type of scenarios. Usually it results in cleaner code as well. The `while` expression is better suited for something like the main loop of a program.
## Quoting
Use the `quote` special form to skip evaluation:
@ -459,7 +470,7 @@ Exceptions generated by PHP are catched as well. Their value will be a hash-map
"TypeError"
```
The Repl contains its own exception handler defined in PHP that will catch any exceptions thrown outside of `try-catch` form.
The REPL contains its own exception handler defined in PHP that will catch any exceptions thrown outside of `try-catch` form.
## Reflection
@ -517,6 +528,7 @@ quasiquote | yes | Quoting
quasiquote-expand | yes | Quoting
try | yes | Exceptions
undef | yes | Environments
while | yes | Control flow
## Built-in functions
@ -528,7 +540,6 @@ 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.
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.

View File

@ -47,12 +47,8 @@
(readline-load readlineFile)
;; Main loop: Read input from user, add it to readline, and parse it
(defn mainLoop ()
(while true
(let (inp (readline "[calc] "))
(do (readline-add inp)
(readline-add inp)
(readline-save readlineFile)
(print (str (parseInput inp) EOL))
true)))
;; Run it
(loop mainLoop)
(print (str "⇒ " (parseInput inp) EOL))))

View File

@ -465,6 +465,22 @@ class Evaller
}
return $env->unset($astData[1]->getName());
} elseif ($symbolName == 'while') {
if ($astLength < 3) {
throw new MadLispException("while at least 2 arguments");
}
$result = null;
$test = $this->eval($astData[1], $env, $depth + 1);
while ($test) {
for ($i = 2; $i < $astLength; $i++) {
$result = $this->eval($astData[$i], $env, $depth + 1);
}
$test = $this->eval($astData[1], $env, $depth + 1);
}
return $result;
}
}

View File

@ -68,15 +68,6 @@ class Core implements ILib
));
}
$env->set('loop', new CoreFunc('loop', 'Call the given function repeatedly in a loop until it returns false.', 1, -1,
function (Func $f, ...$args) {
do {
$result = $f->call($args);
} while ($result);
return $result;
}
));
if (!$this->safemode) {
$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) {