fixed keyword args when appling to a function
This commit is contained in:
@@ -15,3 +15,6 @@
|
||||
|
||||
(printf "addr-of test:" (addr-of test))
|
||||
(test :ij :yes)
|
||||
|
||||
(define (tt :keys a b :rest r)
|
||||
(printf a b r))
|
||||
|
||||
@@ -9,7 +9,8 @@ pushd bin
|
||||
taskkill /F /IM %exeName% > NUL 2> NUL
|
||||
|
||||
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
|
||||
if %errorlevel% == 0 (
|
||||
|
||||
+57
-27
@@ -3,12 +3,15 @@ proc apply_arguments_to_function(Lisp_Object* arguments, Function* function) ->
|
||||
try new_env = Memory::create_child_environment(function->parent_environment);
|
||||
|
||||
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) {
|
||||
if (Memory::get_type(arguments) != Lisp_Object_Type::Pair) {
|
||||
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
|
||||
// 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
|
||||
// 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(
|
||||
sym,
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
String_Array_List* read_in_keywords = create_String_array_list();
|
||||
|
||||
if (arguments == Memory::nil)
|
||||
goto checks;
|
||||
|
||||
proc read_keyword_args = [&]() -> void {
|
||||
// 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.
|
||||
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) {
|
||||
// check if this one is even an accepted keyword
|
||||
bool accepted = false;
|
||||
@@ -47,14 +61,18 @@ proc apply_arguments_to_function(Lisp_Object* arguments, Function* function) ->
|
||||
}
|
||||
}
|
||||
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
|
||||
// as :rest here, instead od always creating an error
|
||||
// (special case with default variables)
|
||||
if (read_obligatory_keywords_count == obligatory_keywords_count)
|
||||
return;
|
||||
create_generic_error(
|
||||
"The function does not take the keyword argument ':%s'",
|
||||
&(arguments->value.pair.first->value.symbol.identifier));
|
||||
return nullptr;
|
||||
"The function does not take the keyword argument ':%s'\n"
|
||||
"and not all required keyword arguments have been read\n"
|
||||
"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
|
||||
@@ -63,14 +81,16 @@ proc apply_arguments_to_function(Lisp_Object* arguments, Function* function) ->
|
||||
arguments->value.pair.first->value.symbol.identifier,
|
||||
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
|
||||
// as :rest here, instead od always creating an error
|
||||
// (special case with default variables)
|
||||
if (read_obligatory_keywords_count == obligatory_keywords_count)
|
||||
return;
|
||||
create_generic_error(
|
||||
"The function already read the keyword argument ':%s'",
|
||||
&(arguments->value.pair.first->value.symbol.identifier));
|
||||
return nullptr;
|
||||
&(arguments->value.pair.first->value.symbol.identifier->data));
|
||||
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) {
|
||||
create_generic_error(
|
||||
"Attempting to set the keyword argument ':%s', but no value was supplied.",
|
||||
&(arguments->value.pair.first->value.symbol.identifier));
|
||||
return nullptr;
|
||||
&(arguments->value.pair.first->value.symbol.identifier->data));
|
||||
return;
|
||||
}
|
||||
|
||||
// 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...
|
||||
try define_symbol(
|
||||
try_void define_symbol(
|
||||
sym,
|
||||
Memory::copy_lisp_object_except_pairs(arguments->value.pair.rest->value.pair.first),
|
||||
new_env);
|
||||
|
||||
append_to_array_list(read_in_keywords, arguments->value.pair.first->value.symbol.identifier);
|
||||
++read_obligatory_keywords_count;
|
||||
|
||||
// overstep both for next one
|
||||
arguments = arguments->value.pair.rest->value.pair.rest;
|
||||
@@ -101,8 +122,9 @@ proc apply_arguments_to_function(Lisp_Object* arguments, Function* function) ->
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
checks:
|
||||
proc check_keyword_args = [&]() -> void {
|
||||
// check if all necessary keywords have been read in
|
||||
for (int i = 0; i < function->keyword_arguments->next_index; ++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 "
|
||||
"keyword argument ':%s'.",
|
||||
&defined_keyword->data);
|
||||
return nullptr;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// this one does have a default value, lets see if we have
|
||||
// to use it or if the user supplied his own
|
||||
if (!was_set) {
|
||||
try 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 sym = Memory::get_or_create_lisp_object_symbol(defined_keyword);
|
||||
try_void val = Memory::copy_lisp_object_except_pairs(function->keyword_arguments->values->data[i]);
|
||||
define_symbol(sym, val, new_env);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
proc read_rest_arg = [&]() -> void {
|
||||
if (arguments == Memory::nil) {
|
||||
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);
|
||||
}
|
||||
} else {
|
||||
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,
|
||||
// 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(
|
||||
"A rest argument was not declared "
|
||||
"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;
|
||||
try result = eval_expr(function->body, new_env);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
This parses the argument specification of funcitons into their
|
||||
Function struct. It does this by allocating new
|
||||
|
||||
+2
-2
@@ -51,8 +51,8 @@ proc get_exe_dir() -> char* {
|
||||
}
|
||||
|
||||
if (!path) {
|
||||
fprintf(stderr, "Failure: %d\n", last_error);
|
||||
return "";
|
||||
fprintf(stderr, "Failure: %ld\n", last_error);
|
||||
return nullptr;
|
||||
}
|
||||
else {
|
||||
// remove the exe name, so we are only left with the path
|
||||
|
||||
Reference in New Issue
Block a user