diff --git a/backend/JavaScriptCore/JscUtils.cc b/backend/JavaScriptCore/JscUtils.cc index bfa30a8c..f2fc0e78 100644 --- a/backend/JavaScriptCore/JscUtils.cc +++ b/backend/JavaScriptCore/JscUtils.cc @@ -73,7 +73,7 @@ std::string_view StringHolder::stringView() const { std::string StringHolder::string() const { jsc_backend::initString(internalHolder_); internalHolder_.inited = false; - return std::move(internalHolder_.stringContent); + return internalHolder_.stringContent; } #if defined(__cpp_char8_t) diff --git a/backend/Python/CMakeLists.txt b/backend/Python/CMakeLists.txt index 6d96b276..161c361c 100644 --- a/backend/Python/CMakeLists.txt +++ b/backend/Python/CMakeLists.txt @@ -1 +1,16 @@ -message(FATAL_ERROR "${SCRIPTX_BACKEND} is to be implemented.") +target_sources(ScriptX PRIVATE + ${CMAKE_CURRENT_LIST_DIR}/PyEngine.cc + ${CMAKE_CURRENT_LIST_DIR}/PyEngine.h + ${CMAKE_CURRENT_LIST_DIR}/PyException.cc + ${CMAKE_CURRENT_LIST_DIR}/PyHelper.h + ${CMAKE_CURRENT_LIST_DIR}/PyHelper.hpp + ${CMAKE_CURRENT_LIST_DIR}/PyHelper.cc + ${CMAKE_CURRENT_LIST_DIR}/PyLocalReference.cc + ${CMAKE_CURRENT_LIST_DIR}/PyNative.cc + ${CMAKE_CURRENT_LIST_DIR}/PyNative.hpp + ${CMAKE_CURRENT_LIST_DIR}/PyReference.hpp + ${CMAKE_CURRENT_LIST_DIR}/PyScope.h + ${CMAKE_CURRENT_LIST_DIR}/PyScope.cc + ${CMAKE_CURRENT_LIST_DIR}/PyUtils.cc + ${CMAKE_CURRENT_LIST_DIR}/PyValue.cc + ) \ No newline at end of file diff --git a/backend/Python/PyEngine.cc b/backend/Python/PyEngine.cc new file mode 100644 index 00000000..2d3c2dea --- /dev/null +++ b/backend/Python/PyEngine.cc @@ -0,0 +1,60 @@ +/* + * Tencent is pleased to support the open source community by making ScriptX available. + * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "PyEngine.h" +#include "../../src/Utils.h" + +namespace script::py_backend { + +PyEngine::PyEngine(std::shared_ptr queue) + : queue_(queue ? std::move(queue) : std::make_shared()) { + Py_Initialize(); +} + +PyEngine::PyEngine() : PyEngine(nullptr) {} + +PyEngine::~PyEngine() = default; + +void PyEngine::destroy() noexcept { ScriptEngine::destroyUserData(); } + +Local PyEngine::get(const Local& key) { return Local(); } + +void PyEngine::set(const Local& key, const Local& value) {} + +Local PyEngine::eval(const Local& script) { return eval(script, Local()); } + +Local PyEngine::eval(const Local& script, const Local& sourceFile) { + return eval(script, sourceFile.asValue()); +} + +Local PyEngine::eval(const Local& script, const Local& sourceFile) { + return Local(); +} + +std::shared_ptr PyEngine::messageQueue() { return queue_; } + +void PyEngine::gc() {} + +void PyEngine::adjustAssociatedMemory(int64_t count) {} + +ScriptLanguage PyEngine::getLanguageType() { return ScriptLanguage::kPython; } + +std::string PyEngine::getEngineVersion() { return Py_GetVersion(); } + +bool PyEngine::isDestroying() const { return false; } + +} // namespace script::py_backend diff --git a/backend/Python/PyEngine.h b/backend/Python/PyEngine.h new file mode 100644 index 00000000..e1c57249 --- /dev/null +++ b/backend/Python/PyEngine.h @@ -0,0 +1,118 @@ +/* + * Tencent is pleased to support the open source community by making ScriptX available. + * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "../../src/Engine.h" +#include "../../src/Exception.h" +#include "../../src/utils/MessageQueue.h" +#include "PyHelper.h" + +namespace script::py_backend { + +class PyEngine : public ScriptEngine { + private: + std::shared_ptr<::script::utils::MessageQueue> queue_; + + public: + PyEngine(std::shared_ptr<::script::utils::MessageQueue> queue); + + PyEngine(); + + SCRIPTX_DISALLOW_COPY_AND_MOVE(PyEngine); + + void destroy() noexcept override; + + bool isDestroying() const override; + + Local get(const Local& key) override; + + void set(const Local& key, const Local& value) override; + using ScriptEngine::set; + + Local eval(const Local& script, const Local& sourceFile); + Local eval(const Local& script, const Local& sourceFile) override; + Local eval(const Local& script) override; + using ScriptEngine::eval; + + std::shared_ptr messageQueue() override; + + void gc() override; + + void adjustAssociatedMemory(int64_t count) override; + + ScriptLanguage getLanguageType() override; + + std::string getEngineVersion() override; + + protected: + ~PyEngine() override; + + private: + template + bool registerNativeClassImpl(const ClassDefine* classDefine) { + return false; + } + + Local getNamespaceForRegister(const std::string_view& nameSpace) { + TEMPLATE_NOT_IMPLEMENTED(); + } + + template + Local newNativeClassImpl(const ClassDefine* classDefine, size_t size, + const Local* args) { + TEMPLATE_NOT_IMPLEMENTED(); + } + + template + bool isInstanceOfImpl(const Local& value, const ClassDefine* classDefine) { + return false; + } + + template + T* getNativeInstanceImpl(const Local& value, const ClassDefine* classDefine) { + return nullptr; + } + + private: + template + friend class ::script::Local; + + template + friend class ::script::Global; + + template + friend class ::script::Weak; + + friend class ::script::Object; + + friend class ::script::Array; + + friend class ::script::Function; + + friend class ::script::ByteBuffer; + + friend class ::script::ScriptEngine; + + friend class ::script::Exception; + + friend class ::script::Arguments; + + friend class ::script::ScriptClass; +}; + +} // namespace script::py_backend \ No newline at end of file diff --git a/backend/Python/PyException.cc b/backend/Python/PyException.cc new file mode 100644 index 00000000..871a0f3c --- /dev/null +++ b/backend/Python/PyException.cc @@ -0,0 +1,40 @@ +/* + * Tencent is pleased to support the open source community by making ScriptX available. + * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace script { + +Exception::Exception(std::string msg) : std::exception(), exception_({}) { + exception_.message_ = std::move(msg); +} + +Exception::Exception(const script::Local& message) + : std::exception(), exception_() {} + +Exception::Exception(const script::Local& exception) + : std::exception(), exception_({}) {} + +Local Exception::exception() const { return {}; } + +std::string Exception::message() const noexcept { return exception_.message_; } + +std::string Exception::stacktrace() const noexcept { return "[no stacktrace]"; } + +const char* Exception::what() const noexcept { return exception_.message_.c_str(); } + +} // namespace script diff --git a/backend/Python/PyHelper.cc b/backend/Python/PyHelper.cc new file mode 100644 index 00000000..ced86204 --- /dev/null +++ b/backend/Python/PyHelper.cc @@ -0,0 +1,40 @@ +/* + * Tencent is pleased to support the open source community by making ScriptX available. + * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "PyHelper.hpp" + +namespace script::py_backend { + +PyObject* checkException(PyObject* obj) { + if (!obj) { + checkException(); + } + return obj; +} + +void checkException() { + auto err = PyErr_Occurred(); + if (err) { + // TODO + } +} + +void rethrowException(const Exception& exception) { + // TODO +} + +} // namespace script::py_backend \ No newline at end of file diff --git a/backend/Python/PyHelper.h b/backend/Python/PyHelper.h new file mode 100644 index 00000000..fb9b5d81 --- /dev/null +++ b/backend/Python/PyHelper.h @@ -0,0 +1,43 @@ +/* + * Tencent is pleased to support the open source community by making ScriptX available. + * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "../../src/foundation.h" + +// docs: +// https://docs.python.org/3/c-api/index.html +// https://docs.python.org/3/extending/embedding.html +// https://docs.python.org/3.8/c-api/init.html#thread-state-and-the-global-interpreter-lock + +SCRIPTX_BEGIN_INCLUDE_LIBRARY +#ifndef PY_SSIZE_T_CLEAN +#define PY_SSIZE_T_CLEAN +#endif +#include +#include +SCRIPTX_END_INCLUDE_LIBRARY + +namespace script::py_backend { + +class PyEngine; + +PyObject* checkException(PyObject* obj); +void checkException(); +void rethrowException(const Exception& exception); + +} // namespace script::py_backend diff --git a/backend/Python/PyHelper.hpp b/backend/Python/PyHelper.hpp new file mode 100644 index 00000000..c3ef7e21 --- /dev/null +++ b/backend/Python/PyHelper.hpp @@ -0,0 +1,53 @@ +/* + * Tencent is pleased to support the open source community by making ScriptX available. + * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include "../../src/Native.hpp" +#include "../../src/Reference.h" +#include "PyEngine.h" +#include "PyHelper.h" + +namespace script { + +struct py_interop { + template + static Local makeLocal(PyObject* ref) { + return Local(ref); + } + + /** + * @return stolen ref. + */ + template + static PyObject* toPy(const Local& ref) { + return Py_XNewRef(ref.val_); + } + + /** + * @return borrowed ref. + */ + template + static PyObject* asPy(const Local& ref) { + return ref.val_; + } + + static Arguments makeArguments(py_backend::PyEngine* engine, PyObject* self, PyObject* args) { + return Arguments(py_backend::ArgumentsData{engine, self, args}); + } +}; + +} // namespace script \ No newline at end of file diff --git a/backend/Python/PyLocalReference.cc b/backend/Python/PyLocalReference.cc new file mode 100644 index 00000000..4bac19aa --- /dev/null +++ b/backend/Python/PyLocalReference.cc @@ -0,0 +1,267 @@ +/* + * Tencent is pleased to support the open source community by making ScriptX available. + * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "../../src/Native.hpp" +#include "../../src/Reference.h" +#include "../../src/Utils.h" +#include "../../src/Value.h" +#include "PyHelper.hpp" +#include "PyReference.hpp" + +namespace script { + +namespace py_backend { +void valueConstructorCheck(PyObject* value) { + SCRIPTX_UNUSED(value); +#ifndef NDEBUG + if (!value) throw Exception("null reference"); +#endif +} +} // namespace py_backend + +#define REF_IMPL_BASIC_FUNC(ValueType) \ + Local::Local(const Local& copy) : val_(py_backend::incRef(copy.val_)) {} \ + Local::Local(Local&& move) noexcept : val_(move.val_) { \ + move.val_ = nullptr; \ + } \ + Local::~Local() { py_backend::decRef(val_); } \ + Local& Local::operator=(const Local& from) { \ + Local(from).swap(*this); \ + return *this; \ + } \ + Local& Local::operator=(Local&& move) noexcept { \ + Local(std::move(move)).swap(*this); \ + return *this; \ + } \ + void Local::swap(Local& rhs) noexcept { std::swap(val_, rhs.val_); } + +#define REF_IMPL_BASIC_EQUALS(ValueType) \ + bool Local::operator==(const script::Local& other) const { \ + return asValue() == other; \ + } + +#define REF_IMPL_BASIC_NOT_VALUE(ValueType) \ + Local::Local(InternalLocalRef val) : val_(val) { \ + py_backend::valueConstructorCheck(val); \ + } \ + Local Local::describe() const { return asValue().describe(); } \ + std::string Local::describeUtf8() const { return asValue().describeUtf8(); } + +#define REF_IMPL_TO_VALUE(ValueType) \ + Local Local::asValue() const { return Local(py_backend::incRef(val_)); } + +REF_IMPL_BASIC_FUNC(Value) + +REF_IMPL_BASIC_FUNC(Object) +REF_IMPL_BASIC_NOT_VALUE(Object) +REF_IMPL_BASIC_EQUALS(Object) +REF_IMPL_TO_VALUE(Object) + +REF_IMPL_BASIC_FUNC(String) +REF_IMPL_BASIC_NOT_VALUE(String) +REF_IMPL_BASIC_EQUALS(String) +REF_IMPL_TO_VALUE(String) + +REF_IMPL_BASIC_FUNC(Number) +REF_IMPL_BASIC_NOT_VALUE(Number) +REF_IMPL_BASIC_EQUALS(Number) +REF_IMPL_TO_VALUE(Number) + +REF_IMPL_BASIC_FUNC(Boolean) +REF_IMPL_BASIC_NOT_VALUE(Boolean) +REF_IMPL_BASIC_EQUALS(Boolean) +REF_IMPL_TO_VALUE(Boolean) + +REF_IMPL_BASIC_FUNC(Function) +REF_IMPL_BASIC_NOT_VALUE(Function) +REF_IMPL_BASIC_EQUALS(Function) +REF_IMPL_TO_VALUE(Function) + +REF_IMPL_BASIC_FUNC(Array) +REF_IMPL_BASIC_NOT_VALUE(Array) +REF_IMPL_BASIC_EQUALS(Array) +REF_IMPL_TO_VALUE(Array) + +REF_IMPL_BASIC_FUNC(ByteBuffer) +REF_IMPL_BASIC_NOT_VALUE(ByteBuffer) +REF_IMPL_BASIC_EQUALS(ByteBuffer) +REF_IMPL_TO_VALUE(ByteBuffer) + +REF_IMPL_BASIC_FUNC(Unsupported) +REF_IMPL_BASIC_NOT_VALUE(Unsupported) +REF_IMPL_BASIC_EQUALS(Unsupported) +REF_IMPL_TO_VALUE(Unsupported) + +// ==== value ==== + +Local::Local() noexcept : val_() {} + +Local::Local(InternalLocalRef ref) : val_(ref) {} + +bool Local::isNull() const { return val_ == nullptr; } + +void Local::reset() { + py_backend::decRef(val_); + val_ = nullptr; +} + +ValueKind Local::getKind() const { + if (isNull()) { + return ValueKind::kNull; + } else if (isString()) { + return ValueKind::kString; + } else if (isNumber()) { + return ValueKind::kNumber; + } else if (isBoolean()) { + return ValueKind::kBoolean; + } else if (isFunction()) { + return ValueKind::kFunction; + } else if (isArray()) { + return ValueKind::kArray; + } else if (isByteBuffer()) { + return ValueKind::kByteBuffer; + } else if (isObject()) { + return ValueKind::kObject; + } else { + return ValueKind::kUnsupported; + } +} + +bool Local::isString() const { return false; } + +bool Local::isNumber() const { return PyNumber_Check(val_); } + +bool Local::isBoolean() const { return PyBool_Check(val_); } + +bool Local::isFunction() const { return PyCallable_Check(val_); } + +bool Local::isArray() const { return false; } + +bool Local::isByteBuffer() const { return false; } + +bool Local::isObject() const { return false; } + +bool Local::isUnsupported() const { return false; } + +Local Local::asString() const { throw Exception("can't cast value as String"); } + +Local Local::asNumber() const { throw Exception("can't cast value as Number"); } + +Local Local::asBoolean() const { throw Exception("can't cast value as Boolean"); } + +Local Local::asFunction() const { + throw Exception("can't cast value as Function"); +} + +Local Local::asArray() const { throw Exception("can't cast value as Array"); } + +Local Local::asByteBuffer() const { + throw Exception("can't cast value as ByteBuffer"); +} + +Local Local::asObject() const { throw Exception("can't cast value as Object"); } + +Local Local::asUnsupported() const { + throw Exception("can't cast value as Unsupported"); +} + +bool Local::operator==(const script::Local& other) const { + // TODO: nullptr vs None + auto lhs = val_; + auto rhs = other.val_; + + // nullptr == nullptr + if (lhs == nullptr || rhs == nullptr) { + return lhs == rhs; + } + + return PyObject_RichCompareBool(lhs, rhs, Py_EQ); +} + +Local Local::describe() const { TEMPLATE_NOT_IMPLEMENTED(); } + +Local Local::get(const script::Local& key) const { return {}; } + +void Local::set(const script::Local& key, + const script::Local& value) const {} + +void Local::remove(const Local& key) const {} +bool Local::has(const Local& key) const { return true; } + +bool Local::instanceOf(const Local& type) const { return false; } + +std::vector> Local::getKeys() const { return {}; } + +float Local::toFloat() const { return static_cast(toDouble()); } + +double Local::toDouble() const { return 0; } + +int32_t Local::toInt32() const { return static_cast(toDouble()); } + +int64_t Local::toInt64() const { return static_cast(toDouble()); } + +bool Local::value() const { return false; } + +Local Local::callImpl(const Local& thiz, size_t size, + const Local* args) const { + // PyObject* self = thiz.isObject() ? py_interop::toPy(thiz) : nullptr; + // TODO: self + PyObject* ret = nullptr; + // args to tuple + if (size == 0) { + ret = PyObject_CallNoArgs(py_interop::asPy(*this)); + } else if (size == 1) { + ret = PyObject_CallOneArg(py_interop::asPy(*this), py_interop::asPy(args[0])); + } else { + auto tuple = PyTuple_New(static_cast(size)); + py_backend::checkException(); + for (size_t i = 0; i < size; ++i) { + PyTuple_SetItem(tuple, static_cast(i), py_interop::toPy(args[i])); + py_backend::checkException(); + } + ret = PyObject_Call(py_interop::asPy(*this), tuple, nullptr); + } + + py_backend::checkException(); + return Local(ret); +} + +size_t Local::size() const { return 0; } + +Local Local::get(size_t index) const { return {}; } + +void Local::set(size_t index, const script::Local& value) const {} + +void Local::add(const script::Local& value) const { set(size(), value); } + +void Local::clear() const {} + +ByteBuffer::Type Local::getType() const { return ByteBuffer::Type::KFloat32; } + +bool Local::isShared() const { return true; } + +void Local::commit() const {} + +void Local::sync() const {} + +size_t Local::byteLength() const { return 0; } + +void* Local::getRawBytes() const { return nullptr; } + +std::shared_ptr Local::getRawBytesShared() const { return {}; } + +} // namespace script diff --git a/backend/Python/PyNative.cc b/backend/Python/PyNative.cc new file mode 100644 index 00000000..703a43c0 --- /dev/null +++ b/backend/Python/PyNative.cc @@ -0,0 +1,61 @@ +/* + * Tencent is pleased to support the open source community by making ScriptX available. + * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "../../src/Native.hpp" +#include "PyEngine.h" +#include "PyHelper.hpp" + +namespace script { + +Arguments::Arguments(InternalCallbackInfoType callbackInfo) : callbackInfo_(callbackInfo) {} + +Arguments::~Arguments() = default; + +Local Arguments::thiz() const { + return py_interop::makeLocal(callbackInfo_.self).asObject(); +} + +bool Arguments::hasThiz() const { return callbackInfo_.self != nullptr; } + +size_t Arguments::size() const { + if (!callbackInfo_.args) { + return 0; + } + return PyTuple_Size(callbackInfo_.args); +} + +Local Arguments::operator[](size_t i) const { + if (i < size()) { + return py_interop::makeLocal(PyTuple_GetItem(callbackInfo_.args, i)); + } + return {}; +} + +ScriptEngine* Arguments::engine() const { return callbackInfo_.engine; } + +ScriptClass::ScriptClass(const script::Local& scriptObject) : internalState_() { + TEMPLATE_NOT_IMPLEMENTED(); +} + +Local ScriptClass::getScriptObject() const { TEMPLATE_NOT_IMPLEMENTED(); } + +Local ScriptClass::getInternalStore() const { TEMPLATE_NOT_IMPLEMENTED(); } + +ScriptEngine* ScriptClass::getScriptEngine() const { TEMPLATE_NOT_IMPLEMENTED(); } + +ScriptClass::~ScriptClass() = default; +} // namespace script \ No newline at end of file diff --git a/backend/Python/PyNative.hpp b/backend/Python/PyNative.hpp new file mode 100644 index 00000000..ec9c2626 --- /dev/null +++ b/backend/Python/PyNative.hpp @@ -0,0 +1,33 @@ +/* + * Tencent is pleased to support the open source community by making ScriptX available. + * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "../../src/Native.h" +#include "PyEngine.h" + +namespace script { + +template +ScriptClass::ScriptClass(const ScriptClass::ConstructFromCpp) : internalState_() {} + +template +T* Arguments::engineAs() const { + return nullptr; +} + +} // namespace script \ No newline at end of file diff --git a/backend/Python/PyReference.hpp b/backend/Python/PyReference.hpp new file mode 100644 index 00000000..393788a4 --- /dev/null +++ b/backend/Python/PyReference.hpp @@ -0,0 +1,150 @@ +/* + * Tencent is pleased to support the open source community by making ScriptX available. + * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include + +namespace script { + +namespace py_backend { + +inline PyObject* incRef(PyObject* ref) { return Py_XNewRef(ref); } + +inline void decRef(PyObject* ref) { Py_XDECREF(ref); } + +} // namespace py_backend + +template +Global::Global() noexcept : val_() {} + +template +Global::Global(const script::Local& localReference) {} + +template +Global::Global(const script::Weak& weak) {} + +template +Global::Global(const script::Global& copy) : val_(copy.val_) {} + +template +Global::Global(script::Global&& move) noexcept : val_(move.val_) {} + +template +Global::~Global() {} + +template +Global& Global::operator=(const script::Global& assign) { + Global(assign).swap(*this); + return *this; +} + +template +Global& Global::operator=(script::Global&& move) noexcept { + Global(std::move(move)).swap(*this); + return *this; +} + +template +void Global::swap(Global& rhs) noexcept {} + +template +Global& Global::operator=(const script::Local& assign) { + *this = Global(assign); + return *this; +} + +template +Local Global::get() const { + TEMPLATE_NOT_IMPLEMENTED(); +} + +template +Local Global::getValue() const { + TEMPLATE_NOT_IMPLEMENTED(); +} + +template +bool Global::isEmpty() const { + return false; +} + +template +void Global::reset() {} + +// == Weak == + +template +Weak::Weak() noexcept : val_() {} + +template +Weak::~Weak() {} + +template +Weak::Weak(const script::Local& localReference) {} + +template +Weak::Weak(const script::Global& globalReference) {} + +template +Weak::Weak(const script::Weak& copy) : val_(copy.val_) {} + +template +Weak::Weak(script::Weak&& move) noexcept : val_(std::move(move.val_)) {} + +template +Weak& Weak::operator=(const script::Weak& assign) { + val_ = assign.val_; + return *this; +} + +template +Weak& Weak::operator=(script::Weak&& move) noexcept { + val_ = std::move(move.val_); + return *this; +} + +template +void Weak::swap(Weak& rhs) noexcept { + std::swap(val_, rhs.val_); +} + +template +Weak& Weak::operator=(const script::Local& assign) { + *this = Weak(assign); + return *this; +} + +template +Local Weak::get() const { + if (isEmpty()) throw Exception("get on empty Weak"); + TEMPLATE_NOT_IMPLEMENTED(); +} + +template +Local Weak::getValue() const { + TEMPLATE_NOT_IMPLEMENTED(); +} + +template +bool Weak::isEmpty() const { + return false; +} + +template +void Weak::reset() noexcept {} + +} // namespace script diff --git a/backend/Python/PyScope.cc b/backend/Python/PyScope.cc new file mode 100644 index 00000000..fd45effb --- /dev/null +++ b/backend/Python/PyScope.cc @@ -0,0 +1,31 @@ +/* + * Tencent is pleased to support the open source community by making ScriptX available. + * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "PyScope.h" + +// reference +// https://docs.python.org/3.8/c-api/init.html#thread-state-and-the-global-interpreter-lock + +namespace script::py_backend { + +EngineScopeImpl::EngineScopeImpl(PyEngine &, PyEngine *) : gilState_(PyGILState_Ensure()) {} +EngineScopeImpl::~EngineScopeImpl() { PyGILState_Release(gilState_); } + +ExitEngineScopeImpl::ExitEngineScopeImpl(PyEngine &) : threadState(PyEval_SaveThread()) {} +ExitEngineScopeImpl::~ExitEngineScopeImpl() { PyEval_RestoreThread(threadState); } + +} // namespace script::py_backend \ No newline at end of file diff --git a/backend/Python/PyScope.h b/backend/Python/PyScope.h new file mode 100644 index 00000000..0d6f98ae --- /dev/null +++ b/backend/Python/PyScope.h @@ -0,0 +1,53 @@ +/* + * Tencent is pleased to support the open source community by making ScriptX available. + * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include "../../src/Reference.h" +#include "PyHelper.h" + +namespace script::py_backend { + +class PyEngine; + +class EngineScopeImpl { + PyGILState_STATE gilState_; + + public: + explicit EngineScopeImpl(PyEngine &, PyEngine *); + + ~EngineScopeImpl(); +}; + +class ExitEngineScopeImpl { + PyThreadState *threadState; + + public: + explicit ExitEngineScopeImpl(PyEngine &); + + ~ExitEngineScopeImpl(); +}; + +class StackFrameScopeImpl { + public: + explicit StackFrameScopeImpl(PyEngine &) {} + + template + Local returnValue(const Local &localRef) { + return localRef; + } +}; +} // namespace script::py_backend diff --git a/backend/Python/PyUtils.cc b/backend/Python/PyUtils.cc new file mode 100644 index 00000000..cd4bf063 --- /dev/null +++ b/backend/Python/PyUtils.cc @@ -0,0 +1,46 @@ +/* + * Tencent is pleased to support the open source community by making ScriptX available. + * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace script { + +StringHolder::StringHolder(const script::Local &string) {} + +StringHolder::~StringHolder() = default; + +size_t StringHolder::length() const { return 0; } + +const char *StringHolder::c_str() const { return ""; } + +std::string_view StringHolder::stringView() const { return {}; } + +std::string StringHolder::string() const { return {}; } + +#if defined(__cpp_char8_t) +// NOLINTNEXTLINE(clang-analyzer-cplusplus.InnerPointer) +std::u8string StringHolder::u8string() const { return std::u8string(c_u8str(), length()); } + +std::u8string_view StringHolder::u8stringView() const { + // NOLINTNEXTLINE(clang-analyzer-cplusplus.InnerPointer) + return std::u8string_view(c_u8str(), length()); +} + +const char8_t *StringHolder::c_u8str() const { return reinterpret_cast(c_str()); } +#endif + +} // namespace script diff --git a/backend/Python/PyValue.cc b/backend/Python/PyValue.cc new file mode 100644 index 00000000..3c8fda2e --- /dev/null +++ b/backend/Python/PyValue.cc @@ -0,0 +1,156 @@ +/* + * Tencent is pleased to support the open source community by making ScriptX available. + * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "../../src/Exception.h" +#include "../../src/Reference.h" +#include "../../src/Scope.h" +#include "../../src/Value.h" +#include "PyHelper.hpp" + +using script::py_interop; +using script::py_backend::checkException; + +namespace script { + +template +Local checkAndMakeLocal(PyObject* ref) { + return py_interop::makeLocal(checkException(ref)); +} + +// for python this creates an empty dict +Local Object::newObject() { return checkAndMakeLocal(PyDict_New()); } + +Local Object::newObjectImpl(const Local& type, size_t size, + const Local* args) { + TEMPLATE_NOT_IMPLEMENTED(); +} + +Local String::newString(const char* utf8) { + return checkAndMakeLocal(PyBytes_FromString(utf8)); +} + +Local String::newString(std::string_view utf8) { + return checkAndMakeLocal( + PyBytes_FromStringAndSize(utf8.data(), static_cast(utf8.length()))); +} + +Local String::newString(const std::string& utf8) { + return checkAndMakeLocal( + PyBytes_FromStringAndSize(utf8.c_str(), static_cast(utf8.length()))); +} + +#if defined(__cpp_char8_t) + +Local String::newString(const char8_t* utf8) { + return newString(reinterpret_cast(utf8)); +} + +Local String::newString(std::u8string_view utf8) { + return newString(std::string_view(reinterpret_cast(utf8.data()), utf8.length())); +} + +Local String::newString(const std::u8string& utf8) { return newString(utf8.c_str()); } + +#endif + +Local Number::newNumber(float value) { return newNumber(static_cast(value)); } + +Local Number::newNumber(double value) { + return checkAndMakeLocal(PyLong_FromDouble(value)); +} + +Local Number::newNumber(int32_t value) { + return checkAndMakeLocal(PyLong_FromLong(static_cast(value))); +} + +Local Number::newNumber(int64_t value) { + return checkAndMakeLocal(PyLong_FromLongLong(static_cast(value))); +} + +Local Boolean::newBoolean(bool value) { + return checkAndMakeLocal(PyBool_FromLong(value)); +} + +namespace { + +static constexpr const char* kFunctionDataName = "_ScriptX_function_data"; + +struct FunctionData { + FunctionCallback function; + py_backend::PyEngine* engine = nullptr; +}; + +} // namespace + +Local Function::newFunction(script::FunctionCallback callback) { + auto callbackIns = std::make_unique(); + callbackIns->engine = EngineScope::currentEngineAs(); + callbackIns->function = std::move(callback); + + PyMethodDef method{}; + method.ml_name = "ScriptX_native_method"; + method.ml_flags = METH_O; + method.ml_doc = "ScriptX Function::newFunction"; + method.ml_meth = [](PyObject* self, PyObject* args) -> PyObject* { + auto ptr = PyCapsule_GetPointer(self, kFunctionDataName); + if (ptr == nullptr) { + ::PyErr_SetString(PyExc_TypeError, "invalid 'self' for native method"); + } else { + auto data = static_cast(ptr); + try { + auto ret = data->function(py_interop::makeArguments(nullptr, self, args)); + return py_interop::toPy(ret); + } catch (Exception& e) { + py_backend::rethrowException(e); + } + } + return nullptr; + }; + + auto ctx = PyCapsule_New(callbackIns.get(), kFunctionDataName, [](PyObject* cap) { + auto ptr = PyCapsule_GetPointer(cap, kFunctionDataName); + delete static_cast(ptr); + }); + py_backend::checkException(ctx); + callbackIns.release(); + + PyObject* closure = PyCFunction_New(&method, ctx); + Py_XDECREF(ctx); + py_backend::checkException(closure); + + return Local(closure); +} + +Local Array::newArray(size_t size) { + return checkAndMakeLocal(PyList_New(static_cast(size))); +} + +Local Array::newArrayImpl(size_t size, const Local* args) { + TEMPLATE_NOT_IMPLEMENTED(); +} + +Local ByteBuffer::newByteBuffer(size_t size) { TEMPLATE_NOT_IMPLEMENTED(); } + +Local ByteBuffer::newByteBuffer(void* nativeBuffer, size_t size) { + TEMPLATE_NOT_IMPLEMENTED(); +} + +Local ByteBuffer::newByteBuffer(std::shared_ptr nativeBuffer, size_t size) { + TEMPLATE_NOT_IMPLEMENTED(); +} + +} // namespace script \ No newline at end of file diff --git a/backend/Python/trait/TraitEngine.h b/backend/Python/trait/TraitEngine.h new file mode 100644 index 00000000..8d6592be --- /dev/null +++ b/backend/Python/trait/TraitEngine.h @@ -0,0 +1,36 @@ +/* + * Tencent is pleased to support the open source community by making ScriptX available. + * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include "../../src/types.h" + +#define TEMPLATE_NOT_IMPLEMENTED() throw Exception(std::string(__func__) + " not implemented"); + +namespace script { + +namespace py_backend { +class PyEngine; +} + +template <> +struct internal::ImplType { + using type = py_backend::PyEngine; +}; + +} // namespace script \ No newline at end of file diff --git a/backend/Python/trait/TraitException.h b/backend/Python/trait/TraitException.h new file mode 100644 index 00000000..80b13f49 --- /dev/null +++ b/backend/Python/trait/TraitException.h @@ -0,0 +1,38 @@ +/* + * Tencent is pleased to support the open source community by making ScriptX available. + * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include +#include "../../src/types.h" + +namespace script { + +namespace py_backend { + +class ExceptionFields { + public: + mutable std::string message_{}; +}; + +} // namespace py_backend + +template <> +struct internal::ImplType { + using type = py_backend::ExceptionFields; +}; + +} // namespace script diff --git a/backend/Python/trait/TraitIncludes.h b/backend/Python/trait/TraitIncludes.h new file mode 100644 index 00000000..6f22d372 --- /dev/null +++ b/backend/Python/trait/TraitIncludes.h @@ -0,0 +1,26 @@ +/* + * Tencent is pleased to support the open source community by making ScriptX available. + * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "../PyEngine.h" +#include "../PyNative.hpp" +#include "../PyReference.hpp" + +// global marco +#define SCRIPTX_BACKEND_PYTHON +#define SCRIPTX_LANG_PYTHON \ No newline at end of file diff --git a/backend/Python/trait/TraitNative.h b/backend/Python/trait/TraitNative.h new file mode 100644 index 00000000..3022f038 --- /dev/null +++ b/backend/Python/trait/TraitNative.h @@ -0,0 +1,49 @@ +/* + * Tencent is pleased to support the open source community by making ScriptX available. + * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include "../../src/types.h" +#include "../PyHelper.h" + +namespace script { + +namespace py_backend { + +struct ArgumentsData { + mutable PyEngine* engine; + PyObject* self; + PyObject* args; +}; + +struct ScriptClassState { + ScriptEngine* scriptEngine_ = nullptr; + Weak weakRef_; +}; + +} // namespace py_backend + +template <> +struct internal::ImplType<::script::Arguments> { + using type = py_backend::ArgumentsData; +}; + +template <> +struct internal::ImplType<::script::ScriptClass> { + using type = py_backend::ScriptClassState; +}; + +} // namespace script \ No newline at end of file diff --git a/backend/Python/trait/TraitReference.h b/backend/Python/trait/TraitReference.h new file mode 100644 index 00000000..d45c7ed5 --- /dev/null +++ b/backend/Python/trait/TraitReference.h @@ -0,0 +1,42 @@ +/* + * Tencent is pleased to support the open source community by making ScriptX available. + * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include "../../src/types.h" +#include "../PyHelper.h" + +namespace script::internal { + +template +struct ImplType> { + using type = PyObject*; +}; + +template +struct ImplType> { + using type = PyObject*; +}; + +template +struct ImplType> { + using type = PyObject*; +}; + +} // namespace script::internal \ No newline at end of file diff --git a/backend/Python/trait/TraitScope.h b/backend/Python/trait/TraitScope.h new file mode 100644 index 00000000..d3cd8996 --- /dev/null +++ b/backend/Python/trait/TraitScope.h @@ -0,0 +1,40 @@ +/* + * Tencent is pleased to support the open source community by making ScriptX available. + * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "../PyScope.h" +#include "TraitEngine.h" + +namespace script { + +template <> +struct internal::ImplType { + using type = py_backend::EngineScopeImpl; +}; + +template <> +struct internal::ImplType { + using type = py_backend::ExitEngineScopeImpl; +}; + +template <> +struct internal::ImplType { + using type = py_backend::StackFrameScopeImpl; +}; + +} // namespace script \ No newline at end of file diff --git a/backend/Python/trait/TraitUtils.h b/backend/Python/trait/TraitUtils.h new file mode 100644 index 00000000..215f6802 --- /dev/null +++ b/backend/Python/trait/TraitUtils.h @@ -0,0 +1,35 @@ +/* + * Tencent is pleased to support the open source community by making ScriptX available. + * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include "../../src/types.h" + +namespace script { + +struct py_interop; + +template <> +struct internal::ImplType { + using type = int; +}; + +template <> +struct internal::ImplType { + using type = py_interop; +}; + +} // namespace script \ No newline at end of file diff --git a/backend/Template/trait/TraitNative.h b/backend/Template/trait/TraitNative.h index 568325b6..3077e648 100644 --- a/backend/Template/trait/TraitNative.h +++ b/backend/Template/trait/TraitNative.h @@ -26,7 +26,7 @@ struct ArgumentsData { size_t size; }; -struct JscScriptClassState { +struct ScriptClassState { ScriptEngine* scriptEngine_ = nullptr; Weak weakRef_; }; @@ -40,7 +40,7 @@ struct internal::ImplType<::script::Arguments> { template <> struct internal::ImplType<::script::ScriptClass> { - using type = template_backend::JscScriptClassState; + using type = template_backend::ScriptClassState; }; } // namespace script \ No newline at end of file diff --git a/test/cmake/TestEnv.cmake b/test/cmake/TestEnv.cmake index 1d582f2a..f04e0735 100644 --- a/test/cmake/TestEnv.cmake +++ b/test/cmake/TestEnv.cmake @@ -159,5 +159,10 @@ elseif (${SCRIPTX_BACKEND} STREQUAL WebAssembly) elseif (${SCRIPTX_BACKEND} STREQUAL QuickJs) include("${SCRIPTX_TEST_LIBS}/quickjs/CMakeLists.txt") set(DEVOPS_LIBS_LIBPATH QuickJs CACHE STRING "" FORCE) +elseif (${SCRIPTX_BACKEND} STREQUAL Python) + set(DEVOPS_LIBS_INCLUDE + "/usr/local/Cellar/python@3.10/3.10.0_2/Frameworks/Python.framework/Headers/" + CACHE STRING "" FORCE) + set(DEVOPS_LIBS_LIBPATH "/usr/local/Cellar/python@3.10/3.10.0_2/Frameworks/Python.framework/Versions/Current/lib/libpython3.10.dylib" CACHE STRING "" FORCE) endif () diff --git a/test/src/gtest_main.cc b/test/src/gtest_main.cc index e9a0258b..ab9c6c5d 100644 --- a/test/src/gtest_main.cc +++ b/test/src/gtest_main.cc @@ -65,13 +65,16 @@ void ScriptXTestFixture::SetUp() { using script::String; EngineScope engineScope(engine); +#if defined(SCRIPTX_LANG_JAVASCRIPT) && !defined(SCRIPTX_BACKEND_WEBASSEMBLY) auto log = Function::newFunction(consoleLog); -#ifndef SCRIPTX_BACKEND_WEBASSEMBLY auto console = Object::newObject(); console.set(String::newString(u8"log"), log); engine->set(String::newString(u8"console"), console); #endif +#ifdef SCRIPTX_BACKEND_LUA + auto log = Function::newFunction(consoleLog); engine->set(String::newString(u8"print"), log); +#endif } }