change case to cond

This commit is contained in:
Pekka Laiho 2020-12-10 21:46:03 +07:00
parent 9d2de20c1e
commit 435c9e6bd3
2 changed files with 30 additions and 14 deletions

View File

@ -279,8 +279,8 @@ This allows for some fun tricks. For example, we can retrieve the body of a func
Name | Safe-mode | Example | Example result | Description Name | Safe-mode | Example | Example result | Description
----- | --------- | ------- | -------------- | ----------- ----- | --------- | ------- | -------------- | -----------
and | yes | `(and 1 0 2)` | `0` | Return the first value that evaluates to false, or the last value. and | yes | `(and 1 0 2)` | `0` | Return the first value that evaluates to false, or the last value.
case | yes | `(case (= 1 0) 0 (= 1 1) 1)` | `1` | Treat odd arguments as tests and even arguments as values. Evaluate and return the value after the first test that evaluates to true. cond | yes | `(cond [(= 0 1) 0] [(= 1 1) (print "1") 1])` | `11` | Treat first item of each argument as test. If test evaluates to true, evaluate the following expressions and return the value of the last.
| yes | `(case (= 1 0) 0 "no match")` | `"no match"` | You can also give optional last argument to case which is returned if none of the tests evaluated to true. | yes | `(cond [(= 0 1) 0] [(= 1 2) 1] [else 3])` | `3` | The symbol `else` evaluates to true. It can be used as the last condition in case no previous test evaluates to true.
def | yes | `(def addOne (fn (a) (+ a 1)))` | `<function>` | Define a value in the current environment. def | yes | `(def addOne (fn (a) (+ a 1)))` | `<function>` | Define a value in the current environment.
do | yes | `(do (print 1) 2)` | `12` | Evaluate multiple expressions and return the value of the last. do | yes | `(do (print 1) 2)` | `12` | Evaluate multiple expressions and return the value of the last.
env | yes | `(env +)` | `<function>` | Return a definition from the current environment represented by argument. Without arguments return the current environment as a hash-map. env | yes | `(env +)` | `<function>` | Return a definition from the current environment represented by argument. Without arguments return the current environment as a hash-map.

View File

@ -93,26 +93,42 @@ class Evaller
$ast = $astData[$astLength - 1]; $ast = $astData[$astLength - 1];
continue; // tco continue; // tco
} elseif ($symbolName == 'case') { } elseif ($symbolName == 'cond') {
if ($astLength < 2) { if ($astLength < 2) {
throw new MadLispException("case requires at least 1 argument"); throw new MadLispException("cond requires at least 1 argument");
}
for ($i = 1; $i < $astLength; $i++) {
if (!($astData[$i] instanceof Seq)) {
throw new MadLispException("argument to cond is not seq");
}
$condData = $astData[$i]->getData();
if (count($condData) < 2) {
throw new MadLispException("clause for cond requires at least 2 arguments");
}
if ($condData[0] instanceof Symbol && $condData[0]->getName() == 'else') {
$test = true;
} else {
$test = $this->eval($condData[0], $env, $depth + 1);
} }
for ($i = 1; $i < $astLength - 1; $i += 2) {
$test = $this->eval($astData[$i], $env, $depth + 1);
if ($test == true) { if ($test == true) {
$ast = $astData[$i + 1]; // Evaluate interval expressions
for ($a = 1; $a < count($condData) - 1; $a++) {
$this->eval($condData[$a], $env, $depth + 1);
}
// Evaluate last expression
$ast = $condData[count($condData) - 1];
continue 2; // tco continue 2; // tco
} }
} }
// Last value, no test // No matches
if ($astLength % 2 == 0) {
$ast = $astData[$astLength - 1];
continue; // tco
} else {
return null; return null;
}
} elseif ($symbolName == 'def') { } elseif ($symbolName == 'def') {
if ($astLength != 3) { if ($astLength != 3) {
throw new MadLispException("def requires exactly 2 arguments"); throw new MadLispException("def requires exactly 2 arguments");