coly_lisp_object now dows not create new nil and t values anymore

Fixed an error where a nil value could not be used as the default
value as a keyword argument since coly_lisp_object would be invoked
before assigning nil as the default argument, producing a separate nil
value, which then fails the nil tests becase it lives in a different
location as Memory::nil.
This commit is contained in:
Felix Brendel
2019-05-17 02:11:20 +02:00
parent 03a2c81aa5
commit 912ec19373
6 changed files with 63 additions and 15 deletions
@@ -0,0 +1,7 @@
((lambda (:keys k1 :defaults-to (+ 1 2 3))
(assert (= k1 6))))
((lambda (:keys k1 :defaults-to ())
(when k1
(assert ()))
(assert (= k1 ()))))
+37 -4
View File
@@ -198,6 +198,7 @@ The programmer can also define their own special forms using =special-lambda= an
be explained later. be explained later.
* Symbols and keywords * Symbols and keywords
* Truthyness
* Lambdas * Lambdas
Slime allows for creating anonymous functions called *lambdas*. We did not talk about binding Slime allows for creating anonymous functions called *lambdas*. We did not talk about binding
variables, we will do this in [[Define]], but we can still use lambdas now. Remember that Lisp variables, we will do this in [[Define]], but we can still use lambdas now. Remember that Lisp
@@ -338,7 +339,8 @@ the special marker =:keys= has to be inserted into the argument list of a =la
=define=. All following arguments *must* be supplied as keyword arguments, /unless/ they are also =define=. All following arguments *must* be supplied as keyword arguments, /unless/ they are also
supplied with a default value, in which case they do not need to be supplied. To attach a default supplied with a default value, in which case they do not need to be supplied. To attach a default
value to a keyword argument, insert =:defaults-to <value>= after the keyword argument name. An value to a keyword argument, insert =:defaults-to <value>= after the keyword argument name. An
example of all of this can be seen in [[code:keyword-args]]. example of all of this can be seen in [[code:keyword-args]]. Important note: keyword arguments must be
defined and supplied after all the regular arguments.
{{{slime_header}}} {{{slime_header}}}
#+name: code:keyword-args #+name: code:keyword-args
@@ -361,10 +363,41 @@ example of all of this can be seen in [[code:keyword-args]].
: 54 : 54
: 54 : 54
** Functions with rest arguments ** Functions with rest arguments
If the programmer wants to create a function that can accept any number of arguments, they can use
the =rest= argument. It is defined after the special marker =:rest= and after the rest argument, no
other arguments can be defined. In the execution of the fuction, the rest arguent will be assigned
to a list containing all the supplied values. The rest argument can be used in conjunction with the
other argument types, regular arguments and keyword arguments.
{{{slime_header}}}
#+name: code:rest-args
#+caption: A more complex functoin definition using keyword arguments
#+begin_src slime
(define (execute-operation operation
:keys
do-logging :defaults-to ()
:rest values)
(define result (apply operation values))
(when do-logging
(printf "Executing operation"
operation
"agains values yielded:"
result))
result)
(printf (execute-operation '+ 1 2 3))
(printf (execute-operation '*
:do-logging t
10 11))
#+end_src
#+RESULTS: code:rest-args
: evaluates to =>
: 6
: Executing operation [C-function] agains values yielded: 110
: 110
* Environments * Environments
* Built-in functions * Built-in functions
+1 -1
View File
@@ -14,7 +14,7 @@ proc create_error(const char* c_file_name, int c_file_line, Lisp_Object* type, S
delete_error(); delete_error();
debug_break(); debug_break();
visualize_lisp_machine(); // visualize_lisp_machine();
using Globals::error; using Globals::error;
error = new(Error); error = new(Error);
+8 -4
View File
@@ -24,11 +24,11 @@ proc apply_arguments_to_function(Lisp_Object* arguments, Function* function) ->
if (arguments == Memory::nil) if (arguments == Memory::nil)
goto checks; goto checks;
// keyword arguments: use all given ones and keep track of the // keyword arguments: use all given ones and keep track of the
// added ones (array list), if end of parameters in encountered or // added ones (array list), if end of parameters in encountered or
// something that is not a keyword is encountered or a keyword // something that is not a keyword is encountered or a keyword
// that is not recognized is encoutered, jump out of the loop. // that is not recognized is encoutered, jump out of the loop.
while (Memory::get_type(arguments->value.pair.first) == Lisp_Object_Type::Keyword) { while (Memory::get_type(arguments->value.pair.first) == Lisp_Object_Type::Keyword) {
// check if this one is even an accepted keyword // check if this one is even an accepted keyword
bool accepted = false; bool accepted = false;
@@ -80,8 +80,9 @@ proc apply_arguments_to_function(Lisp_Object* arguments, Function* function) ->
} }
// if not set it and then add it to the array list // if not set it and then add it to the array list
try sym = Memory::get_or_create_lisp_object_symbol(arguments->value.pair.first->value.symbol.identifier), try sym = Memory::get_or_create_lisp_object_symbol(arguments->value.pair.first->value.symbol.identifier);
define_symbol(sym, arguments->value.pair.rest->value.pair.first, new_env); // NOTE(Felix): It seems we do not need to evaluate the argument here...
try define_symbol(sym, arguments->value.pair.rest->value.pair.first, new_env);
append_to_array_list(read_in_keywords, arguments->value.pair.first->value.symbol.identifier); append_to_array_list(read_in_keywords, arguments->value.pair.first->value.symbol.identifier);
@@ -257,9 +258,11 @@ proc parse_argument_list(Lisp_Object* arguments, Function* function) -> void {
// would be an error // would be an error
next = next->value.pair.rest; next = next->value.pair.rest;
if (Memory::get_type(next) == Lisp_Object_Type::Pair) { if (Memory::get_type(next) == Lisp_Object_Type::Pair) {
Lisp_Object* ret;
try_void ret = eval_expr(next->value.pair.first, function->parent_environment);
append_to_keyword_argument_list(function->keyword_arguments, append_to_keyword_argument_list(function->keyword_arguments,
arguments->value.pair.first->value.symbol.identifier, arguments->value.pair.first->value.symbol.identifier,
next->value.pair.first); ret);
arguments = next->value.pair.rest; arguments = next->value.pair.rest;
} else { } else {
create_parsing_error("Expecting a value after 'defaults-to'"); create_parsing_error("Expecting a value after 'defaults-to'");
@@ -426,6 +429,7 @@ proc eval_expr(Lisp_Object* node, Environment* env) -> Lisp_Object* {
proc is_truthy(Lisp_Object* expression, Environment* env) -> bool { proc is_truthy(Lisp_Object* expression, Environment* env) -> bool {
Lisp_Object* result; Lisp_Object* result;
try result = eval_expr(expression, env); try result = eval_expr(expression, env);
return result != Memory::nil; return result != Memory::nil;
} }
+3
View File
@@ -283,6 +283,9 @@ namespace Memory {
} }
proc copy_lisp_object(Lisp_Object* n) -> Lisp_Object* { proc copy_lisp_object(Lisp_Object* n) -> Lisp_Object* {
if (n == nil || n == t)
return n;
Lisp_Object* target; Lisp_Object* target;
try target = create_lisp_object(); try target = create_lisp_object();
*target = *n; *target = *n;
+1
View File
@@ -635,6 +635,7 @@ proc run_all_tests() -> bool {
printf("\n-- Test Files --\n"); printf("\n-- Test Files --\n");
invoke_test_script("evaluation_of_default_args");
invoke_test_script("lexical_scope"); invoke_test_script("lexical_scope");
invoke_test_script("class_macro"); invoke_test_script("class_macro");
invoke_test_script("sicp"); invoke_test_script("sicp");