Skip to content

Commit

Permalink
lone: revamp variadic lambdas
Browse files Browse the repository at this point in the history
Get rid of the inelegant variadic flag.
Introduce a function calling convention
where a symbol enveloped in a list
means apply should set it to the
list of remaining arguments.

This implements the rest argument idiom
found in many languages out there
including other lisps.

Update existing tests to match.
Add new tests for the new idiom.
  • Loading branch information
matheusmoreira committed Dec 3, 2023
1 parent 674f9c3 commit f89692e
Show file tree
Hide file tree
Showing 18 changed files with 94 additions and 50 deletions.
3 changes: 1 addition & 2 deletions include/lone/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,6 @@ struct lone_module {
struct lone_function_flags {
bool evaluate_arguments: 1;
bool evaluate_result: 1;
bool variable_arguments: 1;
};

struct lone_function {
Expand All @@ -169,7 +168,7 @@ struct lone_primitive {
struct lone_value *name;
lone_primitive function;
struct lone_value *closure;
struct lone_function_flags flags; /* primitives always accept variable arguments */
struct lone_function_flags flags;
};

struct lone_list {
Expand Down
2 changes: 1 addition & 1 deletion source/lone/lisp.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

void lone_lisp_initialize(struct lone_lisp *lone, struct lone_bytes memory, size_t heap_size, void *stack, struct lone_bytes random)
{
struct lone_function_flags flags = { .evaluate_arguments = 0, .evaluate_result = 0, .variable_arguments = 1 };
struct lone_function_flags flags = { .evaluate_arguments = 0, .evaluate_result = 0 };
struct lone_value *import, *export;

lone_memory_initialize(lone, memory, heap_size, stack);
Expand Down
31 changes: 20 additions & 11 deletions source/lone/lisp/evaluator.c
Original file line number Diff line number Diff line change
Expand Up @@ -120,20 +120,30 @@ static struct lone_value *lone_apply_function(struct lone_lisp *lone, struct lon
{
struct lone_value *new_environment = lone_table_create(lone, 16, function->function.environment),
*names = function->function.arguments, *code = function->function.code,
*value = lone_nil(lone);
*value = lone_nil(lone), *current_name;

/* evaluate each argument if function is configured to do so */
if (function->function.flags.evaluate_arguments) { arguments = lone_evaluate_all(lone, module, environment, arguments); }

if (function->function.flags.variable_arguments) {
if (lone_is_nil(names) || !lone_is_nil(lone_list_rest(names))) {
/* must have exactly one argument: the list of arguments */
linux_exit(-1);
}
while (1) {
current_name = lone_list_first(names);

if (!lone_is_nil(names) && lone_is_list(current_name)) {
/* variadic argument passing: (lambda ((arguments))) (lambda (x y (rest))) */

if (lone_is_nil(current_name)) {
/* no name given: (lambda (x y ())) */ linux_exit(-1);
} else if (!lone_is_nil(lone_list_rest(current_name))) {
/* too many names given: (lambda (x y (rest extra))) */ linux_exit(-1);
} else {
/* valid, set name to the list of remaining arguments */
lone_table_set(lone, new_environment, lone_list_first(current_name), arguments);
break;
}

} else {
/* normal argument passing: (lambda (x y)) */

lone_table_set(lone, new_environment, lone_list_first(names), arguments);
} else {
while (1) {
if (lone_is_nil(names) != lone_is_nil(arguments)) {
/* argument number mismatch: ((lambda (x) x) 10 20), ((lambda (x y) y) 10) */ linux_exit(-1);
} else if (lone_is_nil(names) && lone_is_nil(arguments)) {
Expand All @@ -142,8 +152,7 @@ static struct lone_value *lone_apply_function(struct lone_lisp *lone, struct lon
}

/* valid binding, set name in environment and move on */

lone_table_set(lone, new_environment, lone_list_first(names), lone_list_first(arguments));
lone_table_set(lone, new_environment, current_name, lone_list_first(arguments));

names = lone_list_rest(names);
arguments = lone_list_rest(arguments);
Expand Down
2 changes: 1 addition & 1 deletion source/lone/modules/intrinsic/linux.c
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ void lone_module_linux_initialize(struct lone_lisp *lone, int argc, char **argv,
*count, *arguments, *environment, *auxiliary_vector,
*primitive;

struct lone_function_flags flags = { .evaluate_arguments = true, .evaluate_result = false, .variable_arguments = true };
struct lone_function_flags flags = { .evaluate_arguments = true, .evaluate_result = false };
primitive = lone_primitive_create(lone, "linux_system_call", lone_primitive_linux_system_call, linux_system_call_table, flags);
lone_set_and_export(lone, module, lone_intern_c_string(lone, "system-call"), primitive);

Expand Down
2 changes: 1 addition & 1 deletion source/lone/modules/intrinsic/list.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ void lone_module_list_initialize(struct lone_lisp *lone)
*module = lone_module_for_name(lone, name),
*primitive;

struct lone_function_flags flags = { .evaluate_arguments = true, .evaluate_result = false, .variable_arguments = true };
struct lone_function_flags flags = { .evaluate_arguments = true, .evaluate_result = false };

primitive = lone_primitive_create(lone, "construct", lone_primitive_list_construct, module, flags);
lone_set_and_export(lone, module, lone_intern_c_string(lone, "construct"), primitive);
Expand Down
20 changes: 2 additions & 18 deletions source/lone/modules/intrinsic/lone.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ void lone_module_lone_initialize(struct lone_lisp *lone)
*module = lone_module_for_name(lone, name),
*primitive;

struct lone_function_flags flags = { .evaluate_arguments = false, .evaluate_result = false, .variable_arguments = true };
struct lone_function_flags flags = { .evaluate_arguments = false, .evaluate_result = false };

primitive = lone_primitive_create(lone, "begin", lone_primitive_lone_begin, module, flags);
lone_set_and_export(lone, module, lone_intern_c_string(lone, "begin"), primitive);
Expand Down Expand Up @@ -54,10 +54,7 @@ void lone_module_lone_initialize(struct lone_lisp *lone)
primitive = lone_primitive_create(lone, "lambda_bang", lone_primitive_lone_lambda_bang, module, flags);
lone_set_and_export(lone, module, lone_intern_c_string(lone, "lambda!"), primitive);

primitive = lone_primitive_create(lone, "lambda_star", lone_primitive_lone_lambda_star, module, flags);
lone_set_and_export(lone, module, lone_intern_c_string(lone, "lambda*"), primitive);

flags = (struct lone_function_flags) { .evaluate_arguments = true, .evaluate_result = false, .variable_arguments = true };
flags = (struct lone_function_flags) { .evaluate_arguments = true, .evaluate_result = false };

primitive = lone_primitive_create(lone, "print", lone_primitive_lone_print, module, flags);
lone_set_and_export(lone, module, lone_intern_c_string(lone, "print"), primitive);
Expand Down Expand Up @@ -312,7 +309,6 @@ LONE_PRIMITIVE(lone_lambda)
struct lone_function_flags flags = {
.evaluate_arguments = 1,
.evaluate_result = 0,
.variable_arguments = 0,
};

return lone_primitive_lambda_with_flags(lone, environment, arguments, flags);
Expand All @@ -323,18 +319,6 @@ LONE_PRIMITIVE(lone_lambda_bang)
struct lone_function_flags flags = {
.evaluate_arguments = 0,
.evaluate_result = 0,
.variable_arguments = 0,
};

return lone_primitive_lambda_with_flags(lone, environment, arguments, flags);
}

LONE_PRIMITIVE(lone_lambda_star)
{
struct lone_function_flags flags = {
.evaluate_arguments = 1,
.evaluate_result = 0,
.variable_arguments = 1,
};

return lone_primitive_lambda_with_flags(lone, environment, arguments, flags);
Expand Down
2 changes: 1 addition & 1 deletion source/lone/modules/intrinsic/math.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ void lone_module_math_initialize(struct lone_lisp *lone)
*module = lone_module_for_name(lone, name),
*primitive;

struct lone_function_flags flags = { .evaluate_arguments = true, .evaluate_result = false, .variable_arguments = true };
struct lone_function_flags flags = { .evaluate_arguments = true, .evaluate_result = false };

primitive = lone_primitive_create(lone, "add", lone_primitive_math_add, module, flags);
lone_set_and_export(lone, module, lone_intern_c_string(lone, "+"), primitive);
Expand Down
2 changes: 1 addition & 1 deletion source/lone/modules/intrinsic/table.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ void lone_modules_intrinsic_table_initialize(struct lone_lisp *lone)
*module = lone_module_for_name(lone, name),
*primitive;

struct lone_function_flags flags = { .evaluate_arguments = true, .evaluate_result = false, .variable_arguments = true };
struct lone_function_flags flags = { .evaluate_arguments = true, .evaluate_result = false };

primitive = lone_primitive_create(lone, "table_get", lone_primitive_table_get, module, flags);
lone_set_and_export(lone, module, lone_intern_c_string(lone, "get"), primitive);
Expand Down
2 changes: 1 addition & 1 deletion source/lone/modules/intrinsic/text.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ void lone_module_text_initialize(struct lone_lisp *lone)
*module = lone_module_for_name(lone, name),
*primitive;

struct lone_function_flags flags = { .evaluate_arguments = true, .evaluate_result = false, .variable_arguments = true };
struct lone_function_flags flags = { .evaluate_arguments = true, .evaluate_result = false };

primitive = lone_primitive_create(lone, "join", lone_primitive_text_join, module, flags);
lone_set_and_export(lone, module, lone_intern_c_string(lone, "join"), primitive);
Expand Down
2 changes: 1 addition & 1 deletion source/lone/modules/intrinsic/vector.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ void lone_modules_intrinsic_vector_initialize(struct lone_lisp *lone)
*module = lone_module_for_name(lone, name),
*primitive;

struct lone_function_flags flags = { .evaluate_arguments = true, .evaluate_result = false, .variable_arguments = true };
struct lone_function_flags flags = { .evaluate_arguments = true, .evaluate_result = false };

primitive = lone_primitive_create(lone, "vector_get", lone_primitive_vector_get, module, flags);
lone_set_and_export(lone, module, lone_intern_c_string(lone, "get"), primitive);
Expand Down
1 change: 0 additions & 1 deletion source/lone/value/primitive.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ struct lone_value *lone_primitive_create(
value->primitive.function = function;
value->primitive.closure = closure;
value->primitive.flags = flags;
value->primitive.flags.variable_arguments = 1;
return value;
}

11 changes: 0 additions & 11 deletions test/lone/lambda/*/input

This file was deleted.

11 changes: 11 additions & 0 deletions test/lone/lambda/variadic/0/input
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
(import (lone lambda set print))

(set variadic (lambda ((arguments)) (print arguments)))

(variadic)
(variadic 1)
(variadic 1 2)
(variadic 1 2 3)
(variadic 1 2 3 4)
(variadic 1 2 3 4 5)
(variadic 1 2 3 4 5 6)
File renamed without changes.
13 changes: 13 additions & 0 deletions test/lone/lambda/variadic/1/input
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
(import (lone lambda set print))

(set variadic
(lambda (x (arguments))
(print x)
(print arguments)))

(variadic 1)
(variadic 1 2)
(variadic 1 2 3)
(variadic 1 2 3 4)
(variadic 1 2 3 4 5)
(variadic 1 2 3 4 5 6)
12 changes: 12 additions & 0 deletions test/lone/lambda/variadic/1/output
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
1
nil
1
(2)
1
(2 3)
1
(2 3 4)
1
(2 3 4 5)
1
(2 3 4 5 6)
13 changes: 13 additions & 0 deletions test/lone/lambda/variadic/2/input
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
(import (lone lambda set print))

(set variadic
(lambda (x y (arguments))
(print x)
(print y)
(print arguments)))

(variadic 1 2)
(variadic 1 2 3)
(variadic 1 2 3 4)
(variadic 1 2 3 4 5)
(variadic 1 2 3 4 5 6)
15 changes: 15 additions & 0 deletions test/lone/lambda/variadic/2/output
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
1
2
nil
1
2
(3)
1
2
(3 4)
1
2
(3 4 5)
1
2
(3 4 5 6)

0 comments on commit f89692e

Please sign in to comment.