1
1
mirror of https://github.com/kanaka/mal.git synced 2024-08-17 17:50:24 +03:00
mal/impls/jq/step2_eval.jq
Joel Martin 8a19f60386 Move implementations into impls/ dir
- Reorder README to have implementation list after "learning tool"
  bullet.

- This also moves tests/ and libs/ into impls. It would be preferrable
  to have these directories at the top level.  However, this causes
  difficulties with the wasm implementations which need pre-open
  directories and have trouble with paths starting with "../../". So
  in lieu of that, symlink those directories to the top-level.

- Move the run_argv_test.sh script into the tests directory for
  general hygiene.
2020-02-10 23:50:16 -06:00

121 lines
2.9 KiB
Plaintext

include "reader";
include "printer";
include "utils";
def read_line:
. as $in
| label $top
| _readline;
def READ:
read_str | read_form | .value;
def lookup(env):
env[.] //
jqmal_error("'\(.)' not found");
def arg_check(args):
if .inputs != (args|length) then
jqmal_error("Invalid number of arguments (expected \(.inputs), got \(args|length))")
else
.
end;
def interpret(arguments; env):
(select(.kind == "fn") |
arg_check(arguments) |
(
select(.function == "number_add") |
arguments | map(.value) | .[0] + .[1] | wrap("number")
) // (
select(.function == "number_sub") |
arguments | map(.value) | .[0] - .[1] | wrap("number")
) // (
select(.function == "number_mul") |
arguments | map(.value) | .[0] * .[1] | wrap("number")
) // (
select(.function == "number_div") |
arguments | map(.value) | .[0] / .[1] | wrap("number")
)
) //
jqmal_error("Unsupported native function kind \(.kind)");
def EVAL(env):
def eval_ast:
(select(.kind == "symbol") | .value | lookup(env)) //
(select(.kind == "list") | {
kind: "list",
value: .value | map(EVAL(env))
}) // .;
(select(.kind == "list") |
if .value | length == 0 then
.
else
eval_ast|.value as $evald | $evald | first | interpret($evald[1:]; env)
end
) //
(select(.kind == "vector") |
{
kind: "vector",
value: .value|map(EVAL(env))
}
) //
(select(.kind == "hashmap") |
{
kind: "hashmap",
value: .value|map_values(.value |= EVAL(env))
}
) // eval_ast;
def PRINT:
pr_str;
def rep(env):
READ | EVAL(env) |
if . != null then
PRINT
else
null
end;
def repl_(env):
("user> " | _print) |
(read_line | rep(env));
# we don't have no indirect functions, so we'll have to interpret the old way
def replEnv:
{
"+": {
kind: "fn", # native function
inputs: 2,
function: "number_add"
},
"-": {
kind: "fn", # native function
inputs: 2,
function: "number_sub"
},
"*": {
kind: "fn", # native function
inputs: 2,
function: "number_mul"
},
"/": {
kind: "fn", # native function
inputs: 2,
function: "number_div"
},
};
def repl(env):
{continue: true} | while(
.continue;
try {value: repl_(env), continue: true}
catch
if is_jqmal_error then
{value: "Error: \(.)", continue: true}
else
{value: ., continue: false}
end) | if .value then .value|_display else empty end;
repl(replEnv)