diff --git a/httpd/fx/config/routes.kc3 b/httpd/fx/config/routes.kc3
index 11b1f07..08872ac 100644
--- a/httpd/fx/config/routes.kc3
+++ b/httpd/fx/config/routes.kc3
@@ -1,4 +1,5 @@
def HTTPd.routes = []
def_route("/fx/", FXController.route)
-def_route("/", static_controller)
+def_route("/file/", static_controller("./fx/"))
+def_route("/", static_controller("./static/"))
diff --git a/lib/kc3/0.1/httpd.kc3 b/lib/kc3/0.1/httpd.kc3
index d3dba6d..92ab2ad 100644
--- a/lib/kc3/0.1/httpd.kc3
+++ b/lib/kc3/0.1/httpd.kc3
@@ -14,8 +14,6 @@ defmodule HTTPd do
require Str
require URL
- def root_dir = "./static"
-
def load_directory = fn (dir) {
if File.exists?(dir) && File.is_directory?(dir) do
files = File.list(dir)
@@ -183,52 +181,6 @@ defmodule HTTPd do
%HTTP.Response{code: 405, body: body}
}
- def directory_page = fn (request) {
- files = List.sort(File.list(root_dir + request.url))
- file_li = HTTPd.fn (file) {
- slash = if Str.ends_with?(request.url, "/") do "" else "/" end
- real_path = "#{root_dir}#{request.url}#{slash}#{file}"
- dir? = File.is_directory?(real_path)
- dir_slash = if dir? do "/" else "" end
- path = "#{request.url}#{slash}#{file}#{dir_slash}"
- mode = if dir? do "dr-xr-xr-x" else "-r--r--r--" end
- "<li>#{mode} <a href=\"#{URL.escape(path)}\">#{HTML.escape(file)}</a>#{dir_slash}</li>\n"
- }
- body = """<html>
- <head>
- <title>Index of #{request.url}</title>
- <style type="text/css">
- ul { font-family: monospace; }
- </style>
- </head>
- <body>
- <h1>Index of #{request.url}</h1>
- <ul>
- #{str(List.map(files, file_li))}
- </ul>
- </body>
-</html>
-"""
- %HTTP.Response{body: body}
- }
-
- def show_page = fn (request) {
- ext = File.ext(request.url)
- path = root_dir + request.url
- if File.exists?(path) do
- mime = HTTP.mime_type(ext)
- stat = File.stat(path)
- last_modified = Str.ftime(stat.st_mtim, "%a, %d %b %G %T %Z")
- headers = [{"Content-Type", (Str) mime},
- {"Content-Length", (Str) stat.st_size},
- {"Last-Modified", last_modified}]
- body = File.open_r(path)
- %HTTP.Response{body: body, headers: headers}
- else
- error_404_page(request)
- end
- }
-
def routes = []
def def_route = fn (path, controller) {
@@ -254,25 +206,72 @@ defmodule HTTPd do
}
}
- def static_controller = fn (request) {
- render = if (! Str.starts_with?(request.url, "/") ||
- Str.has_str?(request.url, "/..")) do
- error_404_page
- else
- path = root_dir + request.url
- if ! File.exists?(path) do
- error_404_page
- else
- if File.is_directory?(path) do
- directory_page
- else
- show_page
- end
- end
- end
- render(request)
+ def static_controller = fn (root_dir) {
+ directory_page = fn (request) {
+ files = List.sort(File.list(root_dir + request.url))
+ file_li = HTTPd.fn (file) {
+ slash = if Str.ends_with?(request.url, "/") do "" else "/" end
+ real_path = "#{root_dir}#{request.url}#{slash}#{file}"
+ dir? = File.is_directory?(real_path)
+ dir_slash = if dir? do "/" else "" end
+ path = "#{request.url}#{slash}#{file}#{dir_slash}"
+ mode = if dir? do "dr-xr-xr-x" else "-r--r--r--" end
+ "<li>#{mode} <a href=\"#{URL.escape(path)}\">#{HTML.escape(file)}</a>#{dir_slash}</li>\n"
+ }
+ body = """<html>
+ <head>
+ <title>Index of #{request.url}</title>
+ <style type="text/css">
+ ul { font-family: monospace; }
+ </style>
+ </head>
+ <body>
+ <h1>Index of #{request.url}</h1>
+ <ul>
+ #{str(List.map(files, file_li))}
+ </ul>
+ </body>
+</html>
+"""
+ %HTTP.Response{body: body}
+ }
+ show_page = fn (request) {
+ ext = File.ext(request.url)
+ path = root_dir + request.url
+ if File.exists?(path) do
+ mime = HTTP.mime_type(ext)
+ stat = File.stat(path)
+ last_modified = Str.ftime(stat.st_mtim, "%a, %d %b %G %T %Z")
+ headers = [{"Content-Type", (Str) mime},
+ {"Content-Length", (Str) stat.st_size},
+ {"Last-Modified", last_modified}]
+ body = File.open_r(path)
+ %HTTP.Response{body: body, headers: headers}
+ else
+ error_404_page(request)
+ end
+ }
+ fn (request) {
+ render = if (! Str.starts_with?(request.url, "/") ||
+ Str.has_str?(request.url, "/../") ||
+ Str.ends_with?(request.url, "/..")) do
+ error_404_page
+ else
+ path = root_dir + request.url
+ if ! File.exists?(path) do
+ error_404_page
+ else
+ if File.is_directory?(path) do
+ directory_page
+ else
+ show_page
+ end
+ end
+ end
+ render(request)
+ }
}
- def_route("/", static_controller)
+ def_route("/", static_controller("./static"))
end
diff --git a/libkc3/binding.c b/libkc3/binding.c
index ac27d1e..4058492 100644
--- a/libkc3/binding.c
+++ b/libkc3/binding.c
@@ -95,3 +95,25 @@ s_binding * binding_new (const s_sym *name, s_binding *next)
}
return binding;
}
+
+s_binding * binding_new_copy (const s_binding *src)
+{
+ s_binding **b;
+ s_binding *binding;
+ const s_binding *s;
+ binding = NULL;
+ b = &binding;
+ s = src;
+ while (s) {
+ if (! (*b = binding_new(s->name, NULL)))
+ goto clean;
+ if (! tag_init_copy(&(*b)->value, &s->value))
+ goto clean;
+ b = &(*b)->next;
+ s = s->next;
+ }
+ return binding;
+ clean:
+ binding_delete_all(binding);
+ return NULL;
+}
diff --git a/libkc3/binding.h b/libkc3/binding.h
index 730f9de..640c791 100644
--- a/libkc3/binding.h
+++ b/libkc3/binding.h
@@ -25,6 +25,7 @@ s_binding * binding_init (s_binding *binding, const s_sym *name,
s_binding * binding_delete (s_binding *binding);
void binding_delete_all (s_binding *binding);
s_binding * binding_new (const s_sym *name, s_binding *next);
+s_binding * binding_new_copy (const s_binding *src);
/* Observers. */
const s_tag * binding_get (const s_binding *binding, const s_sym *name);
diff --git a/libkc3/buf_inspect.c b/libkc3/buf_inspect.c
index 9258bd8..cf56821 100644
--- a/libkc3/buf_inspect.c
+++ b/libkc3/buf_inspect.c
@@ -271,6 +271,46 @@ sw buf_inspect_array_size (s_pretty *pretty, const s_array *array)
return r;
}
+sw buf_inspect_binding (s_buf *buf, const s_binding *binding)
+{
+ const s_binding *b;
+ s_pretty_save pretty_save;
+ sw r;
+ sw result = 0;
+ assert(buf);
+ pretty_save_init(&pretty_save, &buf->pretty);
+ if ((r = buf_write_1(buf, "[")) < 0)
+ goto clean;
+ result += r;
+ pretty_indent_from_column(&buf->pretty, 0);
+ b = binding;
+ while (b) {
+ if ((r = buf_inspect_ident_sym(buf, b->name)) < 0)
+ goto clean;
+ result += r;
+ if ((r = buf_write_1(buf, ": ")) < 0)
+ goto clean;
+ result += r;
+ if ((r = buf_inspect_tag(buf, &b->value)) < 0)
+ goto clean;
+ result += r;
+ b = b->next;
+ if (b) {
+ if ((r = buf_write_1(buf, ",\n")) < 0)
+ goto clean;
+ result += r;
+ }
+ }
+ if ((r = buf_write_1(buf, "]")) < 0)
+ goto clean;
+ result += r;
+ pretty_save_clean(&pretty_save, &buf->pretty);
+ return result;
+ clean:
+ pretty_save_clean(&pretty_save, &buf->pretty);
+ return r;
+}
+
sw buf_inspect_block (s_buf *buf, const s_block *block)
{
s_pretty_save pretty_save;
@@ -2088,6 +2128,40 @@ sw buf_inspect_fn_size (s_pretty *pretty, const s_fn *fn)
return result;
}
+sw buf_inspect_frame (s_buf *buf, const s_frame *frame)
+{
+ const s_frame *f;
+ s_pretty_save pretty_save;
+ sw r;
+ sw result = 0;
+ assert(buf);
+ pretty_save_init(&pretty_save, &buf->pretty);
+ if ((r = buf_write_1(buf, "[")) < 0)
+ goto clean;
+ result += r;
+ pretty_indent_from_column(&buf->pretty, 0);
+ f = frame;
+ while (f) {
+ if ((r = buf_inspect_binding(buf, f->bindings)) < 0)
+ goto clean;
+ result += r;
+ f = f->next;
+ if (f) {
+ if ((r = buf_write_1(buf, ",\n")) < 0)
+ goto clean;
+ result += r;
+ }
+ }
+ if ((r = buf_write_1(buf, "]")) < 0)
+ goto clean;
+ result += r;
+ pretty_save_clean(&pretty_save, &buf->pretty);
+ return result;
+ clean:
+ pretty_save_clean(&pretty_save, &buf->pretty);
+ return r;
+}
+
sw buf_inspect_ident (s_buf *buf, const s_ident *ident)
{
sw r;
diff --git a/libkc3/buf_inspect.h b/libkc3/buf_inspect.h
index 1bcb97e..8cf06b0 100644
--- a/libkc3/buf_inspect.h
+++ b/libkc3/buf_inspect.h
@@ -130,6 +130,7 @@ sw buf_inspect_fn_pattern (s_buf *buf, const s_list *pattern);
sw buf_inspect_fn_pattern_size (s_pretty *pretty,
const s_list *pattern);
sw buf_inspect_fn_size (s_pretty *pretty, const s_fn *fn);
+sw buf_inspect_frame (s_buf *buf, const s_frame *frame);
sw buf_inspect_ident (s_buf *buf, const s_ident *ident);
sw buf_inspect_ident_size (s_pretty *pretty, const s_ident *ident);
sw buf_inspect_ident_sym (s_buf *buf, const s_sym *sym);
diff --git a/libkc3/env.c b/libkc3/env.c
index fe9dad0..414146b 100644
--- a/libkc3/env.c
+++ b/libkc3/env.c
@@ -659,6 +659,7 @@ bool env_eval_call_fn_args (s_env *env, const s_fn *fn,
s_list *args = NULL;
const s_list *args_final = NULL;
s_fn_clause *clause;
+ s_frame *env_frame;
s_frame frame;
const s_sym *module;
s_list *search_modules;
@@ -675,6 +676,7 @@ bool env_eval_call_fn_args (s_env *env, const s_fn *fn,
module = &g_sym_KC3;
if (! env_module_search_modules(env, &module, &env->search_modules))
return false;
+ env_frame = env->frame;
clause = fn->clauses;
if (arguments) {
if (fn->macro || fn->special_operator)
@@ -688,7 +690,7 @@ bool env_eval_call_fn_args (s_env *env, const s_fn *fn,
args_final = args;
}
while (clause) {
- if (! frame_init(&frame, env->frame)) {
+ if (! frame_init(&frame, fn->frame)) {
list_delete_all(env->search_modules);
env->search_modules = search_modules;
return false;
@@ -697,7 +699,8 @@ bool env_eval_call_fn_args (s_env *env, const s_fn *fn,
if (env_eval_equal_list(env, fn->macro || fn->special_operator,
clause->pattern, args_final, &tmp))
break;
- env->frame = frame_clean(&frame);
+ env->frame = env_frame;
+ frame_clean(&frame);
clause = clause->next_clause;
}
if (! clause) {
@@ -726,14 +729,16 @@ bool env_eval_call_fn_args (s_env *env, const s_fn *fn,
list_delete_all(tmp);
list_delete_all(env->search_modules);
env->search_modules = search_modules;
- env->frame = frame_clean(&frame);
+ env->frame = env_frame;
+ frame_clean(&frame);
return false;
}
list_delete_all(args);
list_delete_all(tmp);
list_delete_all(env->search_modules);
env->search_modules = search_modules;
- env->frame = frame_clean(&frame);
+ env->frame = env_frame;
+ frame_clean(&frame);
if (fn->macro) {
if (! env_eval_tag(env, &tag, dest)) {
tag_clean(&tag);
@@ -1276,6 +1281,8 @@ bool env_eval_fn (s_env *env, const s_fn *fn, s_tag *dest)
return false;
if (! tmp.data.fn.module)
tmp.data.fn.module = env->current_defmodule;
+ if (! (tmp.data.fn.frame = frame_new_copy(env->frame)))
+ return false;
*dest = tmp;
return true;
}
@@ -1297,6 +1304,11 @@ bool env_eval_ident (s_env *env, const s_ident *ident, s_tag *dest)
err_write_1("env_eval_ident: unbound ident: ");
err_inspect_ident(ident);
err_write_1("\n");
+ if (true) {
+ err_write_1("frame: ");
+ err_inspect_frame(env->frame);
+ err_write_1("\n");
+ }
assert(! "env_eval_ident: unbound ident");
return false;
}
diff --git a/libkc3/fn.c b/libkc3/fn.c
index 0f24da9..9021146 100644
--- a/libkc3/fn.c
+++ b/libkc3/fn.c
@@ -19,6 +19,7 @@
#include "buf_parse.h"
#include "fn.h"
#include "fn_clause.h"
+#include "frame.h"
#include "list.h"
#include "sym.h"
#include "tag_type.h"
@@ -41,6 +42,7 @@ void fn_clean (s_fn *fn)
{
assert(fn);
fn_clause_delete_all(fn->clauses);
+ frame_delete_all(fn->frame);
}
void fn_delete (s_fn *fn)
@@ -115,6 +117,11 @@ s_fn * fn_init_copy (s_fn *fn, const s_fn *src)
tmp.clauses = fn_clause_new_copy(src->clauses);
tmp.macro = src->macro;
tmp.special_operator = src->special_operator;
+ if (src->frame &&
+ ! (tmp.frame = frame_new_copy(src->frame))) {
+ fn_clean(&tmp);
+ return NULL;
+ }
*fn = tmp;
return fn;
}
diff --git a/libkc3/frame.c b/libkc3/frame.c
index a7fb881..cd37217 100644
--- a/libkc3/frame.c
+++ b/libkc3/frame.c
@@ -170,6 +170,28 @@ s_frame * frame_new (s_frame *next)
return frame;
}
+s_frame * frame_new_copy (const s_frame *src)
+{
+ s_frame **f;
+ s_frame *frame;
+ const s_frame *s;
+ frame = NULL;
+ f = &frame;
+ s = src;
+ while (s) {
+ *f = frame_new(NULL);
+ if (s->bindings &&
+ ! ((*f)->bindings = binding_new_copy(s->bindings)))
+ goto clean;
+ f = &(*f)->next;
+ s = s->next;
+ }
+ return frame;
+ clean:
+ frame_delete_all(frame);
+ return NULL;
+}
+
s_frame * frame_replace (s_frame *frame, const s_sym *sym,
s_tag *value)
{
diff --git a/libkc3/frame.h b/libkc3/frame.h
index 503eabf..5c924f3 100644
--- a/libkc3/frame.h
+++ b/libkc3/frame.h
@@ -21,6 +21,7 @@ s_frame * frame_init (s_frame *frame, s_frame *next);
/* Constructors. */
s_frame * frame_new (s_frame *next);
+s_frame * frame_new_copy (const s_frame *src);
/* Destructors. */
s_frame * frame_delete (s_frame *frame);
diff --git a/libkc3/io.c b/libkc3/io.c
index fc68519..f1a0985 100644
--- a/libkc3/io.c
+++ b/libkc3/io.c
@@ -210,6 +210,7 @@ DEF_ERR_IO_INSPECT(facts_spec, const p_facts_spec)
DEF_ERR_IO_INSPECT(fn, const s_fn *)
DEF_ERR_IO_INSPECT(fn_clause, const s_fn_clause *)
DEF_ERR_IO_INSPECT(fn_pattern, const s_list *)
+DEF_ERR_IO_INSPECT(frame, const s_frame *)
DEF_ERR_IO_INSPECT(ident, const s_ident *)
DEF_ERR_IO_INSPECT(list, const s_list * const *)
DEF_ERR_IO_INSPECT(map, const s_map *)
diff --git a/libkc3/io.h b/libkc3/io.h
index d86cc67..047005c 100644
--- a/libkc3/io.h
+++ b/libkc3/io.h
@@ -56,6 +56,7 @@ PROTOTYPES_ERR_IO_INSPECT(facts_spec, const p_facts_spec);
PROTOTYPES_ERR_IO_INSPECT(fn, const s_fn *);
PROTOTYPES_ERR_IO_INSPECT(fn_clause, const s_fn_clause *);
PROTOTYPES_ERR_IO_INSPECT(fn_pattern, const s_list *);
+PROTOTYPES_ERR_IO_INSPECT(frame, const s_frame *);
PROTOTYPES_ERR_IO_INSPECT(ident, const s_ident *);
PROTOTYPES_ERR_IO_INSPECT(integer, const s_integer *);
PROTOTYPES_ERR_IO_INSPECT(list, const s_list * const *);
diff --git a/libkc3/types.h b/libkc3/types.h
index 43fd0a5..d30961f 100644
--- a/libkc3/types.h
+++ b/libkc3/types.h
@@ -406,6 +406,7 @@ struct fn {
bool macro;
bool special_operator;
const s_sym *module;
+ s_frame *frame;
};
struct ident {
diff --git a/test/httpd/config/routes.kc3 b/test/httpd/config/routes.kc3
index 1834cf5..f78ee81 100644
--- a/test/httpd/config/routes.kc3
+++ b/test/httpd/config/routes.kc3
@@ -1,4 +1,4 @@
def HTTPd.routes = []
def_route("/doc/", DocController.route)
-def_route("/", static_controller)
+def_route("/", static_controller("./static/"))
diff --git a/test/ikc3/fn.kc3 b/test/ikc3/fn.kc3
index dd4c9af..0cbda38 100644
--- a/test/ikc3/fn.kc3
+++ b/test/ikc3/fn.kc3
@@ -41,3 +41,9 @@ do
end
f(2)
end
+quote f = fn (x) { fn (y) { x * y } }
+f = fn (x) { fn (y) { x * y } }
+quote g = f(2)
+g = f(2)
+quote g(3)
+g(3)
diff --git a/test/ikc3/fn.out.expected b/test/ikc3/fn.out.expected
index 7a6dd80..d206a22 100644
--- a/test/ikc3/fn.out.expected
+++ b/test/ikc3/fn.out.expected
@@ -35,4 +35,10 @@ do
f(2)
end
Hello, world !
-4
\ No newline at end of file
+4
+f = fn (x) { fn (y) { x * y } }
+fn (x) { fn (y) { x * y } }
+g = f(2)
+fn (y) { x * y }
+g(3)
+6