浏览代码

fixed keyword args when appling to a function

master
Felix Brendel 6 年前
父节点
当前提交
df3661d77e
共有 4 个文件被更改,包括 164 次插入130 次删除
  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 查看文件

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

+ 2
- 1
build.bat 查看文件

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


+ 157
- 127
src/eval.cpp 查看文件

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

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) {
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;
}
}
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
// 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;
"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;
}
}
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 {
// 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;
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
src/platform.cpp 查看文件

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


正在加载...
取消
保存