2020-01-05 18:05:49 +03:00
|
|
|
include "reader";
|
|
|
|
include "printer";
|
|
|
|
include "utils";
|
|
|
|
|
|
|
|
def READ:
|
2024-09-29 17:53:23 +03:00
|
|
|
read_form;
|
2020-01-05 18:05:49 +03:00
|
|
|
|
2020-01-14 00:50:01 +03:00
|
|
|
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)");
|
|
|
|
|
2020-01-05 18:05:49 +03:00
|
|
|
def EVAL(env):
|
2024-09-29 17:53:23 +03:00
|
|
|
# ("EVAL: \(pr_str(env))" | _display | empty),
|
|
|
|
(select(.kind == "list") |
|
|
|
|
.value | select(length != 0) as $value |
|
|
|
|
map(EVAL(env)) | .[1:] as $args | first | interpret($args; env)
|
|
|
|
) //
|
|
|
|
(
|
|
|
|
select(.kind == "vector") |
|
|
|
|
{
|
|
|
|
kind: "vector",
|
|
|
|
value: .value|map(EVAL(env))
|
|
|
|
}
|
|
|
|
) //
|
|
|
|
(
|
|
|
|
select(.kind == "hashmap") |
|
|
|
|
{
|
|
|
|
kind: "hashmap",
|
|
|
|
value: .value|map_values(.value |= EVAL(env))
|
|
|
|
}
|
|
|
|
) //
|
|
|
|
(
|
|
|
|
select(.kind == "symbol") |
|
|
|
|
env[.value] // jqmal_error("'\(.)' not found")
|
|
|
|
) //
|
|
|
|
.;
|
2020-01-05 18:05:49 +03:00
|
|
|
|
|
|
|
def PRINT:
|
|
|
|
pr_str;
|
|
|
|
|
2024-09-29 17:53:23 +03:00
|
|
|
def repl:
|
|
|
|
# Infinite generator, interrupted by an exception or ./run.
|
|
|
|
. as $env | "user> " | __readline |
|
|
|
|
try (
|
|
|
|
READ | EVAL($env) |
|
|
|
|
PRINT, ($env | repl)
|
|
|
|
) catch if is_jqmal_error then
|
|
|
|
., ($env | repl)
|
|
|
|
else
|
|
|
|
halt_error
|
|
|
|
end;
|
2020-01-05 18:05:49 +03:00
|
|
|
|
2024-09-29 17:53:23 +03:00
|
|
|
# The main program starts here.
|
2020-01-05 18:05:49 +03:00
|
|
|
{
|
2024-09-29 17:53:23 +03:00
|
|
|
"+": {
|
|
|
|
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"
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
|
repl
|