fixed keyword args when appling to a function

This commit is contained in:
Felix Brendel
2019-07-17 12:13:03 +02:00
parent 7d282238bf
commit df3661d77e
4 changed files with 170 additions and 136 deletions
+3
View File
@@ -15,3 +15,6 @@
(printf "addr-of test:" (addr-of test)) (printf "addr-of test:" (addr-of test))
(test :ij :yes) (test :ij :yes)
(define (tt :keys a b :rest r)
(printf a b r))
+2 -1
View File
@@ -9,7 +9,8 @@ pushd bin
taskkill /F /IM %exeName% > NUL 2> NUL taskkill /F /IM %exeName% > NUL 2> NUL
echo ---------- Compiling ---------- echo ---------- Compiling ----------
call ..\timecmd cl ../src/main.cpp /std:c++latest /Fe%exeName% /W3 /Zi /nologo /EHsc /link /NODEFAULTLIB:libucrt libucrtd.lib rem call ..\timecmd cl ../src/main.cpp /std:c++latest /Fe%exeName% /W3 /Zi /nologo /EHsc /link /NODEFAULTLIB:libucrt libucrtd.lib
call ..\timecmd clang++ ../src/main.cpp -o %exeName% -O3 -std=c++17
popd popd
if %errorlevel% == 0 ( if %errorlevel% == 0 (
+57 -27
View File
@@ -3,12 +3,15 @@ proc apply_arguments_to_function(Lisp_Object* arguments, Function* function) ->
try new_env = Memory::create_child_environment(function->parent_environment); try new_env = Memory::create_child_environment(function->parent_environment);
Lisp_Object* sym, *val; // used as temp storage to use `try` Lisp_Object* sym, *val; // used as temp storage to use `try`
String_Array_List* read_in_keywords;
int obligatory_keywords_count = 0;
int read_obligatory_keywords_count = 0;
// positional arguments proc read_poitional_args = [&]() -> void {
for (int i = 0; i < function->positional_arguments->next_index; ++i) { for (int i = 0; i < function->positional_arguments->next_index; ++i) {
if (Memory::get_type(arguments) != Lisp_Object_Type::Pair) { if (Memory::get_type(arguments) != Lisp_Object_Type::Pair) {
create_wrong_number_of_arguments_error(function->positional_arguments->next_index, i); create_wrong_number_of_arguments_error(function->positional_arguments->next_index, i);
return nullptr; return;
} }
// TODO(Felix): here we create new lisp_object_symbols from // TODO(Felix): here we create new lisp_object_symbols from
// their identifiers but before we converted them to // their identifiers but before we converted them to
@@ -16,7 +19,7 @@ proc apply_arguments_to_function(Lisp_Object* arguments, Function* function) ->
// NOTE(Felix): We have to copy all the arguments, otherwise // NOTE(Felix): We have to copy all the arguments, otherwise
// we change the program code. // we change the program code.
try sym = Memory::get_or_create_lisp_object_symbol(function->positional_arguments->identifiers[i]); try_void sym = Memory::get_or_create_lisp_object_symbol(function->positional_arguments->identifiers[i]);
define_symbol( define_symbol(
sym, sym,
Memory::copy_lisp_object_except_pairs(arguments->value.pair.first), Memory::copy_lisp_object_except_pairs(arguments->value.pair.first),
@@ -24,16 +27,27 @@ proc apply_arguments_to_function(Lisp_Object* arguments, Function* function) ->
arguments = arguments->value.pair.rest; arguments = arguments->value.pair.rest;
} }
};
String_Array_List* read_in_keywords = create_String_array_list(); proc read_keyword_args = [&]() -> void {
if (arguments == Memory::nil)
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.
read_in_keywords = create_String_array_list();
if (arguments == Memory::nil)
return;
// find out how many keyword args we /have/ to read
for (int i = 0; i < function->keyword_arguments->next_index; ++i) {
if (function->keyword_arguments->values->data[i] == nullptr)
++obligatory_keywords_count;
else
break;
}
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;
@@ -47,14 +61,18 @@ proc apply_arguments_to_function(Lisp_Object* arguments, Function* function) ->
} }
} }
if (!accepted) { if (!accepted) {
// TODO(Felix): if we are actually done with all the // NOTE(Felix): if we are actually done with all the
// necessary keywords then we have to count the rest // necessary keywords then we have to count the rest
// as :rest here, instead od always creating an error // as :rest here, instead od always creating an error
// (special case with default variables) // (special case with default variables)
if (read_obligatory_keywords_count == obligatory_keywords_count)
return;
create_generic_error( create_generic_error(
"The function does not take the keyword argument ':%s'", "The function does not take the keyword argument ':%s'\n"
&(arguments->value.pair.first->value.symbol.identifier)); "and not all required keyword arguments have been read\n"
return nullptr; "in to potentially count it as the rest argument.",
&(arguments->value.pair.first->value.symbol.identifier->data));
return;
} }
// check if it was already read in // check if it was already read in
@@ -63,14 +81,16 @@ proc apply_arguments_to_function(Lisp_Object* arguments, Function* function) ->
arguments->value.pair.first->value.symbol.identifier, arguments->value.pair.first->value.symbol.identifier,
read_in_keywords->data[i])) read_in_keywords->data[i]))
{ {
// TODO(Felix): if we are actually done with all the // NOTE(Felix): if we are actually done with all the
// necessary keywords then we have to count the rest // necessary keywords then we have to count the rest
// as :rest here, instead od always creating an error // as :rest here, instead od always creating an error
// (special case with default variables) // (special case with default variables)
if (read_obligatory_keywords_count == obligatory_keywords_count)
return;
create_generic_error( create_generic_error(
"The function already read the keyword argument ':%s'", "The function already read the keyword argument ':%s'",
&(arguments->value.pair.first->value.symbol.identifier)); &(arguments->value.pair.first->value.symbol.identifier->data));
return nullptr; return;
} }
} }
@@ -80,19 +100,20 @@ proc apply_arguments_to_function(Lisp_Object* arguments, Function* function) ->
if (Memory::get_type(arguments->value.pair.rest) != Lisp_Object_Type::Pair) { if (Memory::get_type(arguments->value.pair.rest) != Lisp_Object_Type::Pair) {
create_generic_error( create_generic_error(
"Attempting to set the keyword argument ':%s', but no value was supplied.", "Attempting to set the keyword argument ':%s', but no value was supplied.",
&(arguments->value.pair.first->value.symbol.identifier)); &(arguments->value.pair.first->value.symbol.identifier->data));
return nullptr; return;
} }
// 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_void 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... // NOTE(Felix): It seems we do not need to evaluate the argument here...
try define_symbol( try_void define_symbol(
sym, sym,
Memory::copy_lisp_object_except_pairs(arguments->value.pair.rest->value.pair.first), Memory::copy_lisp_object_except_pairs(arguments->value.pair.rest->value.pair.first),
new_env); 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);
++read_obligatory_keywords_count;
// overstep both for next one // overstep both for next one
arguments = arguments->value.pair.rest->value.pair.rest; arguments = arguments->value.pair.rest->value.pair.rest;
@@ -101,8 +122,9 @@ proc apply_arguments_to_function(Lisp_Object* arguments, Function* function) ->
break; break;
} }
} }
};
checks: proc check_keyword_args = [&]() -> void {
// check if all necessary keywords have been read in // check if all necessary keywords have been read in
for (int i = 0; i < function->keyword_arguments->next_index; ++i) { for (int i = 0; i < function->keyword_arguments->next_index; ++i) {
String* defined_keyword = function->keyword_arguments->identifiers[i]; String* defined_keyword = function->keyword_arguments->identifiers[i];
@@ -123,28 +145,29 @@ proc apply_arguments_to_function(Lisp_Object* arguments, Function* function) ->
"There was no value supplied for the required " "There was no value supplied for the required "
"keyword argument ':%s'.", "keyword argument ':%s'.",
&defined_keyword->data); &defined_keyword->data);
return nullptr; return;
} }
} else { } else {
// this one does have a default value, lets see if we have // this one does have a default value, lets see if we have
// to use it or if the user supplied his own // to use it or if the user supplied his own
if (!was_set) { if (!was_set) {
try sym = Memory::get_or_create_lisp_object_symbol(defined_keyword); try_void sym = Memory::get_or_create_lisp_object_symbol(defined_keyword);
try val = Memory::copy_lisp_object_except_pairs(function->keyword_arguments->values->data[i]); try_void val = Memory::copy_lisp_object_except_pairs(function->keyword_arguments->values->data[i]);
define_symbol(sym, val, new_env); define_symbol(sym, val, new_env);
} }
} }
} }
};
proc read_rest_arg = [&]() -> void {
if (arguments == Memory::nil) { if (arguments == Memory::nil) {
if (function->rest_argument) { if (function->rest_argument) {
try sym = Memory::get_or_create_lisp_object_symbol(function->rest_argument); try_void sym = Memory::get_or_create_lisp_object_symbol(function->rest_argument);
define_symbol(sym, Memory::nil, new_env); define_symbol(sym, Memory::nil, new_env);
} }
} else { } else {
if (function->rest_argument) { if (function->rest_argument) {
try sym = Memory::get_or_create_lisp_object_symbol(function->rest_argument); try_void sym = Memory::get_or_create_lisp_object_symbol(function->rest_argument);
define_symbol( define_symbol(
sym, sym,
// NOTE(Felix): arguments will be a list, and I THINK // NOTE(Felix): arguments will be a list, and I THINK
@@ -156,15 +179,22 @@ proc apply_arguments_to_function(Lisp_Object* arguments, Function* function) ->
create_generic_error( create_generic_error(
"A rest argument was not declared " "A rest argument was not declared "
"but the function was called with additional arguments."); "but the function was called with additional arguments.");
return nullptr; return;
} }
} }
};
try read_poitional_args();
try read_keyword_args();
try check_keyword_args();
try read_rest_arg();
Lisp_Object* result; Lisp_Object* result;
try result = eval_expr(function->body, new_env); try result = eval_expr(function->body, new_env);
return result; return result;
} }
/** /**
This parses the argument specification of funcitons into their This parses the argument specification of funcitons into their
Function struct. It does this by allocating new Function struct. It does this by allocating new
+2 -2
View File
@@ -51,8 +51,8 @@ proc get_exe_dir() -> char* {
} }
if (!path) { if (!path) {
fprintf(stderr, "Failure: %d\n", last_error); fprintf(stderr, "Failure: %ld\n", last_error);
return ""; return nullptr;
} }
else { else {
// remove the exe name, so we are only left with the path // remove the exe name, so we are only left with the path