Просмотр исходного кода

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.
master
Felix Brendel 7 лет назад
Родитель
Сommit
912ec19373
6 измененных файлов: 61 добавлений и 13 удалений
  1. +7
    -0
      bin/tests/evaluation_of_default_args.slime
  2. +41
    -8
      manual/manual.org
  3. +1
    -1
      src/error.cpp
  4. +8
    -4
      src/eval.cpp
  5. +3
    -0
      src/memory.cpp
  6. +1
    -0
      src/testing.cpp

+ 7
- 0
bin/tests/evaluation_of_default_args.slime Просмотреть файл

@@ -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 ()))))

+ 41
- 8
manual/manual.org Просмотреть файл

@@ -198,6 +198,7 @@ The programmer can also define their own special forms using =special-lambda= an
be explained later.

* Symbols and keywords
* Truthyness
* Lambdas
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
@@ -327,18 +328,19 @@ call to that function will look like.

** Functions with keyword arguments
A sometimes more convenient way of passing arguments to a function is using keyword arguments. Using
keyword arguments a function call could look like this: \[\texttt{(function :arg1 value1 :arg2
value2)}\] here the function accepts two arguments named =arg1= and =arg2=. The user of this
keyword arguments a function call could look like this: \[\texttt{(function :arg1 value1 :arg2
value2)}\] here the function accepts two arguments named =arg1= and =arg2=. The user of this
function can see more clearly excatly which argument will be assigned wich value. This notation also
allows for switching the argument order. The following function call is equivalent to the call
allows for switching the argument order. The following function call is equivalent to the call
above. \[\texttt{(function :arg2 value2 :arg1 value1)}\].

For this to work however, the function must be defined to accept these keyword arguments. To do this
the special marker =:keys= has to be inserted into the argument list of a =lambda= or a function
=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
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]].
=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
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]]. Important note: keyword arguments must be
defined and supplied after all the regular arguments.

{{{slime_header}}}
#+name: code:keyword-args
@@ -361,10 +363,41 @@ example of all of this can be seen in [[code:keyword-args]].
: 54
: 54

** 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

** Functions with rest arguments

* Environments
* Built-in functions


+ 1
- 1
src/error.cpp Просмотреть файл

@@ -14,7 +14,7 @@ proc create_error(const char* c_file_name, int c_file_line, Lisp_Object* type, S
delete_error();
debug_break();

visualize_lisp_machine();
// visualize_lisp_machine();

using Globals::error;
error = new(Error);


+ 8
- 4
src/eval.cpp Просмотреть файл

@@ -24,11 +24,11 @@ proc apply_arguments_to_function(Lisp_Object* arguments, Function* function) ->

if (arguments == Memory::nil)
goto checks;

// keyword arguments: use all given ones and keep track of the
// added ones (array list), if end of parameters in encountered or
// something that is not a keyword is encountered or a keyword
// that is not recognized is encoutered, jump out of the loop.

while (Memory::get_type(arguments->value.pair.first) == Lisp_Object_Type::Keyword) {
// check if this one is even an accepted keyword
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
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);
try sym = Memory::get_or_create_lisp_object_symbol(arguments->value.pair.first->value.symbol.identifier);
// 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);

@@ -257,9 +258,11 @@ proc parse_argument_list(Lisp_Object* arguments, Function* function) -> void {
// would be an error
next = next->value.pair.rest;
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,
arguments->value.pair.first->value.symbol.identifier,
next->value.pair.first);
ret);
arguments = next->value.pair.rest;
} else {
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 {
Lisp_Object* result;
try result = eval_expr(expression, env);

return result != Memory::nil;
}



+ 3
- 0
src/memory.cpp Просмотреть файл

@@ -283,6 +283,9 @@ namespace Memory {
}

proc copy_lisp_object(Lisp_Object* n) -> Lisp_Object* {
if (n == nil || n == t)
return n;

Lisp_Object* target;
try target = create_lisp_object();
*target = *n;


+ 1
- 0
src/testing.cpp Просмотреть файл

@@ -635,6 +635,7 @@ proc run_all_tests() -> bool {

printf("\n-- Test Files --\n");

invoke_test_script("evaluation_of_default_args");
invoke_test_script("lexical_scope");
invoke_test_script("class_macro");
invoke_test_script("sicp");


Загрузка…
Отмена
Сохранить