mirror of
https://github.com/kanaka/mal.git
synced 2024-11-13 01:43:50 +03:00
step 3 done~
This commit is contained in:
parent
b27d81d826
commit
51ff32e290
16
jq/core.jq
Normal file
16
jq/core.jq
Normal file
@ -0,0 +1,16 @@
|
||||
include "utils";
|
||||
|
||||
def core_interp(arguments; env):
|
||||
(
|
||||
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("Unknown native function \(.function)");
|
72
jq/env.jq
Normal file
72
jq/env.jq
Normal file
@ -0,0 +1,72 @@
|
||||
include "utils";
|
||||
|
||||
def childEnv(binds; value):
|
||||
{
|
||||
parent: .,
|
||||
environment: [binds, value] | transpose | map({(.[0]): .[1]}) | from_entries
|
||||
};
|
||||
|
||||
def pureChildEnv:
|
||||
{
|
||||
parent: .,
|
||||
environment: {}
|
||||
};
|
||||
|
||||
def rootEnv:
|
||||
{
|
||||
parent: null,
|
||||
environment: {}
|
||||
};
|
||||
|
||||
def env_set(key; value):
|
||||
{
|
||||
parent: .parent,
|
||||
environment: (.environment + (.environment | .[key] |= value)) # merge together, as .environment[key] |= value does not work
|
||||
};
|
||||
|
||||
def env_set(env; key; value):
|
||||
{
|
||||
parent: env.parent,
|
||||
environment: (env.environment + (env.environment | .[key] |= value)) # merge together, as env.environment[key] |= value does not work
|
||||
};
|
||||
|
||||
def env_find(env):
|
||||
if env.environment[.] == null then
|
||||
if env.parent then
|
||||
env_find(env.parent)
|
||||
else
|
||||
null
|
||||
end
|
||||
else
|
||||
env
|
||||
end;
|
||||
|
||||
def env_get(env):
|
||||
. as $key | env_find(env).environment[$key] // jqmal_error("Symbol \($key) not found");
|
||||
|
||||
def addEnv(env):
|
||||
{
|
||||
expr: .,
|
||||
env: env
|
||||
};
|
||||
|
||||
def addToEnv(env; name; expr):
|
||||
{
|
||||
expr: expr,
|
||||
env: env_set(env; name; expr)
|
||||
};
|
||||
|
||||
def addToEnv(envexp; name):
|
||||
{
|
||||
expr: envexp.expr,
|
||||
env: env_set(envexp.env; name; envexp.expr)
|
||||
};
|
||||
|
||||
# for step2
|
||||
def lookup(env):
|
||||
env.environment[.] //
|
||||
if env.parent then
|
||||
lookup(env.parent)
|
||||
else
|
||||
jqmal_error("Symbol \(.) not found")
|
||||
end;
|
17
jq/interp.jq
17
jq/interp.jq
@ -1,4 +1,5 @@
|
||||
include "utils";
|
||||
include "core";
|
||||
|
||||
def arg_check(args):
|
||||
if .inputs != (args|length) then
|
||||
@ -10,17 +11,5 @@ def arg_check(args):
|
||||
|
||||
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("Unknown native function \(.function)");
|
||||
) // jqmal_error("Unsupported function kind \(.kind)")
|
||||
arg_check(arguments) | core_interp(arguments; env)
|
||||
) // jqmal_error("Unsupported function kind \(.kind)");
|
@ -12,12 +12,8 @@ def READ:
|
||||
read_str | read_form | .value;
|
||||
|
||||
def lookup(env):
|
||||
env.environment[.] //
|
||||
if env.parent then
|
||||
lookup(env.parent)
|
||||
else
|
||||
jqmal_error("Symbol \(.) not found")
|
||||
end;
|
||||
env[.] //
|
||||
jqmal_error("Symbol \(.) not found");
|
||||
|
||||
def EVAL(env):
|
||||
def eval_ast:
|
||||
@ -61,38 +57,29 @@ def repl_(env):
|
||||
("user> " | stderr) |
|
||||
(read_line | rep(env));
|
||||
|
||||
def childEnv(binds; value):
|
||||
{
|
||||
parent: .,
|
||||
environment: [binds, value] | transpose | map({(.[0]): .[1]}) | from_entries
|
||||
};
|
||||
|
||||
# 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"
|
||||
},
|
||||
}
|
||||
"+": {
|
||||
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):
|
||||
|
150
jq/step3_env.jq
Normal file
150
jq/step3_env.jq
Normal file
@ -0,0 +1,150 @@
|
||||
include "reader";
|
||||
include "printer";
|
||||
include "utils";
|
||||
include "interp";
|
||||
include "env";
|
||||
|
||||
def read_line:
|
||||
. as $in
|
||||
| label $top
|
||||
| input;
|
||||
|
||||
def READ:
|
||||
read_str | read_form | .value;
|
||||
|
||||
def EVAL(env):
|
||||
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[1] | EVAL($env) as $resv |
|
||||
{ value: [$elem[0], $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;
|
||||
(select(.kind == "list") |
|
||||
if .value | length == 0 then
|
||||
.
|
||||
else
|
||||
(
|
||||
(
|
||||
.value | select(.[0].value == "def!") as $value |
|
||||
($value[2] | EVAL(env)) as $evval |
|
||||
addToEnv($evval; $value[1].value)
|
||||
) //
|
||||
(
|
||||
.value | select(.[0].value == "let*") as $value |
|
||||
(env | pureChildEnv) 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] | { 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
|
||||
| $ev.expr | first |
|
||||
interpret($ev.expr[1:]; $ev.env) | addEnv($ev.env)
|
||||
) //
|
||||
addEnv(env)
|
||||
)
|
||||
end
|
||||
) //
|
||||
(select(.kind == "vector") |
|
||||
[ { env: env, list: .value } | map_with_env ] as $res |
|
||||
{
|
||||
kind: "vector",
|
||||
value: $res | map(.value)
|
||||
} | addEnv($res | last.env)
|
||||
) //
|
||||
(select(.kind == "hashmap") |
|
||||
[ { env: env, list: .value | to_entries } | hmap_with_env ] as $res |
|
||||
{
|
||||
kind: "hashmap",
|
||||
value: $res | map(.value) | from_entries
|
||||
} | addEnv($res | last.env)
|
||||
) //
|
||||
(select(.kind == "symbol") |
|
||||
.value | env_get(env) | addEnv(env)
|
||||
) // 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> " | stderr) |
|
||||
(read_line | rep(env));
|
||||
|
||||
def childEnv(binds; value):
|
||||
{
|
||||
parent: .,
|
||||
environment: [binds, value] | transpose | map({(.[0]): .[1]}) | from_entries
|
||||
};
|
||||
|
||||
# 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"
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
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 else empty end;
|
||||
|
||||
repl(replEnv)
|
Loading…
Reference in New Issue
Block a user