kind: "fn",
function: "slurp",
inputs: 1
+ },
+ "atom": {
+ kind: "fn",
+ function: "atom",
+ inputs: 1
+ },
+ "atom?": {
+ kind: "fn",
+ function: "atom?",
+ inputs: 1
+ },
+ "deref": {
+ kind: "fn",
+ function: "deref",
+ inputs: 1
+ },
+ "reset!": { # defined in interp
+ kind: "fn",
+ function: "reset!",
+ inputs: 2
+ },
+ "swap!": { # defined in interp
+ kind: "fn",
+ function: "swap!",
+ inputs: -1
}
};
select(.function == "slurp") | arguments | map(.value) | issue_extern("read") | wrap("string")
) // (
select(.function == "read-string") | arguments | first.value | read_str | read_form.value
+ ) // (
+ select(.function == "atom") | arguments | first | wrap2("atom"; {names: []})
+ ) // (
+ select(.function == "atom?") | null | wrap(arguments | first.kind == "atom" | tostring)
+ ) // (
+ select(.function == "deref") | arguments | first.value
) // jqmal_error("Unknown native function \(.function)");
\ No newline at end of file
env | env_multiset(keys; value);
def env_set($key; $value):
- (if $value.kind == "function" then
+ (if $value.kind == "function" or $value.kind == "atom" then
# inform the function of its names
$value | inform_function($key)
else
def env_dump_keys:
def _dump:
- .environment | keys;
+ .environment // {} | keys;
if .parent == null then
_dump
else
- .parent | env_dump_keys + _dump
+ (.parent | env_dump_keys + _dump) | unique
end;
def env_set(env; $key; $value):
- (if $value.kind == "function" then
- # inform the function of its names
+ (if $value.kind == "function" or $value.kind == "atom" then
+ # inform the function/atom of its names
$value | (.names += [$key]) | (.names |= unique)
else
$value
end) as $value | {
parent: env.parent,
- environment: (env.environment + (env.environment | .[$key] |= $value)) # merge together, as env.environment[key] |= value does not work
+ environment: ((env.environment // jqmal_error("Environment empty in \(env | keys)")) + (env.environment | .[$key] |= $value)) # merge together, as env.environment[key] |= value does not work
};
def env_find(env):
env_set(env.currentEnv; key; value) | wrapEnv(env.replEnv)
end;
+def env_set_(env; key; value):
+ if env.currentEnv != null then
+ env_set6(env; key; value)
+ else
+ env_set(env; key; value)
+ end;
+
def addToEnv6(envexp; name):
envexp.expr as $value
| envexp.env as $rawEnv
| (if $rawEnv.isReplEnv then
- env_set($rawEnv.currentEnv; name; $value) | wrapEnv
+ env_set_($rawEnv.currentEnv; name; $value) | wrapEnv
else
- env_set($rawEnv.currentEnv; name; $value) | wrapEnv($rawEnv.replEnv)
+ env_set_($rawEnv.currentEnv; name; $value) | wrapEnv($rawEnv.replEnv)
end) as $newEnv
| {
expr: $value,
addToEnv6(envexp; name)
else {
expr: envexp.expr,
- env: env_set(envexp.env; name; envexp.expr)
+ env: env_set_(envexp.env; name; envexp.expr)
} end;
# for step2
.
end;
+def updateAtoms(newEnv):
+ . as $env
+ | reduce (newEnv | env_dump_keys | map(env_get(newEnv) as $value | select($value.kind == "atom") | $value))[] as $atom (
+ $env;
+ . as $e | reduce $atom.names[] as $name (
+ $e;
+ env_set_(.; $name; $atom)));
+
def interpret(arguments; env; _eval):
extractReplEnv(env) as $replEnv |
hasReplEnv(env) as $hasReplEnv |
| setpath(
["env", "currentEnv"];
extractEnv(env) | cUpdateReplEnv($xreplenv; $hasReplEnv))
+ ) //
+ (select(.function == "reset!") |
+ # env modifying function
+ arguments[0].names as $names |
+ arguments[1]|wrap2("atom"; {names: $names}) as $value |
+ (reduce $names[] as $name (
+ env;
+ . as $env | env_set_($env; $name; $value)
+ )) as $env |
+ $value.value | addEnv($env)
+ ) //
+ (select(.function == "swap!") |
+ # env modifying function
+ arguments[0].names as $names |
+ arguments[0].value as $initValue |
+ arguments[1] as $function |
+ ([$initValue] + arguments[2:]) as $args |
+ ($function | interpret($args; env; _eval)) as $newEnvValue |
+ $newEnvValue.expr|wrap2("atom"; {names: $names}) as $newValue |
+ $newEnvValue.env as $newEnv |
+ (reduce $names[] as $name (
+ $newEnv;
+ . as $env | env_set_($env; $name; $newValue)
+ )) as $newEnv |
+ $newValue.value | addEnv($newEnv)
) //
(core_interp(arguments; env) | addEnv(env))
) //
# tell it about its surroundings
(reduce $fn.free_referencess[] as $name (
$fnEnv;
- . as $env | try env_set(
+ . as $env | try env_set_(
.;
$name;
$name | env_get(env) | . as $xvalue
| cWrapEnv($replEnv; $hasReplEnv),
expr: $fn.body
}
- | _eval
+ | _eval
| . as $envexp
- | extractReplEnv($envexp.env) as $xreplenv
+ | (extractReplEnv($envexp.env)) as $xreplenv
|
{
expr: .expr,
env: extractEnv(env)
| cUpdateReplEnv($xreplenv; $hasReplEnv)
| cWrapEnv($xreplenv; $hasReplEnv)
+ | updateAtoms(extractEnv($envexp.env))
}
) //
jqmal_error("Unsupported function kind \(.kind)");
(select(.kind == "false") | "false") //
(select(.kind == "fn") | "#<fn>") //
(select(.kind == "function")| "#<function \([":anon"] + .names | join(", "))>") //
+ (select(.kind == "atom")| "(atom \(.value | pr_str(opt)))") //
"#<Unknown \(.kind) in \(.)>";
def pr_str:
rm $tmp
;;
fwrite)
- filename=$(echo "$command" | jq -Mrc ".args[0]|fromjson")
- content=$(echo "$command" | jq -Mrc ".args[1]|fromjson")
- echo "Writing stuff to $filename"
- echo "$content" > "$filename"
+ tmp=$(mktemp)
+ echo "$command" > $tmp
+ filename=$(cat $tmp | jq -Mrc ".args[0]|fromjson")
+ content=$(cat $tmp | jq -Mrc ".args[1]|fromjson")
+ app=$(cat $tmp | jq -Mrc ".args[2]|fromjson")
+ echo "'$app': Writing stuff to $filename"
+ if [[ $res == false ]]; then
+ echo "$content" > "$filename"
+ else
+ echo "$content" >> "$filename"
+ fi
;;
*)
echo $cmd
) //
(
reduce .value[] as $elem (
- {value: [], env: env};
- . as $dot | $elem | EVAL($dot.env) as $eval_env |
- {
- value: ($dot.value + [$eval_env.expr]),
- env: $eval_env.env
- }
- ) | { expr: .value, env: .env } as $ev
+ [];
+ . as $dot | $elem | EVAL(env) as $eval_env |
+ ($dot + [$eval_env.expr])
+ ) | { expr: ., env: env } as $ev
| $ev.expr | first |
interpret($ev.expr[1:]; $ev.env; _eval_here)
) //
) //
(
reduce .value[] as $elem (
- {value: [], env: env};
- . as $dot | $elem | EVAL($dot.env) as $eval_env |
- {
- value: ($dot.value + [$eval_env.expr]),
- env: $eval_env.env
- }
- ) | { expr: .value, env: .env } as $ev
+ [];
+ . as $dot | $elem | EVAL(env) as $eval_env |
+ ($dot + [$eval_env.expr])
+ ) | { expr: ., env: env } as $ev
| $ev.expr | first |
interpret($ev.expr[1:]; $ev.env; _eval_here)
) //
) //
(
reduce .value[] as $elem (
- {value: [], env: env};
- . as $dot | $elem | EVAL($dot.env) as $eval_env |
- {
- value: ($dot.value + [$eval_env.expr]),
- env: $eval_env.env
- }
- ) | { expr: .value, env: .env } as $ev
+ [];
+ . as $dot | $elem | EVAL(env) as $eval_env |
+ ($dot + [$eval_env.expr])
+ ) | { expr: ., env: env } as $ev
| $ev.expr | first |
interpret($ev.expr[1:]; $ev.env; _eval_here)
) //
else
$list[0] as $elem |
$list[1:] as $rest |
- $elem[1] | EVAL($env) as $resv |
- { value: [$elem[0], $resv.expr], env: env },
+ $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:
(reduce ($value[1].value | nwise(2)) as $xvalue (
$subenv;
. as $env | $xvalue[1] | EVAL($env) as $expenv |
- env_set6($expenv.env; $xvalue[0].value; $expenv.expr))) as $env
+ env_set_($expenv.env; $xvalue[0].value; $expenv.expr))) as $env
| $value[2] | { expr: EVAL($env).expr, env: env }
) //
(
) //
(
reduce .value[] as $elem (
- {value: [], env: env};
- . as $dot | $elem | EVAL($dot.env) as $eval_env |
- {
- value: ($dot.value + [$eval_env.expr]),
- env: $eval_env.env
- }
- ) | { expr: .value, env: .env } as $ev
+ [];
+ . as $dot | $elem | EVAL(env) as $eval_env |
+ ($dot + [$eval_env.expr])
+ ) | { expr: ., env: env } as $ev
| $ev.expr | first |
interpret($ev.expr[1:]; $ev.env; _eval_here)
) //
end
) //
(select(.kind == "hashmap") |
- [ { env: env, list: .value | to_entries } | hmap_with_env ] as $res |
+ [ { env: env, list: (.value | to_entries) } | hmap_with_env ] as $res |
{
kind: "hashmap",
value: $res | map(.value) | from_entries
| 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)\")))))))")
+ | . as $env
+ | env_set_($env; "*ARGV*"; $ARGS.positional | wrap("list"))
)
\ No newline at end of file
value: .
};
+def wrap2(kind; opts):
+ opts + {
+ kind: kind,
+ value: .
+ };
+
def _extern(options):
{command: .}
| debug
def _write_to_file(name):
. as $value
- | [name, .|tojson]
+ | [(name|tojson), (.|tojson), (false|tojson)]
| issue_extern("fwrite"; {nowait: true})
- | $value;
\ No newline at end of file
+ | $value;
+
+def _append_to_file(name):
+ . as $value
+ | [(name|tojson), (.|tojson), (true|tojson)]
+ | issue_extern("fwrite"; {nowait: true})
+ | $value;
+
+def trap:
+ _write_to_file("trap_reason.json") | jqmal_error("trap");
\ No newline at end of file