diff --git a/inkcpp/functional.cpp b/inkcpp/functional.cpp index 81289436..5a20067a 100644 --- a/inkcpp/functional.cpp +++ b/inkcpp/functional.cpp @@ -9,6 +9,7 @@ #include "value.h" #include "stack.h" #include "string_table.h" +#include "operations.h" #ifdef INK_ENABLE_UNREAL # include "InkVar.h" @@ -28,8 +29,28 @@ template<> int32_t function_base::pop(basic_eval_stack* stack, list_table& lists) { value val = stack->pop(); - inkAssert(val.type() == value_type::int32, "Type mismatch!"); - return val.get(); + return casting::numeric_cast(val); +} + +template<> +uint32_t function_base::pop(basic_eval_stack* stack, list_table& lists) +{ + value val = stack->pop(); + return casting::numeric_cast(val); +} + +template<> +bool function_base::pop(basic_eval_stack* stack, list_table& lists) +{ + value val = stack->pop(); + return casting::numeric_cast(val) != 0; +} + +template<> +float function_base::pop(basic_eval_stack* stack, list_table& lists) +{ + value val = stack->pop(); + return casting::numeric_cast(val); } template<> @@ -46,6 +67,24 @@ void function_base::push(basic_eval_stack* stack, const int32_t& v) stack->push(value{}.set(v)); } +template<> +void function_base::push(basic_eval_stack* stack, const uint32_t& v) +{ + stack->push(value{}.set(v)); +} + +template<> +void function_base::push(basic_eval_stack* stack, const float& v) +{ + stack->push(value{}.set(v)); +} + +template<> +void function_base::push(basic_eval_stack* stack, const bool& v) +{ + stack->push(value{}.set(v)); +} + void function_base::push_void(basic_eval_stack* stack) { stack->push(values::null); } void function_base::push_string(basic_eval_stack* stack, const char* dynamic_string) diff --git a/inkcpp/numeric_operations.h b/inkcpp/numeric_operations.h index d2593139..0914f401 100644 --- a/inkcpp/numeric_operations.h +++ b/inkcpp/numeric_operations.h @@ -88,6 +88,7 @@ namespace casting numeric_cast(const value& v) { switch (v.type()) { + case value_type::int32: return v.get(); case value_type::uint32: return v.get(); /// bool value can cast to uint32 case value_type::boolean: return static_cast(v.get()); diff --git a/inkcpp/output.cpp b/inkcpp/output.cpp index 6162db2c..06614125 100644 --- a/inkcpp/output.cpp +++ b/inkcpp/output.cpp @@ -362,6 +362,7 @@ char* basic_stream::get_alloc(string_table& strings, list_table& lists) case value_type::int32: case value_type::float32: case value_type::uint32: + case value_type::boolean: // Convert to string and advance toStr(ptr, end - ptr, _data[i]); while (*ptr != 0) diff --git a/inkcpp/string_utils.h b/inkcpp/string_utils.h index 5924af95..c4eeba21 100644 --- a/inkcpp/string_utils.h +++ b/inkcpp/string_utils.h @@ -85,18 +85,18 @@ inline int toStr(char* buffer, size_t size, float value) return ec; } -inline int toStr(char* buffer, size_t size, const char* c) +inline int toStr(char* buffer, size_t size, const char* str) { char* ptr = buffer; size_t i = 0; - while (*c && i < size) { - *ptr++ = *c; + while (i < size && str[i]) { + ptr[i] = str[i]; ++i; } if (i >= size) { return EINVAL; } - *ptr = 0; + ptr[i] = 0; return 0; } @@ -113,7 +113,7 @@ inline int toStr(char* buffer, size_t size, const value& v) case value_type::float32: return toStr(buffer, size, v.get()); case value_type::boolean: return toStr(buffer, size, v.get()); case value_type::newline: return toStr(buffer, size, "\n"); - default: inkFail("only support toStr for numeric types"); return -1; + default: inkFail("No toStr implementation for this type"); return -1; } } @@ -148,6 +148,8 @@ inline constexpr size_t value_length(const value& v) case value_type::uint32: return decimal_digits(v.get()); case value_type::float32: return decimal_digits(v.get()); case value_type::string: return c_str_len(v.get()); + case value_type::boolean: + return v.get() ? c_str_len("true") : c_str_len("false"); case value_type::newline: return 1; default: inkFail("Can't determine length of this value type"); return -1; } diff --git a/inkcpp_test/CMakeLists.txt b/inkcpp_test/CMakeLists.txt index 2f292f46..1a628535 100644 --- a/inkcpp_test/CMakeLists.txt +++ b/inkcpp_test/CMakeLists.txt @@ -17,6 +17,7 @@ add_executable(inkcpp_test catch.hpp Main.cpp ThirdTierChoiceAfterBrackets.cpp NoEarlyTags.cpp ExternalFunctionsExecuteProperly.cpp + ExternalFunctionTypes.cpp LookaheadSafe.cpp EmptyStringForDivert.cpp MoveTo.cpp diff --git a/inkcpp_test/ExternalFunctionTypes.cpp b/inkcpp_test/ExternalFunctionTypes.cpp new file mode 100644 index 00000000..4c693f5f --- /dev/null +++ b/inkcpp_test/ExternalFunctionTypes.cpp @@ -0,0 +1,48 @@ +#include "catch.hpp" + +#include <../runner_impl.h> +#include +#include +#include +#include + +using namespace ink::runtime; + +SCENARIO("a story with external functions support types", "[story]") +{ + GIVEN("a story with external functions") + { + auto ink = story::from_file(INK_TEST_RESOURCE_DIR "ExternalFunctionTypes.bin"); + auto thread = ink->new_runner().cast(); + + std::stringstream debug; + thread->set_debug_enabled(&debug); + + bool b = false; + int i = 0; + unsigned int u = 0; + float f = 0; + std::string s; + + thread->bind("SET_BOOL", [&b](bool o) { b = o; }); + thread->bind("SET_INT", [&i](int o) { i = o; }); + thread->bind("SET_UINT", [&u](unsigned int o) { u = o; }); + thread->bind("SET_FLOAT", [&f](float o) { f = o; }); + thread->bind("SET_STRING", [&s](std::string o) { s = o; }); + + thread->bind("GET_BOOL", [&b]() { return b; }); + thread->bind("GET_INT", [&i]() { return i; }); + thread->bind("GET_UINT", [&u]() { return u; }); + thread->bind("GET_FLOAT", [&f]() { return f; }); + thread->bind("GET_STRING", [&s]() { return s; }); + + WHEN("run thread") + { + THEN("output shows values from ink") + { + auto line = thread->getline(); + REQUIRE(line == "true 1.5 -5 17 foo\n"); + } + } + } +} diff --git a/inkcpp_test/ink/ExternalFunctionTypes.ink b/inkcpp_test/ink/ExternalFunctionTypes.ink new file mode 100644 index 00000000..004a13df --- /dev/null +++ b/inkcpp_test/ink/ExternalFunctionTypes.ink @@ -0,0 +1,20 @@ +EXTERNAL GET_BOOL() +EXTERNAL GET_FLOAT() +EXTERNAL GET_INT() +EXTERNAL GET_UINT() +EXTERNAL GET_STRING() +EXTERNAL SET_BOOL(b) +EXTERNAL SET_FLOAT(f) +EXTERNAL SET_INT(i) +EXTERNAL SET_UINT(i) +EXTERNAL SET_STRING(s) + +~ SET_BOOL(true) +~ SET_FLOAT(1.5) +~ SET_INT(-5) +~ SET_UINT(17) +~ SET_STRING("foo") + +{GET_BOOL()} {GET_FLOAT()} {GET_INT()} {GET_UINT()} {GET_STRING()} + +-> DONE