nrc_eval first steps
This commit is contained in:
@@ -23,3 +23,4 @@ todo.html
|
|||||||
/tests/libslime/main
|
/tests/libslime/main
|
||||||
/tests/fullslime/main
|
/tests/fullslime/main
|
||||||
*.o
|
*.o
|
||||||
|
/bin/slime_d
|
||||||
|
|||||||
+1
-1
Submodule 3rd/ftb updated: 635af49d52...7d8eabf479
@@ -2,43 +2,50 @@ TIMEFORMAT=%3lU
|
|||||||
SCRIPTPATH="$( cd "$(dirname "$0")" ; pwd -P )"
|
SCRIPTPATH="$( cd "$(dirname "$0")" ; pwd -P )"
|
||||||
pushd $SCRIPTPATH > /dev/null
|
pushd $SCRIPTPATH > /dev/null
|
||||||
|
|
||||||
echo ""
|
# echo ""
|
||||||
echo "----------------------"
|
# echo "----------------------"
|
||||||
echo " compiling libslime "
|
# echo " compiling libslime "
|
||||||
echo "----------------------"
|
# echo "----------------------"
|
||||||
|
# time clang++ --std=c++17 \
|
||||||
time clang++ --std=c++17 \
|
# src/libslime.cpp -c -o libslime.o \
|
||||||
src/libslime.cpp -c -o libslime.o \
|
# -I3rd/ || exit 1
|
||||||
-I3rd/ || exit 1
|
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "----------------------"
|
echo "------------------------------"
|
||||||
echo " compiling fullslime "
|
echo " compiling fullslime (debug) "
|
||||||
echo "----------------------"
|
echo "------------------------------"
|
||||||
|
|
||||||
# time g++ -fpermissive src/main.cpp -g -o ./bin/slime --std=c++17 || exit 1
|
|
||||||
time clang++ -D_DEBUG -D_DONT_BREAK_ON_ERRORS \
|
time clang++ -D_DEBUG -D_DONT_BREAK_ON_ERRORS \
|
||||||
src/main.cpp -g -o ./bin/slime --std=c++17 \
|
src/main.cpp -gfull -gdwarf -o ./bin/slime_d --std=c++17 \
|
||||||
-I3rd/ || exit 1
|
-I3rd/ || exit 1
|
||||||
# time clang++ -O3 -D_DONT_BREAK_ON_ERRORS \
|
|
||||||
# src/main.cpp -g -o ./bin/slime --std=c++17 \
|
|
||||||
# -I3rd/ || exit 1
|
|
||||||
|
|
||||||
pushd ./bin > /dev/null
|
# echo ""
|
||||||
|
# echo "--------------------------------"
|
||||||
|
# echo " compiling fullslime (release) "
|
||||||
|
# echo "--------------------------------"
|
||||||
|
# time clang++ -D_DONT_BREAK_ON_ERRORS -O3 \
|
||||||
|
# src/main.cpp -g -o ./bin/slime --std=c++17 \
|
||||||
|
# -I3rd/ || exit 1
|
||||||
|
|
||||||
echo ""
|
# pushd ./bin > /dev/null
|
||||||
echo "----------------------"
|
|
||||||
echo " generating docs "
|
|
||||||
echo "----------------------"
|
|
||||||
time valgrind -q ./slime dd || exit 1
|
|
||||||
|
|
||||||
echo ""
|
# echo ""
|
||||||
echo "----------------------"
|
# echo "----------------------"
|
||||||
echo " running tests "
|
# echo " generating docs "
|
||||||
echo "----------------------"
|
# echo "----------------------"
|
||||||
|
# time valgrind -q ./slime_d --generate-docs || exit 1
|
||||||
|
|
||||||
time valgrind -q --track-origins=yes --leak-check=full --show-leak-kinds=all ./slime --run-tests
|
# echo ""
|
||||||
|
# echo "----------------------"
|
||||||
|
# echo " running tests "
|
||||||
|
# echo "----------------------"
|
||||||
|
# time valgrind -q --track-origins=yes --leak-check=full --show-leak-kinds=all ./slime_d --run-tests || exit 1
|
||||||
|
|
||||||
|
# echo ""
|
||||||
|
# echo "------------------------"
|
||||||
|
# echo " running benches "
|
||||||
|
# echo "------------------------"
|
||||||
|
# hyperfine -s color --warmup 5 "./slime --run-tests > /dev/null"
|
||||||
|
|
||||||
popd > /dev/null
|
popd > /dev/null
|
||||||
popd > /dev/null
|
# popd > /dev/null
|
||||||
unset TIMEFORMAT
|
unset TIMEFORMAT
|
||||||
|
|||||||
@@ -1,11 +1,4 @@
|
|||||||
namespace Slime {
|
namespace Slime {
|
||||||
inline proc maybe_wrap_body_in_begin(Lisp_Object* body) -> Lisp_Object* {
|
|
||||||
Lisp_Object* begin_symbol = Memory::get_symbol("begin");
|
|
||||||
if (body->value.pair.rest == Memory::nil)
|
|
||||||
return body->value.pair.first;
|
|
||||||
else
|
|
||||||
return Memory::create_lisp_object_pair(begin_symbol, body);
|
|
||||||
}
|
|
||||||
|
|
||||||
proc lisp_object_equal(Lisp_Object* n1, Lisp_Object* n2) -> bool {
|
proc lisp_object_equal(Lisp_Object* n1, Lisp_Object* n2) -> bool {
|
||||||
if (n1 == n2)
|
if (n1 == n2)
|
||||||
|
|||||||
+527
-24
@@ -1,4 +1,246 @@
|
|||||||
namespace Slime {
|
namespace Slime {
|
||||||
|
|
||||||
|
proc create_extended_environment_for_function_application_nrc(
|
||||||
|
Array_List<Lisp_Object*> cs,
|
||||||
|
Lisp_Object* function,
|
||||||
|
int arg_start,
|
||||||
|
int arg_count) -> Environment*
|
||||||
|
{
|
||||||
|
profile_this();
|
||||||
|
|
||||||
|
bool is_c_function = Memory::get_type(function) == Lisp_Object_Type::CFunction;
|
||||||
|
Environment* new_env;
|
||||||
|
Arguments* arg_spec;
|
||||||
|
|
||||||
|
// NOTE(Felix): Step 1.
|
||||||
|
// - setting the parent environment
|
||||||
|
// - setting the arg_spec
|
||||||
|
// - potentially evaluating the arguments
|
||||||
|
if (is_c_function) {
|
||||||
|
new_env = Memory::create_child_environment(get_root_environment());
|
||||||
|
arg_spec = &function->value.cFunction->args;
|
||||||
|
} else {
|
||||||
|
new_env = Memory::create_child_environment(function->value.function->parent_environment);
|
||||||
|
arg_spec = &function->value.function->args;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arg_count == 0) {
|
||||||
|
return new_env;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE(Felix): Even though we will return the environment at the
|
||||||
|
// end, for defining symbols here for the parameters, it has to be
|
||||||
|
// on the envi stack.
|
||||||
|
push_environment(new_env);
|
||||||
|
defer {
|
||||||
|
pop_environment();
|
||||||
|
};
|
||||||
|
|
||||||
|
// NOTE(Felix): Step 2.
|
||||||
|
// Reading the argument spec and fill in the environment
|
||||||
|
// for the function call
|
||||||
|
|
||||||
|
Lisp_Object* sym, *val; // used as temp storage to use `try`
|
||||||
|
Array_List<Lisp_Object*> read_in_keywords;
|
||||||
|
int obligatory_keywords_count = 0;
|
||||||
|
int read_obligatory_keywords_count = 0;
|
||||||
|
|
||||||
|
Lisp_Object* next_arg = cs.data[arg_start];
|
||||||
|
|
||||||
|
proc read_positional_args = [&] {
|
||||||
|
for (int i = 0; i < arg_spec->positional.symbols.next_index; ++i) {
|
||||||
|
if (arg_count == 0) {
|
||||||
|
create_parsing_error("Wrong number of arguments.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// NOTE(Felix): We have to copy all the arguments,
|
||||||
|
// otherwise we change the program code.
|
||||||
|
// XXX(Felix): T C functions we pass by reference.
|
||||||
|
// TODO(Felix): Why did we decide this??
|
||||||
|
sym = arg_spec->positional.symbols.data[i];
|
||||||
|
if (is_c_function) {
|
||||||
|
define_symbol(sym, next_arg);
|
||||||
|
} else {
|
||||||
|
define_symbol(
|
||||||
|
sym,
|
||||||
|
Memory::copy_lisp_object_except_pairs(next_arg));
|
||||||
|
}
|
||||||
|
next_arg = cs[++arg_start];
|
||||||
|
--arg_count;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
proc read_keyword_args = [&] {
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
if (arg_count == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// find out how many keyword args we /have/ to read
|
||||||
|
for (int i = 0; i < arg_spec->keyword.values.next_index; ++i) {
|
||||||
|
if (arg_spec->keyword.values.data[i] == nullptr)
|
||||||
|
++obligatory_keywords_count;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (Memory::get_type(next_arg) == Lisp_Object_Type::Keyword) {
|
||||||
|
// check if this one is even an accepted keyword
|
||||||
|
bool accepted = false;
|
||||||
|
for (int i = 0; i < arg_spec->keyword.values.next_index; ++i) {
|
||||||
|
if (next_arg == arg_spec->keyword.keywords.data[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 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.",
|
||||||
|
&(next_arg->value.symbol->data));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if it was already read in
|
||||||
|
for (int i = 0; i < read_in_keywords.next_index; ++i) {
|
||||||
|
if (next_arg == 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'",
|
||||||
|
&(next_arg->value.symbol->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 (arg_count == 0) {
|
||||||
|
create_generic_error(
|
||||||
|
"Attempting to set the keyword argument ':%s', but no value was supplied.",
|
||||||
|
&(next_arg->value.symbol->data));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if not set it and then add it to the array list
|
||||||
|
try_void sym = Memory::get_symbol(next_arg->value.symbol);
|
||||||
|
next_arg = cs[++arg_start];
|
||||||
|
--arg_count;
|
||||||
|
// NOTE(Felix): It seems we do not need to evaluate the argument here...
|
||||||
|
if (is_c_function) {
|
||||||
|
try_void define_symbol(sym, next_arg);
|
||||||
|
} else {
|
||||||
|
try_void define_symbol(
|
||||||
|
sym,
|
||||||
|
Memory::copy_lisp_object_except_pairs(next_arg));
|
||||||
|
}
|
||||||
|
|
||||||
|
read_in_keywords.append(next_arg);
|
||||||
|
++read_obligatory_keywords_count;
|
||||||
|
|
||||||
|
// overstep both for next one
|
||||||
|
next_arg = cs[++arg_start];
|
||||||
|
--arg_count;
|
||||||
|
|
||||||
|
if (arg_count == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
proc check_keyword_args = [&]() -> void {
|
||||||
|
// check if all necessary keywords have been read in
|
||||||
|
for (int i = 0; i < arg_spec->keyword.values.next_index; ++i) {
|
||||||
|
auto defined_keyword = arg_spec->keyword.keywords.data[i];
|
||||||
|
bool was_set = false;
|
||||||
|
for (int j = 0; j < read_in_keywords.next_index; ++j) {
|
||||||
|
if (read_in_keywords.data[j] == defined_keyword) {
|
||||||
|
was_set = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (arg_spec->keyword.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->value.symbol->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_symbol(defined_keyword->value.symbol);
|
||||||
|
if (is_c_function) {
|
||||||
|
try_void val = arg_spec->keyword.values.data[i];
|
||||||
|
} else {
|
||||||
|
try_void val = Memory::copy_lisp_object_except_pairs(arg_spec->keyword.values.data[i]);
|
||||||
|
}
|
||||||
|
define_symbol(sym, val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
proc read_rest_arg = [&]() -> void {
|
||||||
|
if (arg_count == 0) {
|
||||||
|
if (arg_spec->rest) {
|
||||||
|
define_symbol(arg_spec->rest, Memory::nil);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (arg_spec->rest) {
|
||||||
|
|
||||||
|
Lisp_Object* list;
|
||||||
|
try_void list = Memory::create_list(next_arg);
|
||||||
|
Lisp_Object* head = list;
|
||||||
|
next_arg = cs[++arg_start];
|
||||||
|
--arg_count;
|
||||||
|
while (arg_count > 0) {
|
||||||
|
try_void head->value.pair.rest = Memory::create_list(next_arg);
|
||||||
|
head = head->value.pair.rest;
|
||||||
|
next_arg = cs[++arg_start];
|
||||||
|
--arg_count;
|
||||||
|
}
|
||||||
|
define_symbol(arg_spec->rest, list);
|
||||||
|
} 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_positional_args();
|
||||||
|
try read_keyword_args();
|
||||||
|
try check_keyword_args();
|
||||||
|
try read_rest_arg();
|
||||||
|
|
||||||
|
// TODO(Felix): fucking destructors
|
||||||
|
cs.data = nullptr;
|
||||||
|
return new_env;
|
||||||
|
}
|
||||||
proc create_extended_environment_for_function_application(
|
proc create_extended_environment_for_function_application(
|
||||||
Lisp_Object* unevaluated_arguments,
|
Lisp_Object* unevaluated_arguments,
|
||||||
Lisp_Object* function,
|
Lisp_Object* function,
|
||||||
@@ -246,13 +488,12 @@ namespace Slime {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
This parses the argument specification of funcitons into their
|
|
||||||
Function struct. It does this by allocating new
|
|
||||||
positional_arguments, keyword_arguments and rest_argument and
|
|
||||||
filling it in
|
|
||||||
*/
|
|
||||||
proc create_arguments_from_lambda_list_and_inject(Lisp_Object* arguments, Lisp_Object* function) -> void {
|
proc create_arguments_from_lambda_list_and_inject(Lisp_Object* arguments, Lisp_Object* function) -> void {
|
||||||
|
/* NOTE This parses the argument specification of funcitons
|
||||||
|
* into their Function struct. It does this by allocating new
|
||||||
|
* positional_arguments, keyword_arguments and rest_argument
|
||||||
|
* and filling it in
|
||||||
|
*/
|
||||||
Arguments* result;
|
Arguments* result;
|
||||||
if (Memory::get_type(function) == Lisp_Object_Type::CFunction) {
|
if (Memory::get_type(function) == Lisp_Object_Type::CFunction) {
|
||||||
result = &function->value.cFunction->args;
|
result = &function->value.cFunction->args;
|
||||||
@@ -393,6 +634,280 @@ namespace Slime {
|
|||||||
return evaluated_arguments;
|
return evaluated_arguments;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
proc pause() {
|
||||||
|
printf("\n-----------------------\n"
|
||||||
|
"Press ENTER to continue\n");
|
||||||
|
getchar();
|
||||||
|
}
|
||||||
|
inline proc maybe_wrap_body_in_begin(Lisp_Object* body) -> Lisp_Object* {
|
||||||
|
Lisp_Object* begin_symbol = Memory::get_symbol("begin");
|
||||||
|
if (body->value.pair.rest == Memory::nil)
|
||||||
|
return body->value.pair.first;
|
||||||
|
else
|
||||||
|
return Memory::create_lisp_object_pair(begin_symbol, body);
|
||||||
|
}
|
||||||
|
|
||||||
|
proc nrc_eval(Lisp_Object* expr) -> Lisp_Object* {
|
||||||
|
enum struct Action {
|
||||||
|
Eval,
|
||||||
|
Step,
|
||||||
|
TM,
|
||||||
|
Pop,
|
||||||
|
If,
|
||||||
|
Define_Var,
|
||||||
|
Pop_Environment
|
||||||
|
};
|
||||||
|
|
||||||
|
Array_List<Lisp_Object*> cs;
|
||||||
|
Array_List<Lisp_Object*> pcs;
|
||||||
|
Array_List<Action> nas;
|
||||||
|
Array_List<int> ams;
|
||||||
|
|
||||||
|
proc debug_step = [&] {
|
||||||
|
printf("cs:\n ");
|
||||||
|
for (auto lo : cs) {
|
||||||
|
print(lo, true);
|
||||||
|
printf("\n ");
|
||||||
|
}
|
||||||
|
printf("\npcs:\n ");
|
||||||
|
for (auto lo : pcs) {
|
||||||
|
print(lo, true);
|
||||||
|
printf("\n ");
|
||||||
|
}
|
||||||
|
printf("\nnas:\n ");
|
||||||
|
for (auto na : nas) {
|
||||||
|
printf("%s\n ", [&]
|
||||||
|
{
|
||||||
|
switch(na) {
|
||||||
|
case Action::Pop_Environment: return "Pop_Environment";
|
||||||
|
case Action::Define_Var: return "Define_Var";
|
||||||
|
case Action::Eval: return "Eval";
|
||||||
|
case Action::Step: return "Step";
|
||||||
|
case Action::TM: return "TM";
|
||||||
|
case Action::Pop: return "Pop";
|
||||||
|
case Action::If: return "If";
|
||||||
|
}
|
||||||
|
}());
|
||||||
|
}
|
||||||
|
printf("\nams:\n ");
|
||||||
|
for (auto am : ams) {
|
||||||
|
printf("%d\n ", am);
|
||||||
|
}
|
||||||
|
pause();
|
||||||
|
};
|
||||||
|
|
||||||
|
proc handle_if = [&] {
|
||||||
|
/* | | | <test> |
|
||||||
|
| | -> | <then> |
|
||||||
|
| <if> | | <else> |
|
||||||
|
| .... | | ...... | */
|
||||||
|
--ams.next_index;
|
||||||
|
Lisp_Object* args = pcs.data[--pcs.next_index];
|
||||||
|
Lisp_Object* test = args->value.pair.first;
|
||||||
|
args = args->value.pair.rest;
|
||||||
|
try_void assert_type(args, Lisp_Object_Type::Pair);
|
||||||
|
Lisp_Object* consequence = args->value.pair.first;
|
||||||
|
args = args->value.pair.rest;
|
||||||
|
try_void assert_type(args, Lisp_Object_Type::Pair);
|
||||||
|
Lisp_Object* alternative = args->value.pair.first;
|
||||||
|
args = args->value.pair.rest;
|
||||||
|
try_void assert_type(args, Lisp_Object_Type::Nil);
|
||||||
|
--cs.next_index;
|
||||||
|
cs.append(alternative);
|
||||||
|
cs.append(consequence);
|
||||||
|
cs.append(test);
|
||||||
|
nas.append(Action::Eval);
|
||||||
|
nas.append(Action::If);
|
||||||
|
nas.append(Action::Eval);
|
||||||
|
};
|
||||||
|
|
||||||
|
proc handle_define = [&] {
|
||||||
|
--cs.next_index;
|
||||||
|
--ams.next_index;
|
||||||
|
Lisp_Object* form = pcs.data[--pcs.next_index];
|
||||||
|
Lisp_Object* definee = form->value.pair.first;
|
||||||
|
form = form->value.pair.rest;
|
||||||
|
try_void assert_type(form, Lisp_Object_Type::Pair);
|
||||||
|
Lisp_Object* thing = form->value.pair.first;
|
||||||
|
Lisp_Object* thing_cons = form;
|
||||||
|
form = form->value.pair.rest;
|
||||||
|
Lisp_Object_Type type = Memory::get_type(definee);
|
||||||
|
switch (type) {
|
||||||
|
case Lisp_Object_Type::Symbol: {
|
||||||
|
// BUG(Felix): Defining with doc string crashes
|
||||||
|
if (form != Memory::nil) {
|
||||||
|
Lisp_Object* doc = thing;
|
||||||
|
try_void assert_type(doc, Lisp_Object_Type::String);
|
||||||
|
try_void assert_type(form, Lisp_Object_Type::Pair);
|
||||||
|
form = form->value.pair.rest;
|
||||||
|
thing = form->value.pair.first;
|
||||||
|
try_void assert(form->value.pair.rest == Memory::nil);
|
||||||
|
// TODO docs
|
||||||
|
}
|
||||||
|
cs.append(definee);
|
||||||
|
cs.append(thing);
|
||||||
|
nas.append(Action::Define_Var);
|
||||||
|
nas.append(Action::Eval);
|
||||||
|
} break;
|
||||||
|
case Lisp_Object_Type::Pair: {
|
||||||
|
fflush(stdout);
|
||||||
|
try_void assert_type(definee->value.pair.first, Lisp_Object_Type::Symbol);
|
||||||
|
Lisp_Object* func;
|
||||||
|
try_void func = Memory::create_lisp_object_function(Function_Type::Lambda);
|
||||||
|
func->value.function->parent_environment = get_current_environment();
|
||||||
|
create_arguments_from_lambda_list_and_inject(definee->value.pair.rest, func);
|
||||||
|
func->value.function->body = maybe_wrap_body_in_begin(thing_cons);
|
||||||
|
define_symbol(definee->value.pair.first, func);
|
||||||
|
cs.append(Memory::t);
|
||||||
|
} break;
|
||||||
|
default: {
|
||||||
|
create_generic_error("you can only define symbols");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
proc handle_begin = [&] {
|
||||||
|
--cs.next_index;
|
||||||
|
--ams.next_index;
|
||||||
|
Lisp_Object* args = pcs[--pcs.next_index];
|
||||||
|
int length = list_length(args);
|
||||||
|
cs.reserve(length);
|
||||||
|
printf("aaaaaa\n\n");
|
||||||
|
for_lisp_list(args) {
|
||||||
|
cs.data[cs.next_index - 1 + (length - it_index)] = it;
|
||||||
|
nas.append(Action::Eval);
|
||||||
|
nas.append(Action::Pop);
|
||||||
|
}
|
||||||
|
|
||||||
|
--nas.next_index;
|
||||||
|
cs.next_index += length;
|
||||||
|
};
|
||||||
|
|
||||||
|
cs.append(expr);
|
||||||
|
nas.append(Action::Eval);
|
||||||
|
|
||||||
|
Action current_action;
|
||||||
|
Lisp_Object* pc;
|
||||||
|
while (nas.next_index > 0) {
|
||||||
|
debug_step();
|
||||||
|
|
||||||
|
current_action = nas.data[--nas.next_index];
|
||||||
|
switch (current_action) {
|
||||||
|
case Action::Pop: {
|
||||||
|
--cs.next_index;
|
||||||
|
} break;
|
||||||
|
case Action::Pop_Environment: {
|
||||||
|
pop_environment();
|
||||||
|
} break;
|
||||||
|
case Action::Eval: {
|
||||||
|
pc = cs.data[cs.next_index-1];
|
||||||
|
Lisp_Object_Type type = Memory::get_type(pc);
|
||||||
|
switch (type) {
|
||||||
|
case Lisp_Object_Type::Symbol: {
|
||||||
|
cs.data[cs.next_index-1] = lookup_symbol(pc, get_current_environment());
|
||||||
|
} break;
|
||||||
|
case Lisp_Object_Type::Pair: {
|
||||||
|
cs.data[cs.next_index-1] = pc->value.pair.first;
|
||||||
|
ams.append(cs.next_index-1);
|
||||||
|
pcs.append(pc->value.pair.rest);
|
||||||
|
nas.append(Action::TM);
|
||||||
|
nas.append(Action::Eval);
|
||||||
|
} break;
|
||||||
|
default: {
|
||||||
|
// NOTE(Felix): others are self evaluating
|
||||||
|
// so do nothing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case Action::TM: {
|
||||||
|
pc = cs.data[cs.next_index-1];
|
||||||
|
|
||||||
|
Lisp_Object_Type type = Memory::get_type(pc);
|
||||||
|
switch (type) {
|
||||||
|
case Lisp_Object_Type::CFunction: {
|
||||||
|
if (pc->value.cFunction->is_special_form) {
|
||||||
|
if (pc == Memory::_if) try handle_if();
|
||||||
|
else if (pc == Memory::_begin) try handle_begin();
|
||||||
|
else if (pc == Memory::_define) try handle_define();
|
||||||
|
else {
|
||||||
|
// push_pc_on_cs();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
nas.append(Action::Step);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case Lisp_Object_Type::Function: {
|
||||||
|
if (pc->value.function->type == Function_Type::Macro) {
|
||||||
|
// push_pc_on_cs();
|
||||||
|
} else {
|
||||||
|
nas.append(Action::Step);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
default: {
|
||||||
|
create_generic_error("The first element of the pair was not a function but: %s",
|
||||||
|
Lisp_Object_Type_to_string(type));
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} break;
|
||||||
|
case Action::Step: {
|
||||||
|
if (pcs.data[pcs.next_index-1] == Memory::nil) {
|
||||||
|
--pcs.next_index;
|
||||||
|
int am = ams.data[--ams.next_index];
|
||||||
|
Lisp_Object* function = cs.data[am];
|
||||||
|
Lisp_Object_Type type = Memory::get_type(function);
|
||||||
|
Environment* extended_env =
|
||||||
|
create_extended_environment_for_function_application_nrc(
|
||||||
|
cs, function, am+1, cs.next_index-am-1);
|
||||||
|
cs.next_index = am;
|
||||||
|
push_environment(extended_env);
|
||||||
|
if (type == Lisp_Object_Type::CFunction) {
|
||||||
|
try cs.append(function->value.cFunction->body());
|
||||||
|
pop_environment();
|
||||||
|
} else {
|
||||||
|
nas.append(Action::Pop_Environment);
|
||||||
|
nas.append(Action::Eval);
|
||||||
|
cs.append(function->value.function->body);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cs.append(pcs.data[pcs.next_index-1]->value.pair.first);
|
||||||
|
pcs.data[pcs.next_index-1] = pcs.data[pcs.next_index-1]->value.pair.rest;
|
||||||
|
nas.append(Action::Step);
|
||||||
|
nas.append(Action::Eval);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case Action::If: {
|
||||||
|
/* | <cond> |
|
||||||
|
| <then> |
|
||||||
|
| <else> |
|
||||||
|
| .... | */
|
||||||
|
cs.next_index -= 2;
|
||||||
|
// NOTE(Felix): for false it is sufficent to pop 2 for
|
||||||
|
// true we have to copy the then part to the new top
|
||||||
|
// of the stack
|
||||||
|
if (cs.data[cs.next_index+1] != Memory::nil) {
|
||||||
|
cs.data[cs.next_index-1] = cs.data[cs.next_index];
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case Action::Define_Var: {
|
||||||
|
/* | <thing> |
|
||||||
|
| <symbol> |
|
||||||
|
| .... | */
|
||||||
|
cs.next_index -= 1;
|
||||||
|
try assert_type(cs.data[cs.next_index-1], Lisp_Object_Type::Symbol);
|
||||||
|
try define_symbol(cs.data[cs.next_index-1], cs.data[cs.next_index]);
|
||||||
|
cs.data[cs.next_index-1] = Memory::t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
debug_step();
|
||||||
|
|
||||||
|
return cs.data[--cs.next_index];
|
||||||
|
}
|
||||||
|
|
||||||
proc eval_expr(Lisp_Object* node) -> Lisp_Object* {
|
proc eval_expr(Lisp_Object* node) -> Lisp_Object* {
|
||||||
profile_this();
|
profile_this();
|
||||||
|
|
||||||
@@ -403,14 +918,6 @@ namespace Slime {
|
|||||||
};
|
};
|
||||||
|
|
||||||
switch (Memory::get_type(node)) {
|
switch (Memory::get_type(node)) {
|
||||||
case Lisp_Object_Type::T:
|
|
||||||
case Lisp_Object_Type::Nil:
|
|
||||||
case Lisp_Object_Type::Number:
|
|
||||||
case Lisp_Object_Type::Keyword:
|
|
||||||
case Lisp_Object_Type::String:
|
|
||||||
case Lisp_Object_Type::Function:
|
|
||||||
case Lisp_Object_Type::CFunction:
|
|
||||||
return node;
|
|
||||||
case Lisp_Object_Type::Symbol: {
|
case Lisp_Object_Type::Symbol: {
|
||||||
Lisp_Object* value;
|
Lisp_Object* value;
|
||||||
try value = lookup_symbol(node, get_current_environment());
|
try value = lookup_symbol(node, get_current_environment());
|
||||||
@@ -471,11 +978,7 @@ namespace Slime {
|
|||||||
Lisp_Object_Type_to_string(Memory::get_type(lispOperator)));
|
Lisp_Object_Type_to_string(Memory::get_type(lispOperator)));
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
default: {
|
default: return node;
|
||||||
create_generic_error("%s is not a function.", Lisp_Object_Type_to_string(Memory::get_type(node)));
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -506,14 +1009,14 @@ namespace Slime {
|
|||||||
Lisp_Object* parsed, * evaluated;
|
Lisp_Object* parsed, * evaluated;
|
||||||
while (true) {
|
while (true) {
|
||||||
[&] {
|
[&] {
|
||||||
delete_error();
|
// delete_error();
|
||||||
fputs("> ", stdout);
|
fputs("> ", stdout);
|
||||||
line = read_expression();
|
line = read_expression();
|
||||||
defer {
|
// defer {
|
||||||
free(line);
|
// free(line);
|
||||||
};
|
// };
|
||||||
try_void parsed = Parser::parse_single_expression(line);
|
try_void parsed = Parser::parse_single_expression(line);
|
||||||
try_void evaluated = eval_expr(parsed);
|
try_void evaluated = nrc_eval(parsed);
|
||||||
if (evaluated != Memory::nil) {
|
if (evaluated != Memory::nil) {
|
||||||
print(evaluated);
|
print(evaluated);
|
||||||
fputs("\n", stdout);
|
fputs("\n", stdout);
|
||||||
|
|||||||
+3
-4
@@ -2,21 +2,20 @@
|
|||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
|
|
||||||
if_windows {
|
#ifdef _MSC_VER
|
||||||
// enable colored terminal output for windows
|
// enable colored terminal output for windows
|
||||||
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
DWORD dwMode = 0;
|
DWORD dwMode = 0;
|
||||||
GetConsoleMode(hOut, &dwMode);
|
GetConsoleMode(hOut, &dwMode);
|
||||||
dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
||||||
SetConsoleMode(hOut, dwMode);
|
SetConsoleMode(hOut, dwMode);
|
||||||
}
|
#endif
|
||||||
|
|
||||||
if (argc > 1) {
|
if (argc > 1) {
|
||||||
if (Slime::string_equal(argv[1], "--run-tests")) {
|
if (Slime::string_equal(argv[1], "--run-tests")) {
|
||||||
int res = Slime::run_all_tests();
|
int res = Slime::run_all_tests();
|
||||||
return res ? 0 : 1;
|
return res ? 0 : 1;
|
||||||
}
|
} else if (Slime::string_equal(argv[1], "--generate-docs")) {
|
||||||
if (Slime::string_equal(argv[1], "--generate-docs")) {
|
|
||||||
Slime::Memory::init(4096 * 256* 100);
|
Slime::Memory::init(4096 * 256* 100);
|
||||||
if (Slime::Globals::error) return 1;
|
if (Slime::Globals::error) return 1;
|
||||||
Slime::built_in_load(Slime::Memory::create_string("generate-docs.slime"));
|
Slime::built_in_load(Slime::Memory::create_string("generate-docs.slime"));
|
||||||
|
|||||||
+17
-2
@@ -32,8 +32,13 @@ namespace Slime::Memory {
|
|||||||
// ------------------
|
// ------------------
|
||||||
// immutables
|
// immutables
|
||||||
// ------------------
|
// ------------------
|
||||||
Lisp_Object* nil = nullptr;
|
Lisp_Object* nil = nullptr;
|
||||||
Lisp_Object* t = nullptr;
|
Lisp_Object* t = nullptr;
|
||||||
|
Lisp_Object* _if = nullptr;
|
||||||
|
Lisp_Object* _define = nullptr;
|
||||||
|
Lisp_Object* _begin = nullptr;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
proc print_status() {
|
proc print_status() {
|
||||||
// printf("Memory Status:\n"
|
// printf("Memory Status:\n"
|
||||||
@@ -136,6 +141,8 @@ namespace Slime::Memory {
|
|||||||
environment_memory.for_each([](Environment* env){
|
environment_memory.for_each([](Environment* env){
|
||||||
env->~Environment();
|
env->~Environment();
|
||||||
});
|
});
|
||||||
|
// free the exe dir:
|
||||||
|
free(Globals::load_path.data[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -190,6 +197,10 @@ namespace Slime::Memory {
|
|||||||
Environment* user_env;
|
Environment* user_env;
|
||||||
try_void user_env = Memory::create_child_environment(env);
|
try_void user_env = Memory::create_child_environment(env);
|
||||||
push_environment(user_env);
|
push_environment(user_env);
|
||||||
|
|
||||||
|
try_void _if = lookup_symbol(get_symbol("if"), env);
|
||||||
|
try_void _define = lookup_symbol(get_symbol("define"), env);
|
||||||
|
try_void _begin = lookup_symbol(get_symbol("begin"), env);
|
||||||
}
|
}
|
||||||
|
|
||||||
proc reset() -> void {
|
proc reset() -> void {
|
||||||
@@ -239,6 +250,10 @@ namespace Slime::Memory {
|
|||||||
Environment* user_env;
|
Environment* user_env;
|
||||||
try_void user_env = Memory::create_child_environment(env);
|
try_void user_env = Memory::create_child_environment(env);
|
||||||
push_environment(user_env);
|
push_environment(user_env);
|
||||||
|
|
||||||
|
try_void _if = lookup_symbol(get_symbol("if"), env);
|
||||||
|
try_void _define = lookup_symbol(get_symbol("define"), env);
|
||||||
|
try_void _begin = lookup_symbol(get_symbol("begin"), env);
|
||||||
}
|
}
|
||||||
|
|
||||||
proc create_lisp_object(void* ptr) -> Lisp_Object* {
|
proc create_lisp_object(void* ptr) -> Lisp_Object* {
|
||||||
|
|||||||
+5
-3
@@ -603,9 +603,11 @@ namespace Slime {
|
|||||||
bool result = true;
|
bool result = true;
|
||||||
|
|
||||||
try Memory::init(409600);
|
try Memory::init(409600);
|
||||||
if_debug {
|
defer {
|
||||||
Slime::Memory::free_everything();
|
if_debug {
|
||||||
}
|
Slime::Memory::free_everything();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
push_environment(Memory::create_child_environment(
|
push_environment(Memory::create_child_environment(
|
||||||
get_current_environment()));
|
get_current_environment()));
|
||||||
|
|||||||
Reference in New Issue
Block a user