Przeglądaj źródła

fixed keyword args when appling to a function

master
Felix Brendel 6 lat temu
rodzic
commit
df3661d77e
4 zmienionych plików z 164 dodań i 130 usunięć
  1. +3
    -0
      bin/test.slime
  2. +2
    -1
      build.bat
  3. +157
    -127
      src/eval.cpp
  4. +2
    -2
      src/platform.cpp

+ 3
- 0
bin/test.slime Wyświetl plik

@@ -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
build.bat Wyświetl plik

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


+ 157
- 127
src/eval.cpp Wyświetl plik

@@ -3,168 +3,198 @@ 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;

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;
}
// TODO(Felix): here we create new lisp_object_symbols from
// their identifiers but before we converted them to
// strings from symbols... Wo maybe just use the symbols?


// positional arguments
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;
}
// TODO(Felix): here we create new lisp_object_symbols from
// their identifiers but before we converted them to
// strings from symbols... Wo maybe just use the symbols?

// 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]);
define_symbol(
sym,
Memory::copy_lisp_object_except_pairs(arguments->value.pair.first),
new_env);
// NOTE(Felix): We have to copy all the arguments, otherwise
// we change the program code.
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),
new_env);


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 {
// 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)
goto checks;
if (arguments == Memory::nil)
return;


// 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;
// find out how many keyword args we /have/ to read
for (int i = 0; i < function->keyword_arguments->next_index; ++i) { for (int i = 0; i < function->keyword_arguments->next_index; ++i) {
if (string_equal(
arguments->value.pair.first->value.symbol.identifier,
function->keyword_arguments->identifiers[i]))
{
accepted = true;
if (function->keyword_arguments->values->data[i] == nullptr)
++obligatory_keywords_count;
else
break; break;
}
}
if (!accepted) {
// TODO(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)
create_generic_error(
"The function does not take the keyword argument ':%s'",
&(arguments->value.pair.first->value.symbol.identifier));
return nullptr;
} }


// check if it was already read in
for (int i = 0; i < read_in_keywords->next_index; ++i) {
if (string_equal(
arguments->value.pair.first->value.symbol.identifier,
read_in_keywords->data[i]))
{
// TODO(Felix): if we are actually done with all the

while (Memory::get_type(arguments->value.pair.first) == Lisp_Object_Type::Keyword) {
// check if this one is even an accepted keyword
bool accepted = false;
for (int i = 0; i < function->keyword_arguments->next_index; ++i) {
if (string_equal(
arguments->value.pair.first->value.symbol.identifier,
function->keyword_arguments->identifiers[i]))
{
accepted = true;
break;
}
}
if (!accepted) {
// 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'",
&(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;
} }
}


// okay so we found a keyword that has to be read in and was
// not already read in, is there a next element to actually
// set it to?
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;
}
// check if it was already read in
for (int i = 0; i < read_in_keywords->next_index; ++i) {
if (string_equal(
arguments->value.pair.first->value.symbol.identifier,
read_in_keywords->data[i]))
{
// 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->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);
// NOTE(Felix): It seems we do not need to evaluate the argument here...
try define_symbol(
sym,
Memory::copy_lisp_object_except_pairs(arguments->value.pair.rest->value.pair.first),
new_env);
// okay so we found a keyword that has to be read in and was
// not already read in, is there a next element to actually
// set it to?
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->data));
return;
}


append_to_array_list(read_in_keywords, arguments->value.pair.first->value.symbol.identifier);
// if not set it and then add it to the array list
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_void define_symbol(
sym,
Memory::copy_lisp_object_except_pairs(arguments->value.pair.rest->value.pair.first),
new_env);


// overstep both for next one
arguments = arguments->value.pair.rest->value.pair.rest;
append_to_array_list(read_in_keywords, arguments->value.pair.first->value.symbol.identifier);
++read_obligatory_keywords_count;


if (arguments == Memory::nil) {
break;
}
}
// overstep both for next one
arguments = arguments->value.pair.rest->value.pair.rest;


checks:
// 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];
bool was_set = false;
for (int j = 0; j < read_in_keywords->next_index; ++j) {
if (string_equal(
read_in_keywords->data[j],
defined_keyword))
{
was_set = true;
if (arguments == Memory::nil) {
break; break;
} }
} }
if (function->keyword_arguments->values->data[i] == nullptr) {
// if this one does not have a default value
if (!was_set) {
create_generic_error(
"There was no value supplied for the required "
"keyword argument ':%s'.",
&defined_keyword->data);
return nullptr;
};

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];
bool was_set = false;
for (int j = 0; j < read_in_keywords->next_index; ++j) {
if (string_equal(
read_in_keywords->data[j],
defined_keyword))
{
was_set = true;
break;
}
} }
} 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]);
define_symbol(sym, val, new_env);
if (function->keyword_arguments->values->data[i] == nullptr) {
// if this one does not have a default value
if (!was_set) {
create_generic_error(
"There was no value supplied for the required "
"keyword argument ':%s'.",
&defined_keyword->data);
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_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);
}
} }
} }
}

};


if (arguments == Memory::nil) {
if (function->rest_argument) {
try 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);
define_symbol(
sym,
// NOTE(Felix): arguments will be a list, and I THINK
// we do not need to copy it...
arguments,
new_env);
proc read_rest_arg = [&]() -> void {
if (arguments == Memory::nil) {
if (function->rest_argument) {
try_void sym = Memory::get_or_create_lisp_object_symbol(function->rest_argument);
define_symbol(sym, Memory::nil, new_env);
}
} else { } else {
// rest was not declared but additional arguments were found
create_generic_error(
"A rest argument was not declared "
"but the function was called with additional arguments.");
return nullptr;
if (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
// we do not need to copy it...
arguments,
new_env);
} else {
// rest was not declared but additional arguments were found
create_generic_error(
"A rest argument was not declared "
"but the function was called with additional arguments.");
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
src/platform.cpp Wyświetl plik

@@ -51,8 +51,8 @@ proc get_exe_dir() -> char* {
} }


if (!path) { if (!path) {
fprintf(stderr, "Failure: %d\n", last_error);
return "";
fprintf(stderr, "Failure: %ld\n", last_error);
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


Ładowanie…
Anuluj
Zapisz