diff --git a/README.md b/README.md index af1fc2e..9100c9d 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ C++17 + ✅ Special operator `IF` + macro `DO` - - Tail Call Optimization (TCO). 実装したがテスト未了 + - ✅ Tail Call Optimization (TCO). トランポリン trampoline で相互再帰もOK. - Files diff --git a/environment.cpp b/environment.cpp index 80f2ef1..853064a 100644 --- a/environment.cpp +++ b/environment.cpp @@ -101,9 +101,9 @@ FuncPtr Environment::find_function(const UnicodeString& symbol) void Environment::set_value(const UnicodeString& symbol, const value_t& value, bool constant) { - std::cout << __func__ << " at " << __LINE__ << ": "; - std::cout << symbol << " = " ; - PRINT(value, std::cout); std::cout << "\n"; // DEBUG + //std::cout << __func__ << " at " << __LINE__ << ": "; + //std::cout << symbol << " = " ; + //PRINT(value, std::cout); std::cout << "\n"; // DEBUG // insert() は更新しない! m_values[symbol] = BoundValue { .val = value, .constant = constant}; diff --git a/my_debug.h b/my_debug.h index 2e3ac45..25503a8 100644 --- a/my_debug.h +++ b/my_debug.h @@ -11,7 +11,7 @@ // 不要のときはコメントアウト //#define DEBUG_OBJECT_LIFETIMES 1 -#define DEBUG_ENV_LIFETIMES 1 +//#define DEBUG_ENV_LIFETIMES 1 #define DEBUG_TRACE_FILE stderr diff --git a/test/Makefile b/test/Makefile index fcf9793..da3bcd4 100644 --- a/test/Makefile +++ b/test/Makefile @@ -2,7 +2,7 @@ .PHONY: all clean TARGETS = ref_counted_test reader_test edit_line_test environment_test \ - macro_test evaluation_test block_test + macro_test evaluation_test block_test tco_test all: $(TARGETS) @@ -49,6 +49,9 @@ macro_test: macro_test.o ../macros.o ../environment.o ../object_print.o ../reade evaluation_test: evaluation_test.o ../evaluation.o ../environment.o ../object_print.o ../reader.o ../macros.o ../builtin-functions.o $(CXX) $^ $(LDFLAGS) $(LDLIBS) -lstdc++ -licuuc -licuio -ledit -o $@ +tco_test: tco_test.o ../evaluation.o ../environment.o ../object_print.o ../reader.o ../macros.o ../builtin-functions.o + $(CXX) $^ $(LDFLAGS) $(LDLIBS) -lstdc++ -licuuc -licuio -ledit -o $@ + block_test: block_test.o ../evaluation.o ../environment.o ../object_print.o ../reader.o ../macros.o ../builtin-functions.o $(CXX) $^ $(LDFLAGS) $(LDLIBS) -lstdc++ -licuuc -licuio -ledit -o $@ diff --git a/test/tco.cpp b/test/tco.cpp new file mode 100644 index 0000000..795dfd6 --- /dev/null +++ b/test/tco.cpp @@ -0,0 +1,27 @@ + +#include +using namespace std; + +// -S オプションでアセンブラ出力 + +bool isodd(int n) ; + +// 偶数のとき true +bool iseven(int n) { + return n > 0 ? isodd(n - 1) : true; +} + +// 奇数のとき true +bool isodd(int n) { + return n > 0 ? iseven(n - 1) : false; +} + +int main() +{ + // オプションなし = segfault, -O3 => 結果 1 OK + cout << "iseven(1'000'000) = " << iseven(1'000'000) << "\n"; + + // ちょっとだけ間があく = 計算したうえで, 結果 1 OK + cout << "isodd(2'000'000'001) = " << isodd(2'000'000'001) << "\n"; + return 0; +} diff --git a/test/tco_test.cpp b/test/tco_test.cpp new file mode 100644 index 0000000..55761ea --- /dev/null +++ b/test/tco_test.cpp @@ -0,0 +1,70 @@ + +#include "../environment.h" +#include +#include +#include + +namespace my { +extern value_t EVAL1(value_t ast, EnvPtr env); +extern bool value_isTrue(const value_t& value) ; + +extern void setup_functions(); + +my::value_t do_1minus(my::EnvPtr args) { + my::value_t x = args->find_value("X"); + double v = std::get(x); + + return v - 1; +} + +// @return T or NIL +my::value_t do_gt(my::EnvPtr args) { + double x = std::get(args->find_value("X")); + double y = std::get(args->find_value("Y")); + return x > y ? trueValue : nilValue; +} + +} // namespace my + + +int main() +{ + my::EnvPtr env = std::make_shared(); + + my::setup_functions(); + my::define_function("1-", "(x)", my::do_1minus); + my::define_function(">", "(x y)", my::do_gt); + my::globalEnv->set_value("T", my::trueValue, true); + my::globalEnv->set_value("NIL", my::nilValue, true); + + // 偶数 = true + icu::UnicodeString ast = "(defun iseven (n) (if (> n 0) (isodd (1- n)) t))"; + my::value_t astv = my::read_from_string(ast); + my::EVAL1(astv, env); + + // 奇数 = true + ast = "(defun isodd (n) (if (> n 0) (iseven (1- n)) nil))"; + astv = my::read_from_string(ast); + my::EVAL1(astv, env); + + ast = "(print (iseven 10))"; + astv = my::read_from_string(ast); + my::EVAL1(astv, env); //=> T + + ast = "(print (isodd 10))"; + astv = my::read_from_string(ast); + my::EVAL1(astv, env); //=> NIL + + ast = "(print (iseven 9))"; + astv = my::read_from_string(ast); + my::EVAL1(astv, env); //=> NIL + + ast = "(print (isodd 9))"; + astv = my::read_from_string(ast); + my::EVAL1(astv, env); //=> T + + astv = my::read_from_string("(print (iseven 1000000))"); + my::EVAL1(astv, env); //=> T + + return 0; +}