mirror of
https://github.com/kanaka/mal.git
synced 2024-09-11 13:55:55 +03:00
add step9 and fix "symbol not found" exception format
This commit is contained in:
parent
e9cb5f03ae
commit
4db6de1230
192
jq/core.jq
192
jq/core.jq
@ -107,7 +107,7 @@ def core_identify:
|
||||
"swap!": { # defined in interp
|
||||
kind: "fn",
|
||||
function: "swap!",
|
||||
inputs: -1
|
||||
inputs: -3
|
||||
},
|
||||
"cons": {
|
||||
kind: "fn",
|
||||
@ -133,6 +133,111 @@ def core_identify:
|
||||
kind: "fn",
|
||||
function: "rest",
|
||||
inputs: 1
|
||||
},
|
||||
"throw": {
|
||||
kind: "fn",
|
||||
function: "throw",
|
||||
inputs: 1
|
||||
},
|
||||
"apply": { # defined in interp
|
||||
kind: "fn",
|
||||
function: "apply",
|
||||
inputs: -3
|
||||
},
|
||||
"map": { # defined in interp
|
||||
kind: "fn",
|
||||
function: "map",
|
||||
inputs: 2
|
||||
},
|
||||
"nil?": {
|
||||
kind: "fn",
|
||||
function: "nil?",
|
||||
inputs: 1
|
||||
},
|
||||
"true?": {
|
||||
kind: "fn",
|
||||
function: "true?",
|
||||
inputs: 1
|
||||
},
|
||||
"false?": {
|
||||
kind: "fn",
|
||||
function: "false?",
|
||||
inputs: 1
|
||||
},
|
||||
"symbol": {
|
||||
kind: "fn",
|
||||
function: "symbol",
|
||||
inputs: 1
|
||||
},
|
||||
"symbol?": {
|
||||
kind: "fn",
|
||||
function: "symbol?",
|
||||
inputs: 1
|
||||
},
|
||||
"keyword": {
|
||||
kind: "fn",
|
||||
function: "keyword",
|
||||
inputs: 1
|
||||
},
|
||||
"keyword?": {
|
||||
kind: "fn",
|
||||
function: "keyword?",
|
||||
inputs: 1
|
||||
},
|
||||
"vector": {
|
||||
kind: "fn",
|
||||
function: "vector",
|
||||
inputs: -1
|
||||
},
|
||||
"vector?": {
|
||||
kind: "fn",
|
||||
function: "vector?",
|
||||
inputs: 1
|
||||
},
|
||||
"sequential?": {
|
||||
kind: "fn",
|
||||
function: "sequential?",
|
||||
inputs: 1
|
||||
},
|
||||
"hash-map": {
|
||||
kind: "fn",
|
||||
function: "hash-map",
|
||||
inputs: -1
|
||||
},
|
||||
"map?": {
|
||||
kind: "fn",
|
||||
function: "map?",
|
||||
inputs: 1
|
||||
},
|
||||
"assoc": {
|
||||
kind: "fn",
|
||||
function: "assoc",
|
||||
inputs: -2
|
||||
},
|
||||
"dissoc": {
|
||||
kind: "fn",
|
||||
function: "dissoc",
|
||||
inputs: -2
|
||||
},
|
||||
"get": {
|
||||
kind: "fn",
|
||||
function: "get",
|
||||
inputs: 2
|
||||
},
|
||||
"contains?": {
|
||||
kind: "fn",
|
||||
function: "contains?",
|
||||
inputs: 2
|
||||
},
|
||||
"keys": {
|
||||
kind: "fn",
|
||||
function: "keys",
|
||||
inputs: 1
|
||||
},
|
||||
"vals": {
|
||||
kind: "fn",
|
||||
function: "vals",
|
||||
inputs: 1
|
||||
}
|
||||
};
|
||||
|
||||
@ -140,11 +245,16 @@ def vec2list(obj):
|
||||
if obj.kind == "list" then
|
||||
obj.value | map(vec2list(.)) | wrap("list")
|
||||
else
|
||||
if obj.kind == "vector" then
|
||||
obj.value | map(vec2list(.)) | wrap("list")
|
||||
else
|
||||
obj
|
||||
end end;
|
||||
if obj.kind == "vector" then
|
||||
obj.value | map(vec2list(.)) | wrap("list")
|
||||
else
|
||||
if obj.kind == "hashmap" then
|
||||
obj.value | map_values(.value |= vec2list(.)) | wrap("hashmap")
|
||||
else
|
||||
obj
|
||||
end
|
||||
end
|
||||
end;
|
||||
|
||||
def core_interp(arguments; env):
|
||||
(
|
||||
@ -220,4 +330,72 @@ def core_interp(arguments; env):
|
||||
select(.function == "first") | arguments[0].value | first // {kind:"nil"}
|
||||
) // (
|
||||
select(.function == "rest") | arguments[0]?.value?[1:]? // [] | wrap("list")
|
||||
) // jqmal_error("Unknown native function \(.function)");
|
||||
) // (
|
||||
select(.function == "throw") | jqmal_error(arguments[0] | tojson)
|
||||
) // (
|
||||
select(.function == "nil?") | null | wrap((arguments[0].kind == "nil") | tostring)
|
||||
) // (
|
||||
select(.function == "true?") | null | wrap((arguments[0].kind == "true") | tostring)
|
||||
) // (
|
||||
select(.function == "false?") | null | wrap((arguments[0].kind == "false") | tostring)
|
||||
) // (
|
||||
select(.function == "symbol?") | null | wrap((arguments[0].kind == "symbol") | tostring)
|
||||
) // (
|
||||
select(.function == "symbol") | arguments[0].value | wrap("symbol")
|
||||
) // (
|
||||
select(.function == "keyword") | arguments[0].value | wrap("keyword")
|
||||
) // (
|
||||
select(.function == "keyword?") | null | wrap((arguments[0].kind == "keyword") | tostring)
|
||||
) // (
|
||||
select(.function == "vector") | arguments | wrap("vector")
|
||||
) // (
|
||||
select(.function == "vector?") | null | wrap((arguments[0].kind == "vector") | tostring)
|
||||
) // (
|
||||
select(.function == "sequential?") | null | wrap((arguments[0].kind == "vector" or arguments[0].kind == "list") | tostring)
|
||||
) // (
|
||||
select(.function == "hash-map") |
|
||||
if (arguments|length) % 2 == 1 then
|
||||
jqmal_error("Odd number of arguments to hash-map")
|
||||
else
|
||||
[ arguments |
|
||||
nwise(2) |
|
||||
try {
|
||||
key: (.[0] | extract_string),
|
||||
value: {
|
||||
kkind: .[0].kind,
|
||||
value: .[1]
|
||||
}
|
||||
}
|
||||
] | from_entries | wrap("hashmap")
|
||||
end
|
||||
) // (
|
||||
select(.function == "map?") | null | wrap((arguments[0].kind == "hashmap") | tostring)
|
||||
) // (
|
||||
select(.function == "assoc") |
|
||||
if (arguments|length) % 2 == 0 then
|
||||
jqmal_error("Odd number of key-values to assoc")
|
||||
else
|
||||
arguments[0].value + ([ arguments[1:] |
|
||||
nwise(2) |
|
||||
try {
|
||||
key: (.[0] | extract_string),
|
||||
value: {
|
||||
kkind: .[0].kind,
|
||||
value: .[1]
|
||||
}
|
||||
}
|
||||
] | from_entries) | wrap("hashmap")
|
||||
end
|
||||
) // (
|
||||
select(.function == "dissoc") |
|
||||
arguments[1:] | map(.value) as $keynames |
|
||||
arguments[0].value | with_entries(select(.key as $k | $keynames | contains([$k]) | not)) | wrap("hashmap")
|
||||
) // (
|
||||
select(.function == "get") | arguments[0].value[arguments[1].value].value // {kind:"nil"}
|
||||
) // (
|
||||
select(.function == "contains?") | null | wrap((arguments[0].value | has(arguments[1].value)) | tostring)
|
||||
) // (
|
||||
select(.function == "keys") | arguments[0].value | with_entries(.value as $v | .key as $k | {key: $k, value: {value: $k, kind: $v.kkind}}) | to_entries | map(.value) | wrap("list")
|
||||
) // (
|
||||
select(.function == "vals") | arguments[0].value | map(.value) | to_entries | map(.value) | wrap("list")
|
||||
) // jqmal_error("Unknown native function \(.function)");
|
@ -147,7 +147,7 @@ def env_setfallback(env; fallback):
|
||||
};
|
||||
|
||||
def env_get(env):
|
||||
. as $key | env_find(env).environment[$key] // jqmal_error("Symbol \($key) not found");
|
||||
. as $key | env_find(env).environment[$key] // jqmal_error("'\($key)' not found");
|
||||
|
||||
def env_get(env; key):
|
||||
key | env_get(env);
|
||||
@ -247,5 +247,5 @@ def lookup(env):
|
||||
if env.parent then
|
||||
lookup(env.parent)
|
||||
else
|
||||
jqmal_error("Symbol \(.) not found")
|
||||
jqmal_error("'\(.)' not found")
|
||||
end;
|
30
jq/interp.jq
30
jq/interp.jq
@ -4,10 +4,14 @@ include "env";
|
||||
include "printer";
|
||||
|
||||
def arg_check(args):
|
||||
if .inputs == -1 then
|
||||
.
|
||||
if .inputs < 0 then
|
||||
if (abs(.inputs) - 1) > (args | length) then
|
||||
jqmal_error("Invalid number of arguments (expected at least \(abs(.inputs) - 1), got \(args|length): \(args | wrap("vector") | pr_str))")
|
||||
else
|
||||
.
|
||||
end
|
||||
else if .inputs != (args|length) then
|
||||
jqmal_error("Invalid number of arguments (expected \(.inputs) got \(args|length): \(args))")
|
||||
jqmal_error("Invalid number of arguments (expected \(.inputs), got \(args|length): \(args | wrap("vector") | pr_str))")
|
||||
else
|
||||
.
|
||||
end end;
|
||||
@ -139,7 +143,25 @@ def interpret(arguments; env; _eval):
|
||||
. as $env | env_set_($env; $name; $newValue)
|
||||
)) as $newEnv |
|
||||
$newValue.value | addEnv($newEnv | setpath(["currentEnv", "dirty_atoms"]; ($newEnv.currentEnv.dirty_atoms + [$newValue])|unique))
|
||||
)//
|
||||
) //
|
||||
(select(.function == "apply") |
|
||||
# (apply F ...T A) -> (F ...T ...A)
|
||||
arguments as $args
|
||||
| ($args|first) as $F
|
||||
| ($args|last.value) as $A
|
||||
| $args[1:-1] as $T
|
||||
| $F | interpret([$T[], $A[]]; env; _eval)
|
||||
) //
|
||||
(select(.function == "map") |
|
||||
arguments
|
||||
| first as $F
|
||||
| last.value as $L
|
||||
| (reduce $L[] as $elem (
|
||||
[];
|
||||
. + [($F | interpret([$elem]; env; _eval).expr)]
|
||||
)) as $ex
|
||||
| $ex | wrap("list") | addEnv(env)
|
||||
) //
|
||||
(core_interp(arguments; env) | addEnv(env))
|
||||
) //
|
||||
(select(.kind == "function") as $fn |
|
||||
|
@ -13,7 +13,7 @@ def READ:
|
||||
|
||||
def lookup(env):
|
||||
env[.] //
|
||||
jqmal_error("Symbol \(.) not found");
|
||||
jqmal_error("'\(.)' not found");
|
||||
|
||||
def EVAL(env):
|
||||
def eval_ast:
|
||||
|
382
jq/step9_try.jq
Normal file
382
jq/step9_try.jq
Normal file
@ -0,0 +1,382 @@
|
||||
include "reader";
|
||||
include "printer";
|
||||
include "utils";
|
||||
include "interp";
|
||||
include "env";
|
||||
include "core";
|
||||
|
||||
def read_line:
|
||||
. as $in
|
||||
| label $top
|
||||
| _readline;
|
||||
|
||||
def READ:
|
||||
read_str | read_form | .value;
|
||||
|
||||
def recurseflip(x; y):
|
||||
recurse(y; x);
|
||||
|
||||
def TCOWrap(env; retenv; continue):
|
||||
{
|
||||
ast: .,
|
||||
env: env,
|
||||
ret_env: retenv,
|
||||
finish: (continue | not),
|
||||
cont: true # set inside
|
||||
};
|
||||
|
||||
def _symbol(name):
|
||||
{
|
||||
kind: "symbol",
|
||||
value: name
|
||||
};
|
||||
|
||||
def _symbol_v(name):
|
||||
if .kind == "symbol" then
|
||||
.value == name
|
||||
else
|
||||
false
|
||||
end;
|
||||
|
||||
def quasiquote:
|
||||
if isPair then
|
||||
.value as $value | null |
|
||||
if ($value[0] | _symbol_v("unquote")) then
|
||||
$value[1]
|
||||
else
|
||||
if isPair($value[0]) and ($value[0].value[0] | _symbol_v("splice-unquote")) then
|
||||
[_symbol("concat")] +
|
||||
[$value[0].value[1]] +
|
||||
[($value[1:] | wrap("list") | quasiquote)] | wrap("list")
|
||||
else
|
||||
[_symbol("cons")] +
|
||||
[($value[0] | quasiquote)] +
|
||||
[($value[1:] | wrap("list") | quasiquote)] | wrap("list")
|
||||
end
|
||||
end
|
||||
else
|
||||
[_symbol("quote")] +
|
||||
[.] | wrap("list")
|
||||
end;
|
||||
|
||||
def set_macro_function:
|
||||
if .kind != "function" then
|
||||
jqmal_error("expected a function to be defined by defmacro!")
|
||||
else
|
||||
.is_macro |= true
|
||||
end;
|
||||
|
||||
def is_macro_call(env):
|
||||
if .kind != "list" then
|
||||
false
|
||||
else
|
||||
if (.value|first.kind == "symbol") then
|
||||
env_req(env; .value|first.value)
|
||||
| if .kind != "function" then
|
||||
false
|
||||
else
|
||||
.is_macro
|
||||
end
|
||||
else
|
||||
false
|
||||
end
|
||||
end;
|
||||
|
||||
def EVAL(env):
|
||||
def _eval_here:
|
||||
.env as $env | .expr | EVAL($env);
|
||||
|
||||
def _interpret($_menv):
|
||||
reduce .value[] as $elem (
|
||||
[];
|
||||
. as $dot | $elem | EVAL($_menv) as $eval_env |
|
||||
($dot + [$eval_env.expr])
|
||||
) | . as $expr | first |
|
||||
interpret($expr[1:]; $_menv; _eval_here);
|
||||
|
||||
def macroexpand(env):
|
||||
[ while(is_macro_call(env | unwrapCurrentEnv);
|
||||
_interpret(env).expr) // . ]
|
||||
| first
|
||||
| if is_macro_call(env | unwrapCurrentEnv) then
|
||||
_interpret(env).expr
|
||||
else
|
||||
.
|
||||
end;
|
||||
|
||||
def hmap_with_env:
|
||||
.env as $env | .list as $list |
|
||||
if $list|length == 0 then
|
||||
empty
|
||||
else
|
||||
$list[0] as $elem |
|
||||
$list[1:] as $rest |
|
||||
$elem.value.value | EVAL($env) as $resv |
|
||||
{
|
||||
value: {
|
||||
key: $elem.key,
|
||||
value: { kkind: $elem.value.kkind, value: $resv.expr }
|
||||
},
|
||||
env: env
|
||||
},
|
||||
({env: $resv.env, list: $rest} | hmap_with_env)
|
||||
end;
|
||||
def map_with_env:
|
||||
.env as $env | .list as $list |
|
||||
if $list|length == 0 then
|
||||
empty
|
||||
else
|
||||
$list[0] as $elem |
|
||||
$list[1:] as $rest |
|
||||
$elem | EVAL($env) as $resv |
|
||||
{ value: $resv.expr, env: env },
|
||||
({env: $resv.env, list: $rest} | map_with_env)
|
||||
end;
|
||||
def eval_ast(env):
|
||||
(select(.kind == "vector") |
|
||||
if .value|length == 0 then
|
||||
{
|
||||
kind: "vector",
|
||||
value: []
|
||||
}
|
||||
else
|
||||
[ { env: env, list: .value } | map_with_env ] as $res |
|
||||
{
|
||||
kind: "vector",
|
||||
value: $res | map(.value)
|
||||
}
|
||||
end
|
||||
) //
|
||||
(select(.kind == "hashmap") |
|
||||
[ { env: env, list: (.value | to_entries) } | hmap_with_env ] as $res |
|
||||
{
|
||||
kind: "hashmap",
|
||||
value: $res | map(.value) | from_entries
|
||||
}
|
||||
) //
|
||||
(select(.kind == "function") |
|
||||
.# return this unchanged, since it can only be applied to
|
||||
) //
|
||||
(select(.kind == "symbol") |
|
||||
.value | env_get(env | unwrapCurrentEnv)
|
||||
) // .;
|
||||
|
||||
. as $ast
|
||||
| { env: env, ast: ., cont: true, finish: false, ret_env: null }
|
||||
| [ recurseflip(.cont;
|
||||
.env as $_menv
|
||||
| if .finish then
|
||||
.cont |= false
|
||||
else
|
||||
(.ret_env//.env) as $_retenv
|
||||
| .ret_env as $_orig_retenv
|
||||
| .ast
|
||||
| . as $init
|
||||
| $_menv | unwrapCurrentEnv as $currentEnv # unwrap env "package"
|
||||
| $_menv | unwrapReplEnv as $replEnv # -
|
||||
| $init
|
||||
|
|
||||
(select(.kind == "list") |
|
||||
macroexpand($_menv) |
|
||||
if .kind != "list" then
|
||||
eval_ast($_menv) | TCOWrap($_menv; $_orig_retenv; false)
|
||||
else
|
||||
if .value | length == 0 then
|
||||
. | TCOWrap($_menv; $_orig_retenv; false)
|
||||
else
|
||||
(
|
||||
(
|
||||
.value | select(.[0].value == "def!") as $value |
|
||||
($value[2] | EVAL($_menv)) as $evval |
|
||||
addToEnv($evval; $value[1].value) as $val |
|
||||
$val.expr | TCOWrap($val.env; $_orig_retenv; false)
|
||||
) //
|
||||
(
|
||||
.value | select(.[0].value == "defmacro!") as $value |
|
||||
($value[2] | EVAL($_menv) | (.expr |= set_macro_function)) as $evval |
|
||||
addToEnv($evval; $value[1].value) as $val |
|
||||
$val.expr | TCOWrap($val.env; $_orig_retenv; false)
|
||||
) //
|
||||
(
|
||||
.value | select(.[0].value == "let*") as $value |
|
||||
($currentEnv | pureChildEnv | wrapEnv($replEnv)) as $subenv |
|
||||
(reduce ($value[1].value | nwise(2)) as $xvalue (
|
||||
$subenv;
|
||||
. as $env | $xvalue[1] | EVAL($env) as $expenv |
|
||||
env_set_($expenv.env; $xvalue[0].value; $expenv.expr))) as $env
|
||||
| $value[2] | TCOWrap($env; $_retenv; true)
|
||||
) //
|
||||
(
|
||||
.value | select(.[0].value == "do") as $value |
|
||||
(reduce ($value[1:][]) as $xvalue (
|
||||
{ env: $_menv, expr: {kind:"nil"} };
|
||||
.env as $env | $xvalue | EVAL($env)
|
||||
)) | . as $ex | .expr | TCOWrap($ex.env; $_orig_retenv; false)
|
||||
) //
|
||||
(
|
||||
.value | select(.[0].value == "try*") as $value |
|
||||
try (
|
||||
$value[1] | EVAL($_menv) as $exp | $exp.expr | TCOWrap($exp.env; $_orig_retenv; false)
|
||||
) catch ( . as $exc |
|
||||
if $value[2] then
|
||||
if ($value[2].value[0] | _symbol_v("catch*")) then
|
||||
(if ($exc | is_jqmal_error) then
|
||||
$exc[19:] as $ex |
|
||||
try (
|
||||
$ex
|
||||
| fromjson
|
||||
) catch (
|
||||
$ex |
|
||||
wrap("string")
|
||||
)
|
||||
else
|
||||
$exc|wrap("string")
|
||||
end) as $exc |
|
||||
$value[2].value[2] | EVAL($currentEnv | childEnv([$value[2].value[1].value]; [$exc]) | wrapEnv($replEnv)) as $ex |
|
||||
$ex.expr | TCOWrap($ex.env; $_retenv; false)
|
||||
else
|
||||
error($exc)
|
||||
end
|
||||
else
|
||||
error($exc)
|
||||
end
|
||||
)
|
||||
) //
|
||||
(
|
||||
.value | select(.[0].value == "if") as $value |
|
||||
$value[1] | EVAL($_menv) as $condenv |
|
||||
(if (["false", "nil"] | contains([$condenv.expr.kind])) then
|
||||
($value[3] // {kind:"nil"})
|
||||
else
|
||||
$value[2]
|
||||
end) | TCOWrap($condenv.env; $_orig_retenv; true)
|
||||
) //
|
||||
(
|
||||
.value | select(.[0].value == "fn*") as $value |
|
||||
# we can't do what the guide says, so we'll skip over this
|
||||
# and ues the later implementation
|
||||
# (fn* args body)
|
||||
$value[1].value | map(.value) as $binds |
|
||||
($value[2] | find_free_references($currentEnv | env_dump_keys + $binds)) as $free_referencess | {
|
||||
kind: "function",
|
||||
binds: $binds,
|
||||
env: (env | env_remove_references($free_referencess)),
|
||||
body: $value[2],
|
||||
names: [], # we can't do that circular reference this
|
||||
free_referencess: $free_referencess, # for dynamically scoped variables
|
||||
is_macro: false
|
||||
} | TCOWrap($_menv; $_orig_retenv; false)
|
||||
) //
|
||||
(
|
||||
.value | select(.[0].value == "quote") as $value |
|
||||
$value[1] | TCOWrap($_menv; $_orig_retenv; false)
|
||||
) //
|
||||
(
|
||||
.value | select(.[0].value == "quasiquote") as $value |
|
||||
$value[1] | quasiquote | TCOWrap($_menv; $_orig_retenv; true)
|
||||
) //
|
||||
(
|
||||
.value | select(.[0].value == "macroexpand") as $value |
|
||||
$value[1] | macroexpand(env) | TCOWrap($_menv; $_orig_retenv; false)
|
||||
) //
|
||||
(
|
||||
. as $dot | _interpret($_menv) as $exprenv |
|
||||
$exprenv.expr | TCOWrap($exprenv.env; $_orig_retenv; false)
|
||||
) //
|
||||
TCOWrap($_menv; $_orig_retenv; false)
|
||||
)
|
||||
end
|
||||
end
|
||||
) //
|
||||
(eval_ast($_menv) | TCOWrap($_menv; $_orig_retenv; false))
|
||||
end
|
||||
) ]
|
||||
| last as $result
|
||||
| ($result.ret_env // $result.env) as $env
|
||||
| $result.ast
|
||||
| addEnv($env);
|
||||
|
||||
def PRINT:
|
||||
pr_str;
|
||||
|
||||
def rep(env):
|
||||
READ | EVAL(env) as $expenv |
|
||||
if $expenv.expr != null then
|
||||
$expenv.expr | PRINT
|
||||
else
|
||||
null
|
||||
end | addEnv($expenv.env);
|
||||
|
||||
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:
|
||||
{
|
||||
parent: null,
|
||||
environment: ({
|
||||
"+": {
|
||||
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"
|
||||
},
|
||||
"eval": {
|
||||
kind: "fn",
|
||||
inputs: 1,
|
||||
function: "eval"
|
||||
}
|
||||
} + core_identify),
|
||||
dirty_atoms: [],
|
||||
fallback: null
|
||||
};
|
||||
|
||||
def repl(env):
|
||||
def xrepl:
|
||||
(.env as $env | try repl_($env) catch addEnv($env)) as $expenv |
|
||||
{
|
||||
value: $expenv.expr,
|
||||
stop: false,
|
||||
env: ($expenv.env // .env)
|
||||
} | ., xrepl;
|
||||
{stop: false, env: env} | xrepl | if .value then (.value | _print) else empty end;
|
||||
|
||||
def eval_ign(expr):
|
||||
. as $env | expr | rep($env) | .env;
|
||||
|
||||
def eval_val(expr):
|
||||
. as $env | expr | rep($env) | .expr;
|
||||
|
||||
def getEnv:
|
||||
replEnv
|
||||
| wrapEnv
|
||||
| eval_ign("(def! not (fn* (a) (if a false true)))")
|
||||
| eval_ign("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \"\\nnil)\")))))))")
|
||||
| eval_ign("(defmacro! cond (fn* (& xs) (if (> (count xs) 0) (list 'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw \"odd number of forms to cond\")) (cons 'cond (rest (rest xs)))))))")
|
||||
;
|
||||
|
||||
def main:
|
||||
if $ARGS.positional|length > 0 then
|
||||
getEnv as $env |
|
||||
env_set_($env; "*ARGV*"; $ARGS.positional[1:] | map(wrap("string")) | wrap("list")) |
|
||||
eval_val("(load-file \($ARGS.positional[0] | tojson))")
|
||||
else
|
||||
repl( getEnv as $env | env_set_($env; "*ARGV*"; [] | wrap("list")) )
|
||||
end;
|
||||
|
||||
main
|
@ -7,11 +7,14 @@ def nwise(n):
|
||||
end;
|
||||
_nwise;
|
||||
|
||||
def abs(x):
|
||||
if x < 0 then 0 - x else x end;
|
||||
|
||||
def jqmal_error(e):
|
||||
error("JqMAL :: " + e);
|
||||
error("JqMAL Exception :: " + e);
|
||||
|
||||
def is_jqmal_error:
|
||||
startswith("JqMAL :: ");
|
||||
startswith("JqMAL Exception :: ");
|
||||
|
||||
def wrap(kind):
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user