From 2a48144d6a94f98512903c344a7bcd135d728832 Mon Sep 17 00:00:00 2001
From: landerlyoung <landerlyoung@gmail.com>
Date: Sat, 1 May 2021 15:56:09 +0800
Subject: [PATCH 01/10] add python backend

---
 backend/Python/CMakeLists.txt         |  12 +-
 backend/Python/PyEngine.cc            |  59 +++++++
 backend/Python/PyEngine.h             | 115 ++++++++++++++
 backend/Python/PyException.cc         |  40 +++++
 backend/Python/PyLocalReference.cc    | 216 ++++++++++++++++++++++++++
 backend/Python/PyNative.cc            |  47 ++++++
 backend/Python/PyNative.hpp           |  33 ++++
 backend/Python/PyReference.hpp        | 142 +++++++++++++++++
 backend/Python/PyUtils.cc             |  46 ++++++
 backend/Python/PyValue.cc             |  82 ++++++++++
 backend/Python/trait/TraitEngine.h    |  36 +++++
 backend/Python/trait/TraitException.h |  36 +++++
 backend/Python/trait/TraitIncludes.h  |  26 ++++
 backend/Python/trait/TraitNative.h    |  46 ++++++
 backend/Python/trait/TraitReference.h |  41 +++++
 backend/Python/trait/TraitScope.h     |  80 ++++++++++
 backend/Python/trait/TraitUtils.h     |  32 ++++
 test/cmake/TestEnv.cmake              |   5 +
 18 files changed, 1093 insertions(+), 1 deletion(-)
 create mode 100644 backend/Python/PyEngine.cc
 create mode 100644 backend/Python/PyEngine.h
 create mode 100644 backend/Python/PyException.cc
 create mode 100644 backend/Python/PyLocalReference.cc
 create mode 100644 backend/Python/PyNative.cc
 create mode 100644 backend/Python/PyNative.hpp
 create mode 100644 backend/Python/PyReference.hpp
 create mode 100644 backend/Python/PyUtils.cc
 create mode 100644 backend/Python/PyValue.cc
 create mode 100644 backend/Python/trait/TraitEngine.h
 create mode 100644 backend/Python/trait/TraitException.h
 create mode 100644 backend/Python/trait/TraitIncludes.h
 create mode 100644 backend/Python/trait/TraitNative.h
 create mode 100644 backend/Python/trait/TraitReference.h
 create mode 100644 backend/Python/trait/TraitScope.h
 create mode 100644 backend/Python/trait/TraitUtils.h

diff --git a/backend/Python/CMakeLists.txt b/backend/Python/CMakeLists.txt
index 6d96b276..d547ca57 100644
--- a/backend/Python/CMakeLists.txt
+++ b/backend/Python/CMakeLists.txt
@@ -1 +1,11 @@
-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}/PyLocalReference.cc
+        ${CMAKE_CURRENT_LIST_DIR}/PyNative.cc
+        ${CMAKE_CURRENT_LIST_DIR}/PyNative.hpp
+        ${CMAKE_CURRENT_LIST_DIR}/PyReference.hpp
+        ${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..157cd0e8
--- /dev/null
+++ b/backend/Python/PyEngine.cc
@@ -0,0 +1,59 @@
+/*
+ * 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<utils::MessageQueue> queue) {}
+
+PyEngine::PyEngine() : PyEngine(std::shared_ptr<utils::MessageQueue>{}) {}
+
+PyEngine::~PyEngine() = default;
+
+void PyEngine::destroy() noexcept {}
+
+Local<Value> PyEngine::get(const Local<String>& key) { return Local<Value>(); }
+
+void PyEngine::set(const Local<String>& key, const Local<Value>& value) {}
+
+Local<Value> PyEngine::eval(const Local<String>& script) { return eval(script, Local<Value>()); }
+
+Local<Value> PyEngine::eval(const Local<String>& script, const Local<String>& sourceFile) {
+  return eval(script, sourceFile.asValue());
+}
+
+Local<Value> PyEngine::eval(const Local<String>& script, const Local<Value>& sourceFile) {
+  return Local<Value>();
+}
+
+std::shared_ptr<utils::MessageQueue> PyEngine::messageQueue() {
+  return std::shared_ptr<utils::MessageQueue>();
+}
+
+void PyEngine::gc() {}
+
+void PyEngine::adjustAssociatedMemory(int64_t count) {}
+
+ScriptLanguage PyEngine::getLanguageType() { return ScriptLanguage::kJavaScript; }
+
+std::string PyEngine::getEngineVersion() { return ""; }
+
+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..21df182d
--- /dev/null
+++ b/backend/Python/PyEngine.h
@@ -0,0 +1,115 @@
+/*
+ * 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"
+
+namespace script::py_backend {
+
+class PyEngine : public ScriptEngine {
+ protected:
+ 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<Value> get(const Local<String>& key) override;
+
+  void set(const Local<String>& key, const Local<Value>& value) override;
+  using ScriptEngine::set;
+
+  Local<Value> eval(const Local<String>& script, const Local<Value>& sourceFile);
+  Local<Value> eval(const Local<String>& script, const Local<String>& sourceFile) override;
+  Local<Value> eval(const Local<String>& script) override;
+  using ScriptEngine::eval;
+
+  std::shared_ptr<utils::MessageQueue> messageQueue() override;
+
+  void gc() override;
+
+  void adjustAssociatedMemory(int64_t count) override;
+
+  ScriptLanguage getLanguageType() override;
+
+  std::string getEngineVersion() override;
+
+ protected:
+  ~PyEngine() override;
+
+ private:
+  template <typename T>
+  bool registerNativeClassImpl(const ClassDefine<T>* classDefine) {
+    return false;
+  }
+
+  Local<Object> getNamespaceForRegister(const std::string_view& nameSpace) {
+    TEMPLATE_NOT_IMPLEMENTED();
+  }
+
+  template <typename T>
+  Local<Object> newNativeClassImpl(const ClassDefine<T>* classDefine, size_t size,
+                                   const Local<Value>* args) {
+    TEMPLATE_NOT_IMPLEMENTED();
+  }
+
+  template <typename T>
+  bool isInstanceOfImpl(const Local<Value>& value, const ClassDefine<T>* classDefine) {
+    return false;
+  }
+
+  template <typename T>
+  T* getNativeInstanceImpl(const Local<Value>& value, const ClassDefine<T>* classDefine) {
+    return nullptr;
+  }
+
+ private:
+  template <typename T>
+  friend class ::script::Local;
+
+  template <typename T>
+  friend class ::script::Global;
+
+  template <typename T>
+  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 <ScriptX/ScriptX.h>
+
+namespace script {
+
+Exception::Exception(std::string msg) : std::exception(), exception_({}) {
+  exception_.message_ = std::move(msg);
+}
+
+Exception::Exception(const script::Local<script::String>& message)
+    : std::exception(), exception_() {}
+
+Exception::Exception(const script::Local<script::Value>& exception)
+    : std::exception(), exception_({}) {}
+
+Local<Value> 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/PyLocalReference.cc b/backend/Python/PyLocalReference.cc
new file mode 100644
index 00000000..d4f202d8
--- /dev/null
+++ b/backend/Python/PyLocalReference.cc
@@ -0,0 +1,216 @@
+/*
+ * 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 <ScriptX/ScriptX.h>
+
+namespace script {
+
+#define REF_IMPL_BASIC_FUNC(ValueType)                                           \
+  Local<ValueType>::Local(const Local<ValueType>& copy) : val_(copy.val_) {}     \
+  Local<ValueType>::Local(Local<ValueType>&& move) noexcept : val_(move.val_) {} \
+  Local<ValueType>::~Local() {}                                                  \
+  Local<ValueType>& Local<ValueType>::operator=(const Local& from) {             \
+    Local(from).swap(*this);                                                     \
+    return *this;                                                                \
+  }                                                                              \
+  Local<ValueType>& Local<ValueType>::operator=(Local&& move) noexcept {         \
+    Local(std::move(move)).swap(*this);                                          \
+    return *this;                                                                \
+  }                                                                              \
+  void Local<ValueType>::swap(Local& rhs) noexcept { std::swap(val_, rhs.val_); }
+
+#define REF_IMPL_BASIC_EQUALS(ValueType)                                               \
+  bool Local<ValueType>::operator==(const script::Local<script::Value>& other) const { \
+    return asValue() == other;                                                         \
+  }
+
+#define REF_IMPL_BASIC_NOT_VALUE(ValueType)                                         \
+  Local<ValueType>::Local(InternalLocalRef val) : val_(val) {}                      \
+  Local<String> Local<ValueType>::describe() const { return asValue().describe(); } \
+  std::string Local<ValueType>::describeUtf8() const { return asValue().describeUtf8(); }
+
+#define REF_IMPL_TO_VALUE(ValueType) \
+  Local<Value> Local<ValueType>::asValue() const { return Local<Value>(/*TMPL: value*/); }
+
+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<Value>::Local() noexcept : val_() {}
+
+Local<Value>::Local(InternalLocalRef v8Local) : val_(v8Local) {}
+
+bool Local<Value>::isNull() const { return false; }
+
+void Local<Value>::reset() {}
+
+ValueKind Local<Value>::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<Value>::isString() const { return false; }
+
+bool Local<Value>::isNumber() const { return false; }
+
+bool Local<Value>::isBoolean() const { return false; }
+
+bool Local<Value>::isFunction() const { return false; }
+
+bool Local<Value>::isArray() const { return false; }
+
+bool Local<Value>::isByteBuffer() const { return false; }
+
+bool Local<Value>::isObject() const { return false; }
+
+bool Local<Value>::isUnsupported() const { return false; }
+
+Local<String> Local<Value>::asString() const { throw Exception("can't cast value as String"); }
+
+Local<Number> Local<Value>::asNumber() const { throw Exception("can't cast value as Number"); }
+
+Local<Boolean> Local<Value>::asBoolean() const { throw Exception("can't cast value as Boolean"); }
+
+Local<Function> Local<Value>::asFunction() const {
+  throw Exception("can't cast value as Function");
+}
+
+Local<Array> Local<Value>::asArray() const { throw Exception("can't cast value as Array"); }
+
+Local<ByteBuffer> Local<Value>::asByteBuffer() const {
+  throw Exception("can't cast value as ByteBuffer");
+}
+
+Local<Object> Local<Value>::asObject() const { throw Exception("can't cast value as Object"); }
+
+Local<Unsupported> Local<Value>::asUnsupported() const {
+  throw Exception("can't cast value as Unsupported");
+}
+
+bool Local<Value>::operator==(const script::Local<script::Value>& other) const { return false; }
+
+Local<String> Local<Value>::describe() const { TEMPLATE_NOT_IMPLEMENTED(); }
+
+Local<Value> Local<Object>::get(const script::Local<script::String>& key) const { return {}; }
+
+void Local<Object>::set(const script::Local<script::String>& key,
+                        const script::Local<script::Value>& value) const {}
+
+void Local<Object>::remove(const Local<class script::String>& key) const {}
+bool Local<Object>::has(const Local<class script::String>& key) const { return true; }
+
+bool Local<Object>::instanceOf(const Local<class script::Value>& type) const { return false; }
+
+std::vector<Local<String>> Local<Object>::getKeys() const { return {}; }
+
+float Local<Number>::toFloat() const { return static_cast<float>(toDouble()); }
+
+double Local<Number>::toDouble() const { return 0; }
+
+int32_t Local<Number>::toInt32() const { return static_cast<int32_t>(toDouble()); }
+
+int64_t Local<Number>::toInt64() const { return static_cast<int64_t>(toDouble()); }
+
+bool Local<Boolean>::value() const { return false; }
+
+Local<Value> Local<Function>::callImpl(const Local<Value>& thiz, size_t size,
+                                       const Local<Value>* args) const {
+  return {};
+}
+
+size_t Local<Array>::size() const { return 0; }
+
+Local<Value> Local<Array>::get(size_t index) const { return {}; }
+
+void Local<Array>::set(size_t index, const script::Local<script::Value>& value) const {}
+
+void Local<Array>::add(const script::Local<script::Value>& value) const { set(size(), value); }
+
+void Local<Array>::clear() const {}
+
+ByteBuffer::Type Local<ByteBuffer>::getType() const { return ByteBuffer::Type::KFloat32; }
+
+bool Local<ByteBuffer>::isShared() const { return true; }
+
+void Local<ByteBuffer>::commit() const {}
+
+void Local<ByteBuffer>::sync() const {}
+
+size_t Local<ByteBuffer>::byteLength() const { return 0; }
+
+void* Local<ByteBuffer>::getRawBytes() const { return nullptr; }
+
+std::shared_ptr<void> Local<ByteBuffer>::getRawBytesShared() const { return {}; }
+
+}  // namespace script
diff --git a/backend/Python/PyNative.cc b/backend/Python/PyNative.cc
new file mode 100644
index 00000000..05c10e6a
--- /dev/null
+++ b/backend/Python/PyNative.cc
@@ -0,0 +1,47 @@
+/*
+ * 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 <ScriptX/ScriptX.h>
+
+namespace script {
+
+Arguments::Arguments(InternalCallbackInfoType callbackInfo) : callbackInfo_(callbackInfo) {}
+
+Arguments::~Arguments() = default;
+
+Local<Object> Arguments::thiz() const { TEMPLATE_NOT_IMPLEMENTED(); }
+
+bool Arguments::hasThiz() const { TEMPLATE_NOT_IMPLEMENTED(); }
+
+size_t Arguments::size() const { TEMPLATE_NOT_IMPLEMENTED(); }
+
+Local<Value> Arguments::operator[](size_t i) const { return {}; }
+
+ScriptEngine* Arguments::engine() const { return nullptr; }
+
+ScriptClass::ScriptClass(const script::Local<script::Object>& scriptObject) : internalState_() {
+  TEMPLATE_NOT_IMPLEMENTED();
+}
+
+Local<Object> ScriptClass::getScriptObject() const { TEMPLATE_NOT_IMPLEMENTED(); }
+
+Local<Array> 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 <typename T>
+ScriptClass::ScriptClass(const ScriptClass::ConstructFromCpp<T>) : internalState_() {}
+
+template <typename T>
+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..4c7fdb5d
--- /dev/null
+++ b/backend/Python/PyReference.hpp
@@ -0,0 +1,142 @@
+/*
+ * 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 <utility>
+
+namespace script {
+
+template <typename T>
+Global<T>::Global() noexcept : val_() {}
+
+template <typename T>
+Global<T>::Global(const script::Local<T>& localReference) {}
+
+template <typename T>
+Global<T>::Global(const script::Weak<T>& weak) {}
+
+template <typename T>
+Global<T>::Global(const script::Global<T>& copy) : val_(copy.val_) {}
+
+template <typename T>
+Global<T>::Global(script::Global<T>&& move) noexcept : val_(move.val_) {}
+
+template <typename T>
+Global<T>::~Global() {}
+
+template <typename T>
+Global<T>& Global<T>::operator=(const script::Global<T>& assign) {
+  Global(assign).swap(*this);
+  return *this;
+}
+
+template <typename T>
+Global<T>& Global<T>::operator=(script::Global<T>&& move) noexcept {
+  Global(std::move(move)).swap(*this);
+  return *this;
+}
+
+template <typename T>
+void Global<T>::swap(Global& rhs) noexcept {}
+
+template <typename T>
+Global<T>& Global<T>::operator=(const script::Local<T>& assign) {
+  *this = Global<T>(assign);
+  return *this;
+}
+
+template <typename T>
+Local<T> Global<T>::get() const {
+  TEMPLATE_NOT_IMPLEMENTED();
+}
+
+template <typename T>
+Local<Value> Global<T>::getValue() const {
+  TEMPLATE_NOT_IMPLEMENTED();
+}
+
+template <typename T>
+bool Global<T>::isEmpty() const {
+  return false;
+}
+
+template <typename T>
+void Global<T>::reset() {}
+
+// == Weak ==
+
+template <typename T>
+Weak<T>::Weak() noexcept : val_() {}
+
+template <typename T>
+Weak<T>::~Weak() {}
+
+template <typename T>
+Weak<T>::Weak(const script::Local<T>& localReference) {}
+
+template <typename T>
+Weak<T>::Weak(const script::Global<T>& globalReference) {}
+
+template <typename T>
+Weak<T>::Weak(const script::Weak<T>& copy) : val_(copy.val_) {}
+
+template <typename T>
+Weak<T>::Weak(script::Weak<T>&& move) noexcept : val_(std::move(move.val_)) {}
+
+template <typename T>
+Weak<T>& Weak<T>::operator=(const script::Weak<T>& assign) {
+  val_ = assign.val_;
+  return *this;
+}
+
+template <typename T>
+Weak<T>& Weak<T>::operator=(script::Weak<T>&& move) noexcept {
+  val_ = std::move(move.val_);
+  return *this;
+}
+
+template <typename T>
+void Weak<T>::swap(Weak& rhs) noexcept {
+  std::swap(val_, rhs.val_);
+}
+
+template <typename T>
+Weak<T>& Weak<T>::operator=(const script::Local<T>& assign) {
+  *this = Weak<T>(assign);
+  return *this;
+}
+
+template <typename T>
+Local<T> Weak<T>::get() const {
+  if (isEmpty()) throw Exception("get on empty Weak");
+  TEMPLATE_NOT_IMPLEMENTED();
+}
+
+template <typename T>
+Local<Value> Weak<T>::getValue() const {
+  TEMPLATE_NOT_IMPLEMENTED();
+}
+
+template <typename T>
+bool Weak<T>::isEmpty() const {
+  return false;
+}
+
+template <typename T>
+void Weak<T>::reset() noexcept {}
+
+}  // namespace script
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 <ScriptX/ScriptX.h>
+
+namespace script {
+
+StringHolder::StringHolder(const script::Local<script::String> &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<const char8_t *>(c_str()); }
+#endif
+
+}  // namespace script
diff --git a/backend/Python/PyValue.cc b/backend/Python/PyValue.cc
new file mode 100644
index 00000000..548ad154
--- /dev/null
+++ b/backend/Python/PyValue.cc
@@ -0,0 +1,82 @@
+/*
+ * 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"
+
+namespace script {
+
+Local<Object> Object::newObject() { TEMPLATE_NOT_IMPLEMENTED(); }
+
+Local<Object> Object::newObjectImpl(const Local<Value>& type, size_t size,
+                                    const Local<Value>* args) {
+  TEMPLATE_NOT_IMPLEMENTED();
+}
+
+Local<String> String::newString(const char* utf8) { TEMPLATE_NOT_IMPLEMENTED(); }
+
+Local<String> String::newString(std::string_view utf8) { TEMPLATE_NOT_IMPLEMENTED(); }
+
+Local<String> String::newString(const std::string& utf8) { TEMPLATE_NOT_IMPLEMENTED(); }
+
+#if defined(__cpp_char8_t)
+
+Local<String> String::newString(const char8_t* utf8) {
+  return newString(reinterpret_cast<const char*>(utf8));
+}
+
+Local<String> String::newString(std::u8string_view utf8) {
+  return newString(std::string_view(reinterpret_cast<const char*>(utf8.data()), utf8.length()));
+}
+
+Local<String> String::newString(const std::u8string& utf8) { return newString(utf8.c_str()); }
+
+#endif
+
+Local<Number> Number::newNumber(float value) { return newNumber(static_cast<double>(value)); }
+
+Local<Number> Number::newNumber(double value) { TEMPLATE_NOT_IMPLEMENTED(); }
+
+Local<Number> Number::newNumber(int32_t value) { return newNumber(static_cast<double>(value)); }
+
+Local<Number> Number::newNumber(int64_t value) { return newNumber(static_cast<double>(value)); }
+
+Local<Boolean> Boolean::newBoolean(bool value) { TEMPLATE_NOT_IMPLEMENTED(); }
+
+Local<Function> Function::newFunction(script::FunctionCallback callback) {
+  TEMPLATE_NOT_IMPLEMENTED();
+}
+
+Local<Array> Array::newArray(size_t size) { TEMPLATE_NOT_IMPLEMENTED(); }
+
+Local<Array> Array::newArrayImpl(size_t size, const Local<Value>* args) {
+  TEMPLATE_NOT_IMPLEMENTED();
+}
+
+Local<ByteBuffer> ByteBuffer::newByteBuffer(size_t size) { TEMPLATE_NOT_IMPLEMENTED(); }
+
+Local<script::ByteBuffer> ByteBuffer::newByteBuffer(void* nativeBuffer, size_t size) {
+  TEMPLATE_NOT_IMPLEMENTED();
+}
+
+Local<ByteBuffer> ByteBuffer::newByteBuffer(std::shared_ptr<void> 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 <string>
+#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<ScriptEngine> {
+  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..3c5a3be2
--- /dev/null
+++ b/backend/Python/trait/TraitException.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
+
+namespace script {
+
+namespace py_backend {
+
+class ExceptionFields {
+ public:
+  mutable std::string message_{};
+};
+
+}  // namespace py_backend
+
+template <>
+struct internal::ImplType<Exception> {
+  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..67972386
--- /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_TEMPLATE
+#define SCRIPTX_LANG_NONE
\ 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..2bb38cd1
--- /dev/null
+++ b/backend/Python/trait/TraitNative.h
@@ -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.
+ */
+
+#pragma once
+
+namespace script {
+
+namespace py_backend {
+
+struct ArgumentsData {
+  int stackBase;
+  size_t size;
+};
+
+struct JscScriptClassState {
+  ScriptEngine* scriptEngine_ = nullptr;
+  Weak<Object> 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::JscScriptClassState;
+};
+
+}  // 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..b1c7878c
--- /dev/null
+++ b/backend/Python/trait/TraitReference.h
@@ -0,0 +1,41 @@
+/*
+ * 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 <cstdint>
+#include <string>
+#include "../../src/types.h"
+
+namespace script::internal {
+
+template <typename T>
+struct ImplType<Local<T>> {
+  using type = int;
+};
+
+template <typename T>
+struct ImplType<Global<T>> {
+  using type = int;
+};
+
+template <typename T>
+struct ImplType<Weak<T>> {
+  using type = int;
+};
+
+}  // 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..fbd7dd43
--- /dev/null
+++ b/backend/Python/trait/TraitScope.h
@@ -0,0 +1,80 @@
+/*
+ * 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 "TraitEngine.h"
+
+namespace script {
+
+namespace py_backend {
+
+class EngineScopeImpl {
+ public:
+  explicit EngineScopeImpl(PyEngine &) {
+    // enter engine;
+  }
+
+  ~EngineScopeImpl() {
+    // exit engine;
+  }
+};
+
+class ExitEngineScopeImpl {
+ public:
+  explicit ExitEngineScopeImpl(PyEngine &) {
+    // exit current entered engine
+  }
+
+  ~ExitEngineScopeImpl() {
+    // reenter engine;
+  }
+};
+
+class StackFrameScopeImpl {
+ public:
+  explicit StackFrameScopeImpl(PyEngine &) {
+    // enter stack;
+  }
+
+  ~StackFrameScopeImpl() {
+    // exit stack;
+  }
+
+  template <typename T>
+  Local<T> returnValue(const Local<T> &localRef) {
+    return localRef;
+  }
+};
+}  // namespace py_backend
+
+template <>
+struct internal::ImplType<EngineScope> {
+  using type = py_backend::EngineScopeImpl;
+};
+
+template <>
+struct internal::ImplType<ExitEngineScope> {
+  using type = py_backend::ExitEngineScopeImpl;
+};
+
+template <>
+struct internal::ImplType<StackFrameScope> {
+  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..318334f3
--- /dev/null
+++ b/backend/Python/trait/TraitUtils.h
@@ -0,0 +1,32 @@
+/*
+ * 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
+
+namespace script {
+
+template <>
+struct internal::ImplType<StringHolder> {
+  using type = int;
+};
+
+template <>
+struct internal::ImplType<internal::interop> {
+  using type = int;
+};
+
+}  // namespace script
\ No newline at end of file
diff --git a/test/cmake/TestEnv.cmake b/test/cmake/TestEnv.cmake
index 1d582f2a..30b91ad5 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.9/3.9.4/Frameworks/Python.framework/Versions/3.9/include/python3.9/"
+                CACHE STRING "" FORCE)
+    set(DEVOPS_LIBS_LIBPATH "/usr/local/Cellar/python@3.9/3.9.4/Frameworks/Python.framework/Versions/3.9/lib/libpython3.9.dylib" CACHE STRING "" FORCE)
 endif ()
 

From b05e92c67b876556ab01518bcd92dcdd030361cd Mon Sep 17 00:00:00 2001
From: landerlyoung <landerlyoung@gmail.com>
Date: Sat, 1 May 2021 19:46:35 +0800
Subject: [PATCH 02/10] include

---
 backend/Python/CMakeLists.txt |  3 +++
 backend/Python/PyHelper.cc    | 18 ++++++++++++++++++
 backend/Python/PyHelper.h     | 31 +++++++++++++++++++++++++++++++
 backend/Python/PyHelper.hpp   | 21 +++++++++++++++++++++
 4 files changed, 73 insertions(+)
 create mode 100644 backend/Python/PyHelper.cc
 create mode 100644 backend/Python/PyHelper.h
 create mode 100644 backend/Python/PyHelper.hpp

diff --git a/backend/Python/CMakeLists.txt b/backend/Python/CMakeLists.txt
index d547ca57..047a7387 100644
--- a/backend/Python/CMakeLists.txt
+++ b/backend/Python/CMakeLists.txt
@@ -2,6 +2,9 @@ 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
diff --git a/backend/Python/PyHelper.cc b/backend/Python/PyHelper.cc
new file mode 100644
index 00000000..5db6fa6b
--- /dev/null
+++ b/backend/Python/PyHelper.cc
@@ -0,0 +1,18 @@
+/*
+ * 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"
\ No newline at end of file
diff --git a/backend/Python/PyHelper.h b/backend/Python/PyHelper.h
new file mode 100644
index 00000000..0cc41816
--- /dev/null
+++ b/backend/Python/PyHelper.h
@@ -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.
+ */
+
+#pragma once
+
+#include "../../src/foundation.h"
+
+// docs: https://docs.python.org/3/c-api/index.html
+
+SCRIPTX_BEGIN_INCLUDE_LIBRARY
+#ifndef PY_SSIZE_T_CLEAN
+#define PY_SSIZE_T_CLEAN
+#endif
+#include <Python.h>
+SCRIPTX_END_INCLUDE_LIBRARY
+
+namespace script::py_backend {}
diff --git a/backend/Python/PyHelper.hpp b/backend/Python/PyHelper.hpp
new file mode 100644
index 00000000..32a1058d
--- /dev/null
+++ b/backend/Python/PyHelper.hpp
@@ -0,0 +1,21 @@
+/*
+ * 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 "PyHelper.h"
+
+namespace script::py_backend {}
\ No newline at end of file

From 7d6247c9e4d9ea41cc2c30c738701156af690826 Mon Sep 17 00:00:00 2001
From: landerlyoung <landerlyoung@gmail.com>
Date: Tue, 21 Sep 2021 21:50:43 +0800
Subject: [PATCH 03/10] wip

---
 backend/Python/PyEngine.cc            | 10 +++---
 backend/Python/PyEngine.h             |  1 +
 backend/Python/PyHelper.cc            | 27 +++++++++++++++-
 backend/Python/PyHelper.h             | 13 ++++++--
 backend/Python/PyHelper.hpp           | 12 ++++++-
 backend/Python/PyValue.cc             | 46 +++++++++++++++++++++------
 backend/Python/trait/TraitException.h |  2 ++
 backend/Python/trait/TraitIncludes.h  |  4 +--
 backend/Python/trait/TraitNative.h    |  1 +
 backend/Python/trait/TraitReference.h |  7 ++--
 backend/Python/trait/TraitUtils.h     |  7 +++-
 test/src/gtest_main.cc                |  5 ++-
 12 files changed, 111 insertions(+), 24 deletions(-)

diff --git a/backend/Python/PyEngine.cc b/backend/Python/PyEngine.cc
index 157cd0e8..94c2b8a9 100644
--- a/backend/Python/PyEngine.cc
+++ b/backend/Python/PyEngine.cc
@@ -17,16 +17,18 @@
 
 #include "PyEngine.h"
 #include "../../src/Utils.h"
+#include "pydebug.h"
+#include "pylifecycle.h"
 
 namespace script::py_backend {
 
-PyEngine::PyEngine(std::shared_ptr<utils::MessageQueue> queue) {}
+PyEngine::PyEngine(std::shared_ptr<utils::MessageQueue> queue) { Py_Initialize(); }
 
 PyEngine::PyEngine() : PyEngine(std::shared_ptr<utils::MessageQueue>{}) {}
 
 PyEngine::~PyEngine() = default;
 
-void PyEngine::destroy() noexcept {}
+void PyEngine::destroy() noexcept { ScriptEngine::destroyUserData(); }
 
 Local<Value> PyEngine::get(const Local<String>& key) { return Local<Value>(); }
 
@@ -50,9 +52,9 @@ void PyEngine::gc() {}
 
 void PyEngine::adjustAssociatedMemory(int64_t count) {}
 
-ScriptLanguage PyEngine::getLanguageType() { return ScriptLanguage::kJavaScript; }
+ScriptLanguage PyEngine::getLanguageType() { return ScriptLanguage::kPython; }
 
-std::string PyEngine::getEngineVersion() { return ""; }
+std::string PyEngine::getEngineVersion() { return Py_GetVersion(); }
 
 bool PyEngine::isDestroying() const { return false; }
 
diff --git a/backend/Python/PyEngine.h b/backend/Python/PyEngine.h
index 21df182d..9417415b 100644
--- a/backend/Python/PyEngine.h
+++ b/backend/Python/PyEngine.h
@@ -20,6 +20,7 @@
 #include "../../src/Engine.h"
 #include "../../src/Exception.h"
 #include "../../src/utils/MessageQueue.h"
+#include "PyHelper.h"
 
 namespace script::py_backend {
 
diff --git a/backend/Python/PyHelper.cc b/backend/Python/PyHelper.cc
index 5db6fa6b..d02f4b0e 100644
--- a/backend/Python/PyHelper.cc
+++ b/backend/Python/PyHelper.cc
@@ -15,4 +15,29 @@
  * limitations under the License.
  */
 
-#include "PyHelper.hpp"
\ No newline at end of file
+#include "PyHelper.hpp"
+
+namespace script::py_backend {
+
+PyObject* checkException(PyObject* obj) {
+  if (!obj) {
+    checkException();
+  }
+  return obj;
+}
+
+int checkException(int ret) {
+  if (ret == -1) {
+    checkException();
+  }
+  return ret;
+}
+
+void checkException() {
+  auto err = PyErr_Occurred();
+  if (err) {
+    // TODO
+  }
+}
+
+}  // namespace script::py_backend
\ No newline at end of file
diff --git a/backend/Python/PyHelper.h b/backend/Python/PyHelper.h
index 0cc41816..4bfa85a6 100644
--- a/backend/Python/PyHelper.h
+++ b/backend/Python/PyHelper.h
@@ -19,7 +19,10 @@
 
 #include "../../src/foundation.h"
 
-// docs: https://docs.python.org/3/c-api/index.html
+// docs:
+// https://docs.python.org/3/c-api/index.html
+// https://docs.python.org/3/extending/embedding.html
+// https://docs.python.org/2/c-api/init.html#thread-state-and-the-global-interpreter-lock
 
 SCRIPTX_BEGIN_INCLUDE_LIBRARY
 #ifndef PY_SSIZE_T_CLEAN
@@ -28,4 +31,10 @@ SCRIPTX_BEGIN_INCLUDE_LIBRARY
 #include <Python.h>
 SCRIPTX_END_INCLUDE_LIBRARY
 
-namespace script::py_backend {}
+namespace script::py_backend {
+
+PyObject* checkException(PyObject* obj);
+int checkException(int ret);
+void checkException();
+
+}  // namespace script::py_backend
diff --git a/backend/Python/PyHelper.hpp b/backend/Python/PyHelper.hpp
index 32a1058d..503fa184 100644
--- a/backend/Python/PyHelper.hpp
+++ b/backend/Python/PyHelper.hpp
@@ -16,6 +16,16 @@
  */
 
 #pragma once
+#include "../../src/Reference.h"
 #include "PyHelper.h"
 
-namespace script::py_backend {}
\ No newline at end of file
+namespace script::py_backend {
+
+struct py_interop {
+  template <class T>
+  static Local<T> makeLocal(PyObject* ref) {
+    return Local<T>(ref);
+  }
+};
+
+}  // namespace script::py_backend
\ No newline at end of file
diff --git a/backend/Python/PyValue.cc b/backend/Python/PyValue.cc
index 548ad154..f06ab80b 100644
--- a/backend/Python/PyValue.cc
+++ b/backend/Python/PyValue.cc
@@ -19,21 +19,39 @@
 #include "../../src/Reference.h"
 #include "../../src/Scope.h"
 #include "../../src/Value.h"
+#include "PyHelper.hpp"
+
+using script::py_backend::checkException;
+using script::py_backend::py_interop;
 
 namespace script {
 
-Local<Object> Object::newObject() { TEMPLATE_NOT_IMPLEMENTED(); }
+template <typename T>
+Local<T> checkAndMakeLocal(PyObject* ref) {
+  return py_interop::makeLocal<T>(checkException(ref));
+}
+
+// for python this creates an empty dict
+Local<Object> Object::newObject() { return checkAndMakeLocal<Object>(PyDict_New()); }
 
 Local<Object> Object::newObjectImpl(const Local<Value>& type, size_t size,
                                     const Local<Value>* args) {
   TEMPLATE_NOT_IMPLEMENTED();
 }
 
-Local<String> String::newString(const char* utf8) { TEMPLATE_NOT_IMPLEMENTED(); }
+Local<String> String::newString(const char* utf8) {
+  return checkAndMakeLocal<String>(PyBytes_FromString(utf8));
+}
 
-Local<String> String::newString(std::string_view utf8) { TEMPLATE_NOT_IMPLEMENTED(); }
+Local<String> String::newString(std::string_view utf8) {
+  return checkAndMakeLocal<String>(
+      PyBytes_FromStringAndSize(utf8.data(), static_cast<Py_ssize_t>(utf8.length())));
+}
 
-Local<String> String::newString(const std::string& utf8) { TEMPLATE_NOT_IMPLEMENTED(); }
+Local<String> String::newString(const std::string& utf8) {
+  return checkAndMakeLocal<String>(
+      PyBytes_FromStringAndSize(utf8.c_str(), static_cast<Py_ssize_t>(utf8.length())));
+}
 
 #if defined(__cpp_char8_t)
 
@@ -51,19 +69,29 @@ Local<String> String::newString(const std::u8string& utf8) { return newString(ut
 
 Local<Number> Number::newNumber(float value) { return newNumber(static_cast<double>(value)); }
 
-Local<Number> Number::newNumber(double value) { TEMPLATE_NOT_IMPLEMENTED(); }
+Local<Number> Number::newNumber(double value) {
+  return checkAndMakeLocal<Number>(PyLong_FromDouble(value));
+}
 
-Local<Number> Number::newNumber(int32_t value) { return newNumber(static_cast<double>(value)); }
+Local<Number> Number::newNumber(int32_t value) {
+  return checkAndMakeLocal<Number>(PyLong_FromLong(static_cast<long>(value)));
+}
 
-Local<Number> Number::newNumber(int64_t value) { return newNumber(static_cast<double>(value)); }
+Local<Number> Number::newNumber(int64_t value) {
+  return checkAndMakeLocal<Number>(PyLong_FromLongLong(static_cast<long long>(value)));
+}
 
-Local<Boolean> Boolean::newBoolean(bool value) { TEMPLATE_NOT_IMPLEMENTED(); }
+Local<Boolean> Boolean::newBoolean(bool value) {
+  return checkAndMakeLocal<Boolean>(PyBool_FromLong(value));
+}
 
 Local<Function> Function::newFunction(script::FunctionCallback callback) {
   TEMPLATE_NOT_IMPLEMENTED();
 }
 
-Local<Array> Array::newArray(size_t size) { TEMPLATE_NOT_IMPLEMENTED(); }
+Local<Array> Array::newArray(size_t size) {
+  return checkAndMakeLocal<Array>(PyList_New(static_cast<Py_ssize_t>(size)));
+}
 
 Local<Array> Array::newArrayImpl(size_t size, const Local<Value>* args) {
   TEMPLATE_NOT_IMPLEMENTED();
diff --git a/backend/Python/trait/TraitException.h b/backend/Python/trait/TraitException.h
index 3c5a3be2..80b13f49 100644
--- a/backend/Python/trait/TraitException.h
+++ b/backend/Python/trait/TraitException.h
@@ -16,6 +16,8 @@
  */
 
 #pragma once
+#include <string>
+#include "../../src/types.h"
 
 namespace script {
 
diff --git a/backend/Python/trait/TraitIncludes.h b/backend/Python/trait/TraitIncludes.h
index 67972386..6f22d372 100644
--- a/backend/Python/trait/TraitIncludes.h
+++ b/backend/Python/trait/TraitIncludes.h
@@ -22,5 +22,5 @@
 #include "../PyReference.hpp"
 
 // global marco
-#define SCRIPTX_BACKEND_TEMPLATE
-#define SCRIPTX_LANG_NONE
\ No newline at end of file
+#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
index 2bb38cd1..4f9774a5 100644
--- a/backend/Python/trait/TraitNative.h
+++ b/backend/Python/trait/TraitNative.h
@@ -16,6 +16,7 @@
  */
 
 #pragma once
+#include "../../src/types.h"
 
 namespace script {
 
diff --git a/backend/Python/trait/TraitReference.h b/backend/Python/trait/TraitReference.h
index b1c7878c..d45c7ed5 100644
--- a/backend/Python/trait/TraitReference.h
+++ b/backend/Python/trait/TraitReference.h
@@ -20,22 +20,23 @@
 #include <cstdint>
 #include <string>
 #include "../../src/types.h"
+#include "../PyHelper.h"
 
 namespace script::internal {
 
 template <typename T>
 struct ImplType<Local<T>> {
-  using type = int;
+  using type = PyObject*;
 };
 
 template <typename T>
 struct ImplType<Global<T>> {
-  using type = int;
+  using type = PyObject*;
 };
 
 template <typename T>
 struct ImplType<Weak<T>> {
-  using type = int;
+  using type = PyObject*;
 };
 
 }  // namespace script::internal
\ No newline at end of file
diff --git a/backend/Python/trait/TraitUtils.h b/backend/Python/trait/TraitUtils.h
index 318334f3..506a9c46 100644
--- a/backend/Python/trait/TraitUtils.h
+++ b/backend/Python/trait/TraitUtils.h
@@ -16,9 +16,14 @@
  */
 
 #pragma once
+#include "../../src/types.h"
 
 namespace script {
 
+namespace py_backend {
+struct py_interop;
+}
+
 template <>
 struct internal::ImplType<StringHolder> {
   using type = int;
@@ -26,7 +31,7 @@ struct internal::ImplType<StringHolder> {
 
 template <>
 struct internal::ImplType<internal::interop> {
-  using type = int;
+  using type = py_backend::py_interop;
 };
 
 }  // namespace script
\ No newline at end of file
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
   }
 }
 

From 358e056cee73ee7abbdb56e24f76897e6879ff1a Mon Sep 17 00:00:00 2001
From: landerlyoung <landerlyoung@gmail.com>
Date: Sun, 12 Dec 2021 20:54:32 +0800
Subject: [PATCH 04/10] update

---
 backend/Python/PyEngine.cc           | 13 ++++++-------
 backend/Python/PyEngine.h            |  4 +++-
 backend/Python/PyHelper.h            |  1 +
 backend/Python/trait/TraitNative.h   |  4 ++--
 backend/Python/trait/TraitScope.h    |  2 +-
 backend/Template/trait/TraitNative.h |  4 ++--
 test/cmake/TestEnv.cmake             |  4 ++--
 7 files changed, 17 insertions(+), 15 deletions(-)

diff --git a/backend/Python/PyEngine.cc b/backend/Python/PyEngine.cc
index 94c2b8a9..2d3c2dea 100644
--- a/backend/Python/PyEngine.cc
+++ b/backend/Python/PyEngine.cc
@@ -17,14 +17,15 @@
 
 #include "PyEngine.h"
 #include "../../src/Utils.h"
-#include "pydebug.h"
-#include "pylifecycle.h"
 
 namespace script::py_backend {
 
-PyEngine::PyEngine(std::shared_ptr<utils::MessageQueue> queue) { Py_Initialize(); }
+PyEngine::PyEngine(std::shared_ptr<utils::MessageQueue> queue)
+    : queue_(queue ? std::move(queue) : std::make_shared<utils::MessageQueue>()) {
+  Py_Initialize();
+}
 
-PyEngine::PyEngine() : PyEngine(std::shared_ptr<utils::MessageQueue>{}) {}
+PyEngine::PyEngine() : PyEngine(nullptr) {}
 
 PyEngine::~PyEngine() = default;
 
@@ -44,9 +45,7 @@ Local<Value> PyEngine::eval(const Local<String>& script, const Local<Value>& sou
   return Local<Value>();
 }
 
-std::shared_ptr<utils::MessageQueue> PyEngine::messageQueue() {
-  return std::shared_ptr<utils::MessageQueue>();
-}
+std::shared_ptr<utils::MessageQueue> PyEngine::messageQueue() { return queue_; }
 
 void PyEngine::gc() {}
 
diff --git a/backend/Python/PyEngine.h b/backend/Python/PyEngine.h
index 9417415b..e1c57249 100644
--- a/backend/Python/PyEngine.h
+++ b/backend/Python/PyEngine.h
@@ -25,7 +25,9 @@
 namespace script::py_backend {
 
 class PyEngine : public ScriptEngine {
- protected:
+ private:
+  std::shared_ptr<::script::utils::MessageQueue> queue_;
+
  public:
   PyEngine(std::shared_ptr<::script::utils::MessageQueue> queue);
 
diff --git a/backend/Python/PyHelper.h b/backend/Python/PyHelper.h
index 4bfa85a6..81135d6d 100644
--- a/backend/Python/PyHelper.h
+++ b/backend/Python/PyHelper.h
@@ -29,6 +29,7 @@ SCRIPTX_BEGIN_INCLUDE_LIBRARY
 #define PY_SSIZE_T_CLEAN
 #endif
 #include <Python.h>
+#include <pylifecycle.h>
 SCRIPTX_END_INCLUDE_LIBRARY
 
 namespace script::py_backend {
diff --git a/backend/Python/trait/TraitNative.h b/backend/Python/trait/TraitNative.h
index 4f9774a5..79f57f3e 100644
--- a/backend/Python/trait/TraitNative.h
+++ b/backend/Python/trait/TraitNative.h
@@ -27,7 +27,7 @@ struct ArgumentsData {
   size_t size;
 };
 
-struct JscScriptClassState {
+struct ScriptClassState {
   ScriptEngine* scriptEngine_ = nullptr;
   Weak<Object> weakRef_;
 };
@@ -41,7 +41,7 @@ struct internal::ImplType<::script::Arguments> {
 
 template <>
 struct internal::ImplType<::script::ScriptClass> {
-  using type = py_backend::JscScriptClassState;
+  using type = py_backend::ScriptClassState;
 };
 
 }  // namespace script
\ No newline at end of file
diff --git a/backend/Python/trait/TraitScope.h b/backend/Python/trait/TraitScope.h
index fbd7dd43..f0162ef5 100644
--- a/backend/Python/trait/TraitScope.h
+++ b/backend/Python/trait/TraitScope.h
@@ -25,7 +25,7 @@ namespace py_backend {
 
 class EngineScopeImpl {
  public:
-  explicit EngineScopeImpl(PyEngine &) {
+  explicit EngineScopeImpl(PyEngine &, PyEngine *) {
     // enter engine;
   }
 
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<Object> 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 30b91ad5..f04e0735 100644
--- a/test/cmake/TestEnv.cmake
+++ b/test/cmake/TestEnv.cmake
@@ -161,8 +161,8 @@ elseif (${SCRIPTX_BACKEND} STREQUAL QuickJs)
     set(DEVOPS_LIBS_LIBPATH QuickJs CACHE STRING "" FORCE)
 elseif (${SCRIPTX_BACKEND} STREQUAL Python)
     set(DEVOPS_LIBS_INCLUDE
-            "/usr/local/Cellar/python@3.9/3.9.4/Frameworks/Python.framework/Versions/3.9/include/python3.9/"
+            "/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.9/3.9.4/Frameworks/Python.framework/Versions/3.9/lib/libpython3.9.dylib" 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 ()
 

From c1adeb673490dbaf3a4e77a248595bad7cb1051c Mon Sep 17 00:00:00 2001
From: landerlyoung <landerlyoung@gmail.com>
Date: Sat, 18 Dec 2021 15:41:49 +0800
Subject: [PATCH 05/10] x

---
 backend/JavaScriptCore/JscUtils.cc | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

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)

From 0014762e3388963cad841f9439f146445ecf0026 Mon Sep 17 00:00:00 2001
From: landerlyoung <landerlyoung@gmail.com>
Date: Sat, 18 Dec 2021 22:08:52 +0800
Subject: [PATCH 06/10] py local ref-count

---
 backend/Python/PyHelper.h          |  2 +-
 backend/Python/PyLocalReference.cc | 60 ++++++++++++++++++++----------
 backend/Python/PyReference.hpp     |  8 ++++
 3 files changed, 49 insertions(+), 21 deletions(-)

diff --git a/backend/Python/PyHelper.h b/backend/Python/PyHelper.h
index 81135d6d..db8375e1 100644
--- a/backend/Python/PyHelper.h
+++ b/backend/Python/PyHelper.h
@@ -22,7 +22,7 @@
 // docs:
 // https://docs.python.org/3/c-api/index.html
 // https://docs.python.org/3/extending/embedding.html
-// https://docs.python.org/2/c-api/init.html#thread-state-and-the-global-interpreter-lock
+// 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
diff --git a/backend/Python/PyLocalReference.cc b/backend/Python/PyLocalReference.cc
index d4f202d8..3db91ca5 100644
--- a/backend/Python/PyLocalReference.cc
+++ b/backend/Python/PyLocalReference.cc
@@ -15,22 +15,37 @@
  * limitations under the License.
  */
 
-#include <ScriptX/ScriptX.h>
+#include "../../src/Native.hpp"
+#include "../../src/Reference.h"
+#include "../../src/Utils.h"
+#include "../../src/Value.h"
+#include "PyReference.hpp"
 
 namespace script {
 
-#define REF_IMPL_BASIC_FUNC(ValueType)                                           \
-  Local<ValueType>::Local(const Local<ValueType>& copy) : val_(copy.val_) {}     \
-  Local<ValueType>::Local(Local<ValueType>&& move) noexcept : val_(move.val_) {} \
-  Local<ValueType>::~Local() {}                                                  \
-  Local<ValueType>& Local<ValueType>::operator=(const Local& from) {             \
-    Local(from).swap(*this);                                                     \
-    return *this;                                                                \
-  }                                                                              \
-  Local<ValueType>& Local<ValueType>::operator=(Local&& move) noexcept {         \
-    Local(std::move(move)).swap(*this);                                          \
-    return *this;                                                                \
-  }                                                                              \
+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<ValueType>::Local(const Local<ValueType>& copy) : val_(py_backend::incRef(copy.val_)) {} \
+  Local<ValueType>::Local(Local<ValueType>&& move) noexcept : val_(move.val_) {                  \
+    move.val_ = nullptr;                                                                         \
+  }                                                                                              \
+  Local<ValueType>::~Local() { py_backend::decRef(val_); }                                       \
+  Local<ValueType>& Local<ValueType>::operator=(const Local& from) {                             \
+    Local(from).swap(*this);                                                                     \
+    return *this;                                                                                \
+  }                                                                                              \
+  Local<ValueType>& Local<ValueType>::operator=(Local&& move) noexcept {                         \
+    Local(std::move(move)).swap(*this);                                                          \
+    return *this;                                                                                \
+  }                                                                                              \
   void Local<ValueType>::swap(Local& rhs) noexcept { std::swap(val_, rhs.val_); }
 
 #define REF_IMPL_BASIC_EQUALS(ValueType)                                               \
@@ -39,12 +54,14 @@ namespace script {
   }
 
 #define REF_IMPL_BASIC_NOT_VALUE(ValueType)                                         \
-  Local<ValueType>::Local(InternalLocalRef val) : val_(val) {}                      \
+  Local<ValueType>::Local(InternalLocalRef val) : val_(val) {                       \
+    py_backend::valueConstructorCheck(val);                                         \
+  }                                                                                 \
   Local<String> Local<ValueType>::describe() const { return asValue().describe(); } \
   std::string Local<ValueType>::describeUtf8() const { return asValue().describeUtf8(); }
 
 #define REF_IMPL_TO_VALUE(ValueType) \
-  Local<Value> Local<ValueType>::asValue() const { return Local<Value>(/*TMPL: value*/); }
+  Local<Value> Local<ValueType>::asValue() const { return Local<Value>(val_); }
 
 REF_IMPL_BASIC_FUNC(Value)
 
@@ -92,11 +109,14 @@ REF_IMPL_TO_VALUE(Unsupported)
 
 Local<Value>::Local() noexcept : val_() {}
 
-Local<Value>::Local(InternalLocalRef v8Local) : val_(v8Local) {}
+Local<Value>::Local(InternalLocalRef ref) : val_(ref) {}
 
-bool Local<Value>::isNull() const { return false; }
+bool Local<Value>::isNull() const { return val_ == nullptr; }
 
-void Local<Value>::reset() {}
+void Local<Value>::reset() {
+  py_backend::decRef(val_);
+  val_ = nullptr;
+}
 
 ValueKind Local<Value>::getKind() const {
   if (isNull()) {
@@ -122,9 +142,9 @@ ValueKind Local<Value>::getKind() const {
 
 bool Local<Value>::isString() const { return false; }
 
-bool Local<Value>::isNumber() const { return false; }
+bool Local<Value>::isNumber() const { return PyNumber_Check(val_); }
 
-bool Local<Value>::isBoolean() const { return false; }
+bool Local<Value>::isBoolean() const { return PyBool_Check(val_); }
 
 bool Local<Value>::isFunction() const { return false; }
 
diff --git a/backend/Python/PyReference.hpp b/backend/Python/PyReference.hpp
index 4c7fdb5d..393788a4 100644
--- a/backend/Python/PyReference.hpp
+++ b/backend/Python/PyReference.hpp
@@ -20,6 +20,14 @@
 
 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 <typename T>
 Global<T>::Global() noexcept : val_() {}
 

From 5c4f3b4d6446990c66457d38c44a6580aff55bcb Mon Sep 17 00:00:00 2001
From: landerlyoung <landerlyoung@gmail.com>
Date: Sat, 18 Dec 2021 23:29:14 +0800
Subject: [PATCH 07/10] py scope

---
 backend/Python/CMakeLists.txt     |  2 ++
 backend/Python/PyScope.cc         | 31 ++++++++++++++++++
 backend/Python/PyScope.h          | 53 +++++++++++++++++++++++++++++++
 backend/Python/trait/TraitScope.h | 42 +-----------------------
 4 files changed, 87 insertions(+), 41 deletions(-)
 create mode 100644 backend/Python/PyScope.cc
 create mode 100644 backend/Python/PyScope.h

diff --git a/backend/Python/CMakeLists.txt b/backend/Python/CMakeLists.txt
index 047a7387..161c361c 100644
--- a/backend/Python/CMakeLists.txt
+++ b/backend/Python/CMakeLists.txt
@@ -9,6 +9,8 @@ target_sources(ScriptX PRIVATE
         ${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/PyScope.cc b/backend/Python/PyScope.cc
new file mode 100644
index 00000000..d34be031
--- /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..8be5e839
--- /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_ = PyGILState_UNLOCKED;
+
+ public:
+  explicit EngineScopeImpl(PyEngine &, PyEngine *);
+
+  ~EngineScopeImpl();
+};
+
+class ExitEngineScopeImpl {
+  PyThreadState *threadState = nullptr;
+
+ public:
+  explicit ExitEngineScopeImpl(PyEngine &);
+
+  ~ExitEngineScopeImpl();
+};
+
+class StackFrameScopeImpl {
+ public:
+  explicit StackFrameScopeImpl(PyEngine &) {}
+
+  template <typename T>
+  Local<T> returnValue(const Local<T> &localRef) {
+    return localRef;
+  }
+};
+}  // namespace script::py_backend
diff --git a/backend/Python/trait/TraitScope.h b/backend/Python/trait/TraitScope.h
index f0162ef5..d3cd8996 100644
--- a/backend/Python/trait/TraitScope.h
+++ b/backend/Python/trait/TraitScope.h
@@ -17,51 +17,11 @@
 
 #pragma once
 
+#include "../PyScope.h"
 #include "TraitEngine.h"
 
 namespace script {
 
-namespace py_backend {
-
-class EngineScopeImpl {
- public:
-  explicit EngineScopeImpl(PyEngine &, PyEngine *) {
-    // enter engine;
-  }
-
-  ~EngineScopeImpl() {
-    // exit engine;
-  }
-};
-
-class ExitEngineScopeImpl {
- public:
-  explicit ExitEngineScopeImpl(PyEngine &) {
-    // exit current entered engine
-  }
-
-  ~ExitEngineScopeImpl() {
-    // reenter engine;
-  }
-};
-
-class StackFrameScopeImpl {
- public:
-  explicit StackFrameScopeImpl(PyEngine &) {
-    // enter stack;
-  }
-
-  ~StackFrameScopeImpl() {
-    // exit stack;
-  }
-
-  template <typename T>
-  Local<T> returnValue(const Local<T> &localRef) {
-    return localRef;
-  }
-};
-}  // namespace py_backend
-
 template <>
 struct internal::ImplType<EngineScope> {
   using type = py_backend::EngineScopeImpl;

From b5d09f9805d9f4e99264dda2ba8751d888cbfa31 Mon Sep 17 00:00:00 2001
From: landerlyoung <landerlyoung@gmail.com>
Date: Sun, 19 Dec 2021 15:21:31 +0800
Subject: [PATCH 08/10] py equals

---
 backend/Python/PyLocalReference.cc | 13 ++++++++++++-
 backend/Python/PyScope.cc          |  4 ++--
 backend/Python/PyScope.h           |  4 ++--
 3 files changed, 16 insertions(+), 5 deletions(-)

diff --git a/backend/Python/PyLocalReference.cc b/backend/Python/PyLocalReference.cc
index 3db91ca5..d2ee9a6c 100644
--- a/backend/Python/PyLocalReference.cc
+++ b/backend/Python/PyLocalReference.cc
@@ -178,7 +178,18 @@ Local<Unsupported> Local<Value>::asUnsupported() const {
   throw Exception("can't cast value as Unsupported");
 }
 
-bool Local<Value>::operator==(const script::Local<script::Value>& other) const { return false; }
+bool Local<Value>::operator==(const script::Local<script::Value>& 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<String> Local<Value>::describe() const { TEMPLATE_NOT_IMPLEMENTED(); }
 
diff --git a/backend/Python/PyScope.cc b/backend/Python/PyScope.cc
index d34be031..fd45effb 100644
--- a/backend/Python/PyScope.cc
+++ b/backend/Python/PyScope.cc
@@ -22,10 +22,10 @@
 
 namespace script::py_backend {
 
-EngineScopeImpl::EngineScopeImpl(PyEngine &, PyEngine *) { gilState_ = PyGILState_Ensure(); }
+EngineScopeImpl::EngineScopeImpl(PyEngine &, PyEngine *) : gilState_(PyGILState_Ensure()) {}
 EngineScopeImpl::~EngineScopeImpl() { PyGILState_Release(gilState_); }
 
-ExitEngineScopeImpl::ExitEngineScopeImpl(PyEngine &) { threadState = PyEval_SaveThread(); }
+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
index 8be5e839..0d6f98ae 100644
--- a/backend/Python/PyScope.h
+++ b/backend/Python/PyScope.h
@@ -24,7 +24,7 @@ namespace script::py_backend {
 class PyEngine;
 
 class EngineScopeImpl {
-  PyGILState_STATE gilState_ = PyGILState_UNLOCKED;
+  PyGILState_STATE gilState_;
 
  public:
   explicit EngineScopeImpl(PyEngine &, PyEngine *);
@@ -33,7 +33,7 @@ class EngineScopeImpl {
 };
 
 class ExitEngineScopeImpl {
-  PyThreadState *threadState = nullptr;
+  PyThreadState *threadState;
 
  public:
   explicit ExitEngineScopeImpl(PyEngine &);

From 076cfdd09a981699f8efdb4f4cb109f7e7f9b4f4 Mon Sep 17 00:00:00 2001
From: landerlyoung <landerlyoung@gmail.com>
Date: Sun, 19 Dec 2021 16:50:07 +0800
Subject: [PATCH 09/10] py arguments & newFunction

---
 backend/Python/PyHelper.h          |  2 ++
 backend/Python/PyHelper.hpp        | 27 +++++++++++++++--
 backend/Python/PyNative.cc         | 26 ++++++++++++----
 backend/Python/PyValue.cc          | 48 +++++++++++++++++++++++++++++-
 backend/Python/trait/TraitNative.h |  6 ++--
 backend/Python/trait/TraitUtils.h  |  4 +--
 6 files changed, 98 insertions(+), 15 deletions(-)

diff --git a/backend/Python/PyHelper.h b/backend/Python/PyHelper.h
index db8375e1..8158e146 100644
--- a/backend/Python/PyHelper.h
+++ b/backend/Python/PyHelper.h
@@ -34,6 +34,8 @@ SCRIPTX_END_INCLUDE_LIBRARY
 
 namespace script::py_backend {
 
+class PyEngine;
+
 PyObject* checkException(PyObject* obj);
 int checkException(int ret);
 void checkException();
diff --git a/backend/Python/PyHelper.hpp b/backend/Python/PyHelper.hpp
index 503fa184..2197ed34 100644
--- a/backend/Python/PyHelper.hpp
+++ b/backend/Python/PyHelper.hpp
@@ -16,16 +16,37 @@
  */
 
 #pragma once
+#include "../../src/Native.hpp"
 #include "../../src/Reference.h"
 #include "PyHelper.h"
 
-namespace script::py_backend {
+namespace script {
 
 struct py_interop {
-  template <class T>
+  template <typename T>
   static Local<T> makeLocal(PyObject* ref) {
     return Local<T>(ref);
   }
+
+  /**
+   * @return stolen ref.
+   */
+  template <typename T>
+  static PyObject* toPy(const Local<T>& ref) {
+    return Py_XNewRef(ref.val_);
+  }
+
+  /**
+   * @return borrowed ref.
+   */
+  template <typename T>
+  static PyObject* asPy(const Local<T>& 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::py_backend
\ No newline at end of file
+}  // namespace script
\ No newline at end of file
diff --git a/backend/Python/PyNative.cc b/backend/Python/PyNative.cc
index 05c10e6a..703a43c0 100644
--- a/backend/Python/PyNative.cc
+++ b/backend/Python/PyNative.cc
@@ -15,7 +15,9 @@
  * limitations under the License.
  */
 
-#include <ScriptX/ScriptX.h>
+#include "../../src/Native.hpp"
+#include "PyEngine.h"
+#include "PyHelper.hpp"
 
 namespace script {
 
@@ -23,15 +25,27 @@ Arguments::Arguments(InternalCallbackInfoType callbackInfo) : callbackInfo_(call
 
 Arguments::~Arguments() = default;
 
-Local<Object> Arguments::thiz() const { TEMPLATE_NOT_IMPLEMENTED(); }
+Local<Object> Arguments::thiz() const {
+  return py_interop::makeLocal<Value>(callbackInfo_.self).asObject();
+}
 
-bool Arguments::hasThiz() const { TEMPLATE_NOT_IMPLEMENTED(); }
+bool Arguments::hasThiz() const { return callbackInfo_.self != nullptr; }
 
-size_t Arguments::size() const { TEMPLATE_NOT_IMPLEMENTED(); }
+size_t Arguments::size() const {
+  if (!callbackInfo_.args) {
+    return 0;
+  }
+  return PyTuple_Size(callbackInfo_.args);
+}
 
-Local<Value> Arguments::operator[](size_t i) const { return {}; }
+Local<Value> Arguments::operator[](size_t i) const {
+  if (i < size()) {
+    return py_interop::makeLocal<Value>(PyTuple_GetItem(callbackInfo_.args, i));
+  }
+  return {};
+}
 
-ScriptEngine* Arguments::engine() const { return nullptr; }
+ScriptEngine* Arguments::engine() const { return callbackInfo_.engine; }
 
 ScriptClass::ScriptClass(const script::Local<script::Object>& scriptObject) : internalState_() {
   TEMPLATE_NOT_IMPLEMENTED();
diff --git a/backend/Python/PyValue.cc b/backend/Python/PyValue.cc
index f06ab80b..11ba4e8f 100644
--- a/backend/Python/PyValue.cc
+++ b/backend/Python/PyValue.cc
@@ -85,8 +85,54 @@ Local<Boolean> Boolean::newBoolean(bool value) {
   return checkAndMakeLocal<Boolean>(PyBool_FromLong(value));
 }
 
+namespace {
+
+static constexpr const char* kFunctionDataName = "capsule_function_data";
+
+struct FunctionData {
+  FunctionCallback function;
+  py_backend::PyEngine* engine = nullptr;
+};
+
+}  // namespace
+
 Local<Function> Function::newFunction(script::FunctionCallback callback) {
-  TEMPLATE_NOT_IMPLEMENTED();
+  auto callbackIns = std::make_unique<FunctionData>();
+  callbackIns->engine = EngineScope::currentEngineAs<py_backend::PyEngine>();
+  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) {
+      // TODO: exception
+    } else {
+      auto data = static_cast<FunctionData*>(ptr);
+      try {
+        auto ret = data->function(py_interop::makeArguments(nullptr, self, args));
+        return py_interop::toPy(ret);
+      } catch (Exception& e) {
+        // TODO: exception
+      }
+    }
+    return nullptr;
+  };
+
+  auto ctx = PyCapsule_New(callbackIns.get(), kFunctionDataName, [](PyObject* cap) {
+    auto ptr = PyCapsule_GetPointer(cap, kFunctionDataName);
+    delete static_cast<FunctionData*>(ptr);
+  });
+
+  PyObject* closure = PyCFunction_New(&method, ctx);
+
+  Py_XDECREF(ctx);
+
+  // todo: check exception
+  callbackIns.release();
+  return Local<Function>(closure);
 }
 
 Local<Array> Array::newArray(size_t size) {
diff --git a/backend/Python/trait/TraitNative.h b/backend/Python/trait/TraitNative.h
index 79f57f3e..3022f038 100644
--- a/backend/Python/trait/TraitNative.h
+++ b/backend/Python/trait/TraitNative.h
@@ -17,14 +17,16 @@
 
 #pragma once
 #include "../../src/types.h"
+#include "../PyHelper.h"
 
 namespace script {
 
 namespace py_backend {
 
 struct ArgumentsData {
-  int stackBase;
-  size_t size;
+  mutable PyEngine* engine;
+  PyObject* self;
+  PyObject* args;
 };
 
 struct ScriptClassState {
diff --git a/backend/Python/trait/TraitUtils.h b/backend/Python/trait/TraitUtils.h
index 506a9c46..215f6802 100644
--- a/backend/Python/trait/TraitUtils.h
+++ b/backend/Python/trait/TraitUtils.h
@@ -20,9 +20,7 @@
 
 namespace script {
 
-namespace py_backend {
 struct py_interop;
-}
 
 template <>
 struct internal::ImplType<StringHolder> {
@@ -31,7 +29,7 @@ struct internal::ImplType<StringHolder> {
 
 template <>
 struct internal::ImplType<internal::interop> {
-  using type = py_backend::py_interop;
+  using type = py_interop;
 };
 
 }  // namespace script
\ No newline at end of file

From d4faea7a703c8251b5e5a7f6f6cb1cfe1829e28f Mon Sep 17 00:00:00 2001
From: landerlyoung <landerlyoung@gmail.com>
Date: Sun, 19 Dec 2021 23:50:50 +0800
Subject: [PATCH 10/10] wip

---
 backend/Python/PyHelper.cc         | 11 ++++-------
 backend/Python/PyHelper.h          |  2 +-
 backend/Python/PyHelper.hpp        |  1 +
 backend/Python/PyLocalReference.cc | 26 +++++++++++++++++++++++---
 backend/Python/PyValue.cc          | 14 +++++++-------
 5 files changed, 36 insertions(+), 18 deletions(-)

diff --git a/backend/Python/PyHelper.cc b/backend/Python/PyHelper.cc
index d02f4b0e..ced86204 100644
--- a/backend/Python/PyHelper.cc
+++ b/backend/Python/PyHelper.cc
@@ -26,13 +26,6 @@ PyObject* checkException(PyObject* obj) {
   return obj;
 }
 
-int checkException(int ret) {
-  if (ret == -1) {
-    checkException();
-  }
-  return ret;
-}
-
 void checkException() {
   auto err = PyErr_Occurred();
   if (err) {
@@ -40,4 +33,8 @@ void checkException() {
   }
 }
 
+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
index 8158e146..fb9b5d81 100644
--- a/backend/Python/PyHelper.h
+++ b/backend/Python/PyHelper.h
@@ -37,7 +37,7 @@ namespace script::py_backend {
 class PyEngine;
 
 PyObject* checkException(PyObject* obj);
-int checkException(int ret);
 void checkException();
+void rethrowException(const Exception& exception);
 
 }  // namespace script::py_backend
diff --git a/backend/Python/PyHelper.hpp b/backend/Python/PyHelper.hpp
index 2197ed34..c3ef7e21 100644
--- a/backend/Python/PyHelper.hpp
+++ b/backend/Python/PyHelper.hpp
@@ -18,6 +18,7 @@
 #pragma once
 #include "../../src/Native.hpp"
 #include "../../src/Reference.h"
+#include "PyEngine.h"
 #include "PyHelper.h"
 
 namespace script {
diff --git a/backend/Python/PyLocalReference.cc b/backend/Python/PyLocalReference.cc
index d2ee9a6c..4bac19aa 100644
--- a/backend/Python/PyLocalReference.cc
+++ b/backend/Python/PyLocalReference.cc
@@ -19,6 +19,7 @@
 #include "../../src/Reference.h"
 #include "../../src/Utils.h"
 #include "../../src/Value.h"
+#include "PyHelper.hpp"
 #include "PyReference.hpp"
 
 namespace script {
@@ -61,7 +62,7 @@ void valueConstructorCheck(PyObject* value) {
   std::string Local<ValueType>::describeUtf8() const { return asValue().describeUtf8(); }
 
 #define REF_IMPL_TO_VALUE(ValueType) \
-  Local<Value> Local<ValueType>::asValue() const { return Local<Value>(val_); }
+  Local<Value> Local<ValueType>::asValue() const { return Local<Value>(py_backend::incRef(val_)); }
 
 REF_IMPL_BASIC_FUNC(Value)
 
@@ -146,7 +147,7 @@ bool Local<Value>::isNumber() const { return PyNumber_Check(val_); }
 
 bool Local<Value>::isBoolean() const { return PyBool_Check(val_); }
 
-bool Local<Value>::isFunction() const { return false; }
+bool Local<Value>::isFunction() const { return PyCallable_Check(val_); }
 
 bool Local<Value>::isArray() const { return false; }
 
@@ -217,7 +218,26 @@ bool Local<Boolean>::value() const { return false; }
 
 Local<Value> Local<Function>::callImpl(const Local<Value>& thiz, size_t size,
                                        const Local<Value>* args) const {
-  return {};
+  // 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<Py_ssize_t>(size));
+    py_backend::checkException();
+    for (size_t i = 0; i < size; ++i) {
+      PyTuple_SetItem(tuple, static_cast<Py_ssize_t>(i), py_interop::toPy(args[i]));
+      py_backend::checkException();
+    }
+    ret = PyObject_Call(py_interop::asPy(*this), tuple, nullptr);
+  }
+
+  py_backend::checkException();
+  return Local<Value>(ret);
 }
 
 size_t Local<Array>::size() const { return 0; }
diff --git a/backend/Python/PyValue.cc b/backend/Python/PyValue.cc
index 11ba4e8f..3c8fda2e 100644
--- a/backend/Python/PyValue.cc
+++ b/backend/Python/PyValue.cc
@@ -21,8 +21,8 @@
 #include "../../src/Value.h"
 #include "PyHelper.hpp"
 
+using script::py_interop;
 using script::py_backend::checkException;
-using script::py_backend::py_interop;
 
 namespace script {
 
@@ -87,7 +87,7 @@ Local<Boolean> Boolean::newBoolean(bool value) {
 
 namespace {
 
-static constexpr const char* kFunctionDataName = "capsule_function_data";
+static constexpr const char* kFunctionDataName = "_ScriptX_function_data";
 
 struct FunctionData {
   FunctionCallback function;
@@ -108,14 +108,14 @@ Local<Function> Function::newFunction(script::FunctionCallback callback) {
   method.ml_meth = [](PyObject* self, PyObject* args) -> PyObject* {
     auto ptr = PyCapsule_GetPointer(self, kFunctionDataName);
     if (ptr == nullptr) {
-      // TODO: exception
+      ::PyErr_SetString(PyExc_TypeError, "invalid 'self' for native method");
     } else {
       auto data = static_cast<FunctionData*>(ptr);
       try {
         auto ret = data->function(py_interop::makeArguments(nullptr, self, args));
         return py_interop::toPy(ret);
       } catch (Exception& e) {
-        // TODO: exception
+        py_backend::rethrowException(e);
       }
     }
     return nullptr;
@@ -125,13 +125,13 @@ Local<Function> Function::newFunction(script::FunctionCallback callback) {
     auto ptr = PyCapsule_GetPointer(cap, kFunctionDataName);
     delete static_cast<FunctionData*>(ptr);
   });
+  py_backend::checkException(ctx);
+  callbackIns.release();
 
   PyObject* closure = PyCFunction_New(&method, ctx);
-
   Py_XDECREF(ctx);
+  py_backend::checkException(closure);
 
-  // todo: check exception
-  callbackIns.release();
   return Local<Function>(closure);
 }
 
