From 6f8bf82e9aa37d76b56027c73e04a769ae9e45d0 Mon Sep 17 00:00:00 2001 From: Mahbub Alam <98163463+mahbubalamdev@users.noreply.github.com> Date: Tue, 24 Oct 2023 05:59:58 -0400 Subject: [PATCH] Examples for beginners (#169) * Add examples folder * Draft change * Add draft changes * Add examples * Refactor examples --------- Co-authored-by: Mahbub Alam --- examples/1_type_cast.cpp | 35 +++++++++ examples/2_module_and_binding.cpp | 36 ++++++++++ examples/3_list_operation.cpp | 50 +++++++++++++ examples/4_dictionary_operation.cpp | 108 ++++++++++++++++++++++++++++ examples/5_python_scripting.cpp | 26 +++++++ examples/6_type_checker.cpp | 87 ++++++++++++++++++++++ 6 files changed, 342 insertions(+) create mode 100644 examples/1_type_cast.cpp create mode 100644 examples/2_module_and_binding.cpp create mode 100644 examples/3_list_operation.cpp create mode 100644 examples/4_dictionary_operation.cpp create mode 100644 examples/5_python_scripting.cpp create mode 100644 examples/6_type_checker.cpp diff --git a/examples/1_type_cast.cpp b/examples/1_type_cast.cpp new file mode 100644 index 00000000..3ff45a7f --- /dev/null +++ b/examples/1_type_cast.cpp @@ -0,0 +1,35 @@ + +/** + * This example demonstrates the type casting feature of PocketPy. + * It creates a virtual machine and cast PyObject* to different types. +*/ + +#include "pocketpy.h" + +using namespace pkpy; + + +int main(){ + // Create a virtual machine + VM* vm = new VM(); + + PyObject* str_obj = py_var(vm, "hello world"); + // Cast PyObject* to Str type + Str& str = py_cast(vm, str_obj); + std::cout << "string: " << str.c_str() << std::endl; // hello world + + + PyObject* int_obj = py_var(vm, 10); + // Cast PyObject* to Int type + int int_var = py_cast(vm, int_obj); + std::cout << "int: " << int_var << std::endl; // 10 + + PyObject* float_obj = py_var(vm, 10.5); + // Cast PyObject* to double type + double float_var = py_cast(vm, float_obj); + std::cout << "float: " << float_var << std::endl; // 10.5 + + // Dispose the virtual machine + delete vm; + return 0; +} diff --git a/examples/2_module_and_binding.cpp b/examples/2_module_and_binding.cpp new file mode 100644 index 00000000..dc897087 --- /dev/null +++ b/examples/2_module_and_binding.cpp @@ -0,0 +1,36 @@ + +/** + * This example demonstrate the process of creating a python module and + * bind a function to it, as well as the procedure for calling the function. +*/ + +#include "pocketpy.h" + +using namespace pkpy; + + +int main(){ + // Create a virtual machine + VM* vm = new VM(); + + // Create a module + PyObject* math_module = vm->new_module("math"); + + // Bind a function named "add" to the module + vm->bind(math_module, "add(a: int, b: int) -> int", + [](VM* vm, ArgsView args){ + int a = py_cast(vm, args[0]); + int b = py_cast(vm, args[1]); + return py_var(vm, a + b); + }); + + + // Call the "add" function + PyObject* f_sum = math_module->attr("add"); + PyObject* result = vm->call(f_sum, py_var(vm, 4), py_var(vm, 5)); + std::cout << "Sum: " << py_cast(vm, result) << std::endl; // 9 + + // Dispose the virtual machine + delete vm; + return 0; +} diff --git a/examples/3_list_operation.cpp b/examples/3_list_operation.cpp new file mode 100644 index 00000000..d96d63ea --- /dev/null +++ b/examples/3_list_operation.cpp @@ -0,0 +1,50 @@ + +/** + * This example demonstrates how to build a List object and how to access its elements. + * It creates a python module named "math_utils" and bind a function named "average" to it. + * It exercises creating a List and accessing its elements. + * It also demonstrates how to cast a python object to a C++ type. +*/ + +#include "pocketpy.h" + +using namespace pkpy; + + +int main(){ + // Create a virtual machine + VM* vm = new VM(); + + // Create a module + PyObject* math_utils = vm->new_module("math_utils"); + + // Bind a function named "average" to the module + vm->bind(math_utils, "average(l: List[float]) -> float", + [](VM* vm, ArgsView args){ + // Cast the argument to a list + List& l = py_cast(vm, args[0]); + double sum = 0; + + // Calculate the sum of the list by iterating through the list + for(auto& e : l){ + sum += py_cast(vm, e); + } + return py_var(vm, sum / l.size()); + }); + + // Create a list of numbers and covert it to a python object + List numbers; + numbers.push_back(py_var(vm, 1.0)); + numbers.push_back(py_var(vm, 2.0)); + numbers.push_back(py_var(vm, 3.0)); + PyObject* list = py_var(vm, std::move(numbers)); + + // Call the "average" function + PyObject* f_average = math_utils->attr("average"); + PyObject* result = vm->call(f_average, list); + std::cout << "Average: " << py_cast(vm, result) << std::endl; // 2 + + // Dispose the virtual machine + delete vm; + return 0; +} diff --git a/examples/4_dictionary_operation.cpp b/examples/4_dictionary_operation.cpp new file mode 100644 index 00000000..3e43878d --- /dev/null +++ b/examples/4_dictionary_operation.cpp @@ -0,0 +1,108 @@ + +/** + * This example illustrate use of Dict in PocketPy. + * It creates a python module named "employee" and bind four functions to it. + * It exercises setting and getting elements in a Dict. +*/ + + +#include "pocketpy.h" + +using namespace pkpy; + + +int main(){ + // Create a virtual machine + VM* vm = new VM(); + + // Create "employee" module + PyObject* employee_module = vm->new_module("employee"); + + // Bind a function named "get_first_name" to the module + vm->bind(employee_module, "get_first_name(employee: Dict) -> str", + "Returns first_name of the employee", // docstring + [](VM* vm, ArgsView args){ + // Cast the argument to a dictionary + Dict& employee = CAST(Dict&, args[0]); + // Access the first_name field and return it + return employee.try_get(VAR("first_name")); + }); + + // Bind a function named "get_last_name" to the module + vm->bind(employee_module, "get_last_name(employee: Dict) -> str", + "Returns last_name of the employee", // docstring + [](VM* vm, ArgsView args){ + // Cast the argument to a dictionary + Dict& employee = CAST(Dict&, args[0]); + // Access the last_name field and return it + return employee.try_get(VAR("last_name")); + }); + + // Bind a function named "get_salary" to the module + // It accepts a dictionary as argument and returns a float + vm->bind(employee_module, "get_salary(employee: Dict) -> float", + "Returns salary of the employee", // docstring + [](VM* vm, ArgsView args){ + // Cast the argument to a dictionary + Dict& employee = CAST(Dict&, args[0]); + // Access the salary field and return it + return employee.try_get(VAR("salary")); + }); + + // Bind a function named "love_coding" to the module + // It accepts a dictionary as argument and returns a bool + vm->bind(employee_module, "love_coding(employee: Dict) -> bool", + "Returns Yes if the employee loves coding, No otherwise", // docstring + [](VM* vm, ArgsView args){ + // Cast the argument to a dictionary + Dict& employee = CAST(Dict&, args[0]); + + // Access the hobbies field and cast it to a list + List& hobbies = CAST(List&, employee.try_get(VAR("hobbies"))); + + // Iterate through the list and check if the employee loves coding + for(auto& e : hobbies){ + if(CAST(Str&, e) == Str("Coding")){ + return VAR("Yes"); + } + } + return VAR("No"); + }); + + // Create employee dictionary covert it to a python object + Dict employee(vm); + employee.set(VAR("first_name"), VAR("John")); + employee.set(VAR("last_name"), VAR("Doe")); + employee.set(VAR("age"), VAR(30)); + employee.set(VAR("salary"), VAR(10000.0)); + List hobbies; + hobbies.push_back(VAR("Reading")); + hobbies.push_back(VAR("Walking")); + hobbies.push_back(VAR("Coding")); + employee.set(VAR("hobbies"), VAR(std::move(hobbies))); + PyObject* employee_obj = VAR(std::move(employee)); + + // Call the "get_first_name" function + PyObject* f_get_first_name = employee_module->attr("get_first_name"); + PyObject* first_name = vm->call(f_get_first_name, employee_obj); + std::cout << "First name: " << CAST(Str&, first_name) << std::endl; // First name: John + + // Call the "get_last_name" function + PyObject* f_get_last_name = employee_module->attr("get_last_name"); + PyObject* last_name = vm->call(f_get_last_name, employee_obj); + std::cout << "Last name: " << CAST(Str&, last_name) << std::endl; // Last name: Doe + + // Call the "get_salary" function + PyObject* f_get_salary = employee_module->attr("get_salary"); + PyObject* salary = vm->call(f_get_salary, employee_obj); + std::cout << "Salary: "<< CAST(double, salary) << std::endl; // Salary: 10000 + + // Call the "love_coding" function + PyObject* f_love_coding = employee_module->attr("love_coding"); + PyObject* love_coding = vm->call(f_love_coding, employee_obj); + std::cout << "Loves coding: " << CAST(Str&, love_coding) << std::endl; // Loves coding: Yes + + // Dispose the virtual machine + delete vm; + return 0; +} diff --git a/examples/5_python_scripting.cpp b/examples/5_python_scripting.cpp new file mode 100644 index 00000000..735e615b --- /dev/null +++ b/examples/5_python_scripting.cpp @@ -0,0 +1,26 @@ + +/** + * This example demonstrate the use of PocketPy as a scripting language. + * It creates a virtual machine and execute a python script. +*/ + +#include "pocketpy.h" + +using namespace pkpy; + + +int main(){ + // Create a virtual machine + VM* vm = new VM(); + + // Print "hello world" to the console + vm->exec("print('hello world')"); // hello world + + // List comprehension + vm->exec("l = [i*i for i in range(1, 6)]"); + vm->exec("print(l)"); // [1, 4, 9, 16, 25] + + // Dispose the virtual machine + delete vm; + return 0; +} diff --git a/examples/6_type_checker.cpp b/examples/6_type_checker.cpp new file mode 100644 index 00000000..2f0b3d56 --- /dev/null +++ b/examples/6_type_checker.cpp @@ -0,0 +1,87 @@ + +/** + * This example demonstrates how to create different types of objects and + * how to check their types. +*/ + +#include "pocketpy.h" + +using namespace pkpy; + + +int main(){ + // Create a virtual machine + VM* vm = new VM(); + + // Create a module + PyObject* type_checker = vm->new_module("type_checker"); + + // Bind a function named "get_type" to the module + vm->bind(type_checker, "get_type(obj: object) -> str", + "Returns type of a python object", // docstring + [](VM* vm, ArgsView args){ + PyObject* obj = args[0]; + if(is_type(obj, vm->tp_int)){ + return py_var(vm, "int"); + } + else if(is_type(obj, vm->tp_str)){ + return py_var(vm, "str"); + } + else if(is_type(obj, vm->tp_float)){ + return py_var(vm, "float"); + } + else if(is_type(obj, vm->tp_bool)){ + return py_var(vm, "bool"); + } + else if(is_type(obj, vm->tp_dict)){ + return py_var(vm, "dict"); + } + else if(is_type(obj, vm->tp_list)){ + return py_var(vm, "list"); + } + else if(is_type(obj, vm->tp_tuple)){ + return py_var(vm, "tuple"); + } + else{ + return py_var(vm, "unknown"); + } + }); + + // Get the "get_type" function + PyObject* f_get_type = type_checker->attr("get_type"); + + // Create a dictionary + Dict d(vm); + d.set(py_var(vm, "key"), py_var(vm, "value")); + + // Create a list + List l; + l.push_back(py_var(vm, "list_element")); + + // Declare a two-element tuple + Tuple t(2); + t[0] = py_var(vm, "tuple_element_0"); + t[1] = py_var(vm, "tuple_element_1"); + + // Create different types of objects + PyObject* int_obj = py_var(vm, 1); + PyObject* str_obj = py_var(vm, "hello"); + PyObject* float_obj = py_var(vm, 1.0); + PyObject* bool_obj = py_var(vm, true); + PyObject* dict_obj = py_var(vm, std::move(d)); + PyObject* list_obj = py_var(vm, std::move(l)); + PyObject* tuple_obj = py_var(vm, std::move(t)); + + // Call the "get_type" function and print type of different objects + std::cout << "Type of 1: " << CAST(Str&, vm->call(f_get_type, int_obj)) << std::endl; + std::cout << "Type of \"hello\": " << CAST(Str&, vm->call(f_get_type, str_obj)) << std::endl; + std::cout << "Type of 1.0: " << CAST(Str&, vm->call(f_get_type, float_obj)) << std::endl; + std::cout << "Type of true: " << CAST(Str&, vm->call(f_get_type, bool_obj)) << std::endl; + std::cout << "Type of {\"key\": \"value\" }: " << CAST(Str&, vm->call(f_get_type, dict_obj)) << std::endl; + std::cout << "Type of [\"list_element\"]: " << CAST(Str&, vm->call(f_get_type, list_obj)) << std::endl; + std::cout << "Type of (\"tuple_element_0\", \"tuple_element_1\"): " << CAST(Str&, vm->call(f_get_type, tuple_obj)) << std::endl; + + // Dispose the virtual machine + delete vm; + return 0; +}