fixed keyword args when appling to a function
This commit is contained in:
@@ -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))
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user