mirror of
https://github.com/peklaiho/madlisp.git
synced 2024-11-22 13:24:46 +00:00
add while, remove loop
This commit is contained in:
parent
a808ba8d4f
commit
cf75c6eefd
19
README.md
19
README.md
@ -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.
|
||||
|
10
mad/calc.mad
10
mad/calc.mad
@ -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))))
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user