From 82b725442ef87c68e752052b6bc5fe5cdef86af0 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 14 Jun 2024 15:46:15 -0400 Subject: [PATCH 01/21] + README --- README.md | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 00000000..9b61eef5 --- /dev/null +++ b/README.md @@ -0,0 +1,94 @@ +# python bindings for Egad abstract syntax tree library (xo-expression) + +## Getting Started + +### Build + install `xo-cmake` dependency + +- [github/Rconybea/xo-cmake](https://github.com/Rconybea/xo-cmake) + +Installs a few cmake ingredients, along with a build assistant `xo-build` for XO projects such as this one. + +### Build + install other necessary XO dependencies + +``` +$ xo-build --clone --configure --build --install xo-indentlog +$ xo-build --clone --configure --build --install xo-refnct +$ xo-build --clone --configure --build --install xo-subsys +$ xo-build --clone --configure --build --install xo-reflect +$ xo-build --clone --configure --build --install xo-expression +$ xo-build --clone --configure --build --install xo-jit +$ xo-build --clone --configure --build --install xo-pyutil +``` + +### copy `xo-pyexpression` repository locally +``` +$ xo-build --clone xo-pyexpression` +``` + +or equivalently +``` +$ git clone git@github.com:Rconybea/xo-pyexpression.git +``` + +### build + install xo-pyexpression +``` +$ xo-build --configure --build --install xo-pyexpression +``` + +or equivalently: +``` +$ PREFIX=/usr/local # or preferred install location +$ cmake -DCMAKE_INSTALL_PREFIX=$PREFIX -S xo-pyexpression -B xo-pyyexpression/.build +$ cmake --build xo-pyexpression/.build -j +$ cmake --install xo-pyexpression/.build +``` +(also see .github/workflows/main.yml) + +## Examples + +Assumes `xo-pyexpression` installed to `~/local2/lib`, +i.e. built with `PREFIX=~/local2`. +``` +PYTHONPATH=~/locasl2/lib:$PYTHONPATH python +>>> import xo_pyexpression +>>> dir(xo_pyexpression) +['Expression', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'exprtype'] +``` + +## Development + +### use from build tree +Requires that supporting libraries (e.g. `xo_pyreflect`) appear in PYTHONPATH +``` +$ cd xo-pyexpression/.build/src/pyexpression +$ python +>>> import xo_pyexpression +``` + +### build for unit test coverage +``` +$ cd xo-pyexpression +$ cmake -DCMAKE_BUILD_TYPE=coverage -DENABLE_TESTING=on -S . -B .build-ccov +$ cmake --build .build-ccov -j +``` + +### LSP (language server) support + +LSP looks for compile commands in the root of the source tree; +while Cmake creates them in the root of its build directory. + +``` +$ cd xo-pyexpression +$ ln -s .build/compile_commands.json # supply compile commands to LSP +``` + +### display cmake variables + +- `-L` list variables +- `-A` include 'advanced' variables +- `-H` include help text + +``` +$ cd xo-pyexpression/.build +$ cmake -LAH +``` From 1ead5333b0d45b0ff1040d6db8f8671613e5b83a Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 14 Jun 2024 15:46:40 -0400 Subject: [PATCH 02/21] xo-pyexpression: mvp working --- .gitignore | 8 +++ CMakeLists.txt | 28 ++++++++++ cmake/xo-bootstrap-macros.cmake | 35 +++++++++++++ cmake/xo_pyexpressionConfig.cmake.in | 7 +++ include/REAMDE.md | 1 + src/pyexpression/CMakeLists.txt | 9 ++++ src/pyexpression/pyexpression.cpp | 76 ++++++++++++++++++++++++++++ src/pyexpression/pyexpression.hpp.in | 25 +++++++++ 8 files changed, 189 insertions(+) create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 cmake/xo-bootstrap-macros.cmake create mode 100644 cmake/xo_pyexpressionConfig.cmake.in create mode 100644 include/REAMDE.md create mode 100644 src/pyexpression/CMakeLists.txt create mode 100644 src/pyexpression/pyexpression.cpp create mode 100644 src/pyexpression/pyexpression.hpp.in diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..3d3a7826 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +# emacs workspace config +.projectile +# clangd working space (see emacs+lsp) +.cache +# typical cmake build directory (source-tree-nephew) +.build* +# symlink to builddir/compile_commands.json; should be set manually in dev sandbox +compile_commands.json diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000..31f734f4 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,28 @@ +# xo-pyexpression/CMakeLists.txt + +cmake_minimum_required(VERSION 3.10) + +project(xo_pyexpression VERSION 0.1) + +include(GNUInstallDirs) +include(cmake/xo-bootstrap-macros.cmake) + +xo_cxx_toplevel_options3() + +# ---------------------------------------------------------------- +# c++ settings (usually temporary) + +set(PROJECT_CXX_FLAGS "") +add_definitions(${PROJECT_CXX_FLAGS}) + +# ---------------------------------------------------------------- + +add_subdirectory(src/pyexpression) +#add_subdirectory(utest) + +# ---------------------------------------------------------------- +# provide find_package() support + +xo_export_cmake_config(${PROJECT_NAME} ${PROJECT_VERSION} ${PROJECT_NAME}Targets) + +# end CMakeLists.txt diff --git a/cmake/xo-bootstrap-macros.cmake b/cmake/xo-bootstrap-macros.cmake new file mode 100644 index 00000000..aba31169 --- /dev/null +++ b/cmake/xo-bootstrap-macros.cmake @@ -0,0 +1,35 @@ +# ---------------------------------------------------------------- +# for example: +# $ PREFIX=/usr/local # for example +# $ cmake -DCMAKE_MODULE_PATH=prefix -DCMAKE_INSTALL_PREFIX=$PREFIX -B .build +# +# will get +# CMAKE_MODULE_PATH +# from xo-cmake-config --cmake-module-path +# +# and expect .cmake macros in +# CMAKE_MODULE_PATH/xo_macros/xo_cxx.cmake +# ---------------------------------------------------------------- + +find_program(XO_CMAKE_CONFIG_EXECUTABLE NAMES xo-cmake-config REQUIRED) + +if ("${XO_CMAKE_CONFIG_EXECUTABLE}" STREQUAL "XO_CMAKE_CONFIG_EXECUTABLE-NOT_FOUND") + message(FATAL "could not find xo-cmake-config executable") +endif() + +message(STATUS "XO_CMAKE_CONFIG_EXECUTABLE=${XO_CMAKE_CONFIG_EXECUTABLE}") + +if (NOT XO_SUBMODULE_BUILD) + if (("${CMAKE_MODULE_PATH}" STREQUAL "") OR ("${CMAKE_MODULE_PATH}" STREQUAL prefix)) + # default to typical install location for xo-project-macros + execute_process(COMMAND ${XO_CMAKE_CONFIG_EXECUTABLE} --cmake-module-path OUTPUT_VARIABLE CMAKE_MODULE_PATH) + message(STATUS "CMAKE_MODULE_PATH=${CMAKE_MODULE_PATH}") + endif() +endif() + +# needs to have been installed somewhere on CMAKE_MODULE_PATH, +# (e.g. from xo-cmake with the same value for CMAKE_INSTALL_PREFIX) +# +include(xo_macros/xo_cxx) + +xo_cxx_bootstrap_message() diff --git a/cmake/xo_pyexpressionConfig.cmake.in b/cmake/xo_pyexpressionConfig.cmake.in new file mode 100644 index 00000000..dc1d5e3d --- /dev/null +++ b/cmake/xo_pyexpressionConfig.cmake.in @@ -0,0 +1,7 @@ +@PACKAGE_INIT@ + +include(CMakeFindDependencyMacro) +find_dependency(xo_expression) +find_dependency(xo_pyreflect) +include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") +check_required_components("@PROJECT_NAME@") diff --git a/include/REAMDE.md b/include/REAMDE.md new file mode 100644 index 00000000..9db0605f --- /dev/null +++ b/include/REAMDE.md @@ -0,0 +1 @@ +placeholder for future xo-pymatrix header files diff --git a/src/pyexpression/CMakeLists.txt b/src/pyexpression/CMakeLists.txt new file mode 100644 index 00000000..6e81f021 --- /dev/null +++ b/src/pyexpression/CMakeLists.txt @@ -0,0 +1,9 @@ +# xo-pyexpression/src/pyexpression/CMakeLists.txt + +set(SELF_LIB xo_pyexpression) +set(SELF_SRCS pyexpression.cpp) + +xo_pybind11_library(${SELF_LIB} ${PROJECT_NAME}Targets ${SELF_SRCS}) +xo_pybind11_dependency(${SELF_LIB} xo_expression) +xo_pybind11_dependency(${SELF_LIB} xo_pyreflect) +xo_dependency(${SELF_LIB} refcnt) diff --git a/src/pyexpression/pyexpression.cpp b/src/pyexpression/pyexpression.cpp new file mode 100644 index 00000000..a87f6b06 --- /dev/null +++ b/src/pyexpression/pyexpression.cpp @@ -0,0 +1,76 @@ +/* @file pyexpression.cpp */ + +#include "pyexpression.hpp" +#include "xo/pyreflect/pyreflect.hpp" +#include "xo/expression/Expression.hpp" +#include "xo/expression/ConstantInterface.hpp" +#include "xo/expression/Constant.hpp" +#include "xo/pyutil/pyutil.hpp" + +namespace xo { + namespace ast { + using xo::ast::exprtype; + using xo::ast::Expression; + using xo::ast::ConstantInterface; + using xo::ast::Constant; + using xo::reflect::TaggedPtr; + using xo::ref::rp; + namespace py = pybind11; + + PYBIND11_MODULE(XO_PYEXPRESSION_MODULE_NAME(), m) { + // e.g. for xo::reflect::TypeDescr + PYREFLECT_IMPORT_MODULE(); // py::module_::import("pyreflect"); + + m.doc() = "pybind11 plugin for xo-expression"; + + py::enum_(m, "exprtype") + .value("invalid", exprtype::invalid) + .value("constant", exprtype::constant) + .value("primitive", exprtype::primitive) + .value("apply", exprtype::apply) + .value("lambda", exprtype::lambda) + .value("variable", exprtype::variable) + ; + + py::class_>(m, "Expression") + .def("extype", &Expression::extype) + .def("__repr__", &Expression::display_string); + ; + + py::class_>(m, "ConstantInterface") + .def("value_td", &ConstantInterface::value_td, + py::doc("type description for literal value represented by this Constant")) + .def("value", + [](const ConstantInterface & expr) { + TaggedPtr tp = expr.value_tp(); + + auto * p = tp.recover_native(); + + /* TODO: promote to pyobject, so we can do polymorphism */ + if (p) + return *p; + else + return std::numeric_limits::quiet_NaN(); + }, + py::doc("recover constant expression's wrapped value [wip - only works for double]")) + ; + + py::class_, ConstantInterface, rp>>(m, "Constant_double") + ; + + m.def("make_constant", + [](double x) { + return make_constant(x); + }, + py::arg("x"), + py::doc("make_constant(x) creates constant expression holding x [wip - only works for double")) + ; + + } /*pyexpresion*/ + } /*namespace ast*/ +} /*namespace xo*/ + +/* end pyexpression.cpp */ diff --git a/src/pyexpression/pyexpression.hpp.in b/src/pyexpression/pyexpression.hpp.in new file mode 100644 index 00000000..7f4f4660 --- /dev/null +++ b/src/pyexpression/pyexpression.hpp.in @@ -0,0 +1,25 @@ +/* @file pyexpression.hpp + * + * automatically generated from src/xo_xo_pyexpression/xo_pyexpression.hpp.in + * see src/xo_xo_pyexpression/CMakeLists.txt + */ + +/* python requires module name = library name + * example: + * PYBIND11_MODULE(XO_PYEXPRESSION_MODULE_NAME(), m) { ... } + */ +#define XO_PYEXPRESSION_MODULE_NAME() @SELF_LIB@ + +/* example: + * py::module_::import(XO_PYEXPRESSION_MODULE_NAME_STR) + */ +#define XO_PYEXPRESSION_MODULE_NAME_STR "@SELF_LIB@" + +/* example: + * XO_PYEXPRESSION_IMPORT_MODULE() + * replaces + * py::module_::import("xo_pyexpression") + */ +#define XO_PYEXPRESSION_IMPORT_MODULE() py::module_::import("@SELF_LIB@") + +/* end pyexpression.hpp */ From 27a0dd591f7ca6454bbfd782bc9cd8ae863f44a4 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 14 Jun 2024 16:11:37 -0400 Subject: [PATCH 03/21] xo-pyexpression: + Primitive + PrimitiveInterface + examples --- src/pyexpression/pyexpression.cpp | 33 +++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/pyexpression/pyexpression.cpp b/src/pyexpression/pyexpression.cpp index a87f6b06..c42fbcc7 100644 --- a/src/pyexpression/pyexpression.cpp +++ b/src/pyexpression/pyexpression.cpp @@ -5,7 +5,10 @@ #include "xo/expression/Expression.hpp" #include "xo/expression/ConstantInterface.hpp" #include "xo/expression/Constant.hpp" +#include "xo/expression/PrimitiveInterface.hpp" +#include "xo/expression/Primitive.hpp" #include "xo/pyutil/pyutil.hpp" +#include namespace xo { namespace ast { @@ -13,6 +16,9 @@ namespace xo { using xo::ast::Expression; using xo::ast::ConstantInterface; using xo::ast::Constant; + using xo::ast::PrimitiveInterface; + using xo::ast::Primitive; + using xo::ast::make_primitive; using xo::reflect::TaggedPtr; using xo::ref::rp; namespace py = pybind11; @@ -38,6 +44,8 @@ namespace xo { .def("__repr__", &Expression::display_string); ; + // ----- Constants ----- + py::class_>(m, "ConstantInterface") @@ -69,6 +77,31 @@ namespace xo { py::doc("make_constant(x) creates constant expression holding x [wip - only works for double")) ; + // ----- Primitives ----- + + py::class_>(m, "PrimitiveInterface") + .def("name", &PrimitiveInterface::name, + py::doc("name of this primitive function; use this name to invoke the function")) + .def("n_arg", &PrimitiveInterface::n_arg, + py::doc("number of arguments to this function (not counting return value)")) + ; + + using Fn_dbl_dbl_type = double (*)(double); + + m.def("make_sqrt_pm", []() { return make_primitive("sqrt", sqrt); }, + py::doc("create primitive representing the ::sqrt() function")); + m.def("make_sin_pm", []() { return make_primitive("sin", ::sin); }, + py::doc("create primitive representing the ::sin() function")); + m.def("make_cos_pm", []() { return make_primitive("cos", ::cos); }, + py::doc("create primitive representing the ::cos() function")); + + py::class_, + PrimitiveInterface, + rp>>(m, "Primitive_double_double") + ; + } /*pyexpresion*/ } /*namespace ast*/ } /*namespace xo*/ From 3d354f76575d5625deeb22e1bdd6652facf30f86 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 14 Jun 2024 16:18:55 -0400 Subject: [PATCH 04/21] xo-pyexpression: + Apply expressions --- src/pyexpression/pyexpression.cpp | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/pyexpression/pyexpression.cpp b/src/pyexpression/pyexpression.cpp index c42fbcc7..6fecc65b 100644 --- a/src/pyexpression/pyexpression.cpp +++ b/src/pyexpression/pyexpression.cpp @@ -3,10 +3,11 @@ #include "pyexpression.hpp" #include "xo/pyreflect/pyreflect.hpp" #include "xo/expression/Expression.hpp" -#include "xo/expression/ConstantInterface.hpp" -#include "xo/expression/Constant.hpp" +#include "xo/expression/Apply.hpp" #include "xo/expression/PrimitiveInterface.hpp" #include "xo/expression/Primitive.hpp" +#include "xo/expression/ConstantInterface.hpp" +#include "xo/expression/Constant.hpp" #include "xo/pyutil/pyutil.hpp" #include @@ -14,11 +15,12 @@ namespace xo { namespace ast { using xo::ast::exprtype; using xo::ast::Expression; - using xo::ast::ConstantInterface; - using xo::ast::Constant; + using xo::ast::make_apply; using xo::ast::PrimitiveInterface; using xo::ast::Primitive; using xo::ast::make_primitive; + using xo::ast::ConstantInterface; + using xo::ast::Constant; using xo::reflect::TaggedPtr; using xo::ref::rp; namespace py = pybind11; @@ -80,7 +82,7 @@ namespace xo { // ----- Primitives ----- py::class_>(m, "PrimitiveInterface") .def("name", &PrimitiveInterface::name, py::doc("name of this primitive function; use this name to invoke the function")) @@ -102,6 +104,17 @@ namespace xo { rp>>(m, "Primitive_double_double") ; + // ----- Apply ----- + + py::class_>(m, "Apply") + .def_property_readonly("fn", &Apply::fn, py::doc("function to be invoked")) + .def_property_readonly("argv", &Apply::argv, py::doc("expressions (in position order) for function arguments")) + ; + + m.def("make_apply", &make_apply); + } /*pyexpresion*/ } /*namespace ast*/ } /*namespace xo*/ From a9deebaa90e77757dfc7d335c282fbef5b834713 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 14 Jun 2024 16:23:01 -0400 Subject: [PATCH 05/21] xo-pyexpression: bugfix: missing #includes for pybind11 opt feats --- src/pyexpression/pyexpression.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pyexpression/pyexpression.cpp b/src/pyexpression/pyexpression.cpp index 6fecc65b..2a9c38d3 100644 --- a/src/pyexpression/pyexpression.cpp +++ b/src/pyexpression/pyexpression.cpp @@ -9,6 +9,8 @@ #include "xo/expression/ConstantInterface.hpp" #include "xo/expression/Constant.hpp" #include "xo/pyutil/pyutil.hpp" +#include +#include #include namespace xo { From 97c0613fee0174f7856b1be31c1af5dddd3a976b Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 14 Jun 2024 16:23:21 -0400 Subject: [PATCH 06/21] xo-pyexpression: Expression.extype -> readonly property --- src/pyexpression/pyexpression.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pyexpression/pyexpression.cpp b/src/pyexpression/pyexpression.cpp index 2a9c38d3..01447f4f 100644 --- a/src/pyexpression/pyexpression.cpp +++ b/src/pyexpression/pyexpression.cpp @@ -44,7 +44,7 @@ namespace xo { py::class_>(m, "Expression") - .def("extype", &Expression::extype) + .def_property_readonly("extype", &Expression::extype) .def("__repr__", &Expression::display_string); ; From 7fcb0026f1f46635965ac7f4f2ec56b0d97e27e5 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 14 Jun 2024 16:26:23 -0400 Subject: [PATCH 07/21] pyexpression: + Variable + make_var --- src/pyexpression/pyexpression.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/pyexpression/pyexpression.cpp b/src/pyexpression/pyexpression.cpp index 01447f4f..2c8ca496 100644 --- a/src/pyexpression/pyexpression.cpp +++ b/src/pyexpression/pyexpression.cpp @@ -8,6 +8,7 @@ #include "xo/expression/Primitive.hpp" #include "xo/expression/ConstantInterface.hpp" #include "xo/expression/Constant.hpp" +#include "xo/expression/Variable.hpp" #include "xo/pyutil/pyutil.hpp" #include #include @@ -23,6 +24,8 @@ namespace xo { using xo::ast::make_primitive; using xo::ast::ConstantInterface; using xo::ast::Constant; + using xo::ast::Variable; + using xo::ast::make_var; using xo::reflect::TaggedPtr; using xo::ref::rp; namespace py = pybind11; @@ -117,6 +120,14 @@ namespace xo { m.def("make_apply", &make_apply); + // ----- Variables ----- + + py::class_>(m, "Variable") + .def_property_readonly("name", &Variable::name, py::doc("variable name")) + ; + + m.def("make_var", &make_var); + } /*pyexpresion*/ } /*namespace ast*/ } /*namespace xo*/ From 42a4009d027fa72bfdb8e0f6f2f3e7f742128697 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 14 Jun 2024 16:40:24 -0400 Subject: [PATCH 08/21] pyexpression: + Lambda + make_lambda --- src/pyexpression/pyexpression.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/pyexpression/pyexpression.cpp b/src/pyexpression/pyexpression.cpp index 2c8ca496..ff808c0c 100644 --- a/src/pyexpression/pyexpression.cpp +++ b/src/pyexpression/pyexpression.cpp @@ -9,6 +9,7 @@ #include "xo/expression/ConstantInterface.hpp" #include "xo/expression/Constant.hpp" #include "xo/expression/Variable.hpp" +#include "xo/expression/Lambda.hpp" #include "xo/pyutil/pyutil.hpp" #include #include @@ -26,6 +27,8 @@ namespace xo { using xo::ast::Constant; using xo::ast::Variable; using xo::ast::make_var; + using xo::ast::Lambda; + using xo::ast::make_lambda; using xo::reflect::TaggedPtr; using xo::ref::rp; namespace py = pybind11; @@ -111,9 +114,7 @@ namespace xo { // ----- Apply ----- - py::class_>(m, "Apply") + py::class_>(m, "Apply") .def_property_readonly("fn", &Apply::fn, py::doc("function to be invoked")) .def_property_readonly("argv", &Apply::argv, py::doc("expressions (in position order) for function arguments")) ; @@ -128,6 +129,15 @@ namespace xo { m.def("make_var", &make_var); + // ----- Lambdas ----- + + py::class_>(m, "Lambda") + .def_property_readonly("name", &Lambda::name, py::doc("lambda name (maybe automatically generated?)")) + .def_property_readonly("argv", &Lambda::argv, py::doc("lambda formal parameters")) + .def_property_readonly("body", &Lambda::body, py::doc("lambda body expression")) + ; + + m.def("make_lambda", &make_lambda); } /*pyexpresion*/ } /*namespace ast*/ } /*namespace xo*/ From a4396576c84ae0563fc7494f477cef91f40dd977 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 17 Jun 2024 16:55:24 -0400 Subject: [PATCH 09/21] xo-pyexpression: + if-expressions --- src/pyexpression/pyexpression.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/pyexpression/pyexpression.cpp b/src/pyexpression/pyexpression.cpp index ff808c0c..a74c7076 100644 --- a/src/pyexpression/pyexpression.cpp +++ b/src/pyexpression/pyexpression.cpp @@ -10,6 +10,7 @@ #include "xo/expression/Constant.hpp" #include "xo/expression/Variable.hpp" #include "xo/expression/Lambda.hpp" +#include "xo/expression/IfExpr.hpp" #include "xo/pyutil/pyutil.hpp" #include #include @@ -29,6 +30,8 @@ namespace xo { using xo::ast::make_var; using xo::ast::Lambda; using xo::ast::make_lambda; + using xo::ast::IfExpr; + using xo::ast::make_ifexpr; using xo::reflect::TaggedPtr; using xo::ref::rp; namespace py = pybind11; @@ -46,6 +49,7 @@ namespace xo { .value("apply", exprtype::apply) .value("lambda", exprtype::lambda) .value("variable", exprtype::variable) + .value("ifexpr", exprtype::ifexpr) ; py::class_>(m, "IfExpr") + .def_property_readonly("test", &IfExpr::test, py::doc("test expression")) + .def_property_readonly("when_true", &IfExpr::when_true, py::doc("execute this expression when (and only when) test succeeds")) + .def_property_readonly("when_false", &IfExpr::when_false, py::doc("execute this expression when (and only when) test fails")) + ; + + m.def("make_ifexpr", &make_ifexpr); } /*pyexpresion*/ } /*namespace ast*/ } /*namespace xo*/ From 8c44daf87d7064a46e989dde4323d412cf7d2c63 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 17 Jun 2024 16:56:03 -0400 Subject: [PATCH 10/21] xo-pyexpression: + make_pow_pm() --- src/pyexpression/pyexpression.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/pyexpression/pyexpression.cpp b/src/pyexpression/pyexpression.cpp index a74c7076..1b945f87 100644 --- a/src/pyexpression/pyexpression.cpp +++ b/src/pyexpression/pyexpression.cpp @@ -110,11 +110,17 @@ namespace xo { py::doc("create primitive representing the ::sin() function")); m.def("make_cos_pm", []() { return make_primitive("cos", ::cos); }, py::doc("create primitive representing the ::cos() function")); + m.def("make_pow_pm", []() { return make_primitive("pow", ::pow); }, + py::doc("create primitive representing the ::pow() function")); py::class_, PrimitiveInterface, rp>>(m, "Primitive_double_double") ; + py::class_, + PrimitiveInterface, + rp>>(m, "Primitive_double_double_double") + ; // ----- Apply ----- From ac2c0a7f263d2e3d675ae6b9f7114a5f38eaf2a6 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 17 Jun 2024 16:56:30 -0400 Subject: [PATCH 11/21] xo-pyexpression: use Apply::make() instead of make_apply() --- src/pyexpression/pyexpression.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pyexpression/pyexpression.cpp b/src/pyexpression/pyexpression.cpp index 1b945f87..6ba4ec54 100644 --- a/src/pyexpression/pyexpression.cpp +++ b/src/pyexpression/pyexpression.cpp @@ -129,7 +129,7 @@ namespace xo { .def_property_readonly("argv", &Apply::argv, py::doc("expressions (in position order) for function arguments")) ; - m.def("make_apply", &make_apply); + m.def("make_apply", &Apply::make); // ----- Variables ----- From abd33daec0d22144918aa6575ebf5ebe6832cdd2 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Mon, 17 Jun 2024 16:56:42 -0400 Subject: [PATCH 12/21] xo-pyexpression: + lambda getters .type_str .n_arg --- src/pyexpression/pyexpression.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pyexpression/pyexpression.cpp b/src/pyexpression/pyexpression.cpp index 6ba4ec54..bc58917d 100644 --- a/src/pyexpression/pyexpression.cpp +++ b/src/pyexpression/pyexpression.cpp @@ -143,8 +143,10 @@ namespace xo { py::class_>(m, "Lambda") .def_property_readonly("name", &Lambda::name, py::doc("lambda name (maybe automatically generated?)")) + .def_property_readonly("type_str", &Lambda::type_str, py::doc("string specifying lambda type. e.g. \"double(double,double)\"")) .def_property_readonly("argv", &Lambda::argv, py::doc("lambda formal parameters")) .def_property_readonly("body", &Lambda::body, py::doc("lambda body expression")) + .def_property_readonly("n_arg", &Lambda::n_arg, py::doc("number of format parameters to this lambda function")) ; m.def("make_lambda", &make_lambda); From c381fc47517c1811bba847cdb7ac8b07a434e8db Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 18 Jun 2024 17:26:14 -0400 Subject: [PATCH 13/21] xo-pyexpression: + typedescr arg to make_var() --- src/pyexpression/pyexpression.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/pyexpression/pyexpression.cpp b/src/pyexpression/pyexpression.cpp index bc58917d..283df9ac 100644 --- a/src/pyexpression/pyexpression.cpp +++ b/src/pyexpression/pyexpression.cpp @@ -137,7 +137,9 @@ namespace xo { .def_property_readonly("name", &Variable::name, py::doc("variable name")) ; - m.def("make_var", &make_var); + m.def("make_var", &make_var, + py::arg("name"), + py::arg("var_type")); // ----- Lambdas ----- From dc4f13815a19b386cee6f9cd7b9094e74bee83f5 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 19 Jun 2024 11:01:24 -0400 Subject: [PATCH 14/21] xo-pyexpression: + Expression.valuetype --- src/pyexpression/pyexpression.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/pyexpression/pyexpression.cpp b/src/pyexpression/pyexpression.cpp index 283df9ac..a69828d1 100644 --- a/src/pyexpression/pyexpression.cpp +++ b/src/pyexpression/pyexpression.cpp @@ -55,6 +55,7 @@ namespace xo { py::class_>(m, "Expression") .def_property_readonly("extype", &Expression::extype) + .def_property_readonly("valuetype", &Expression::valuetype) .def("__repr__", &Expression::display_string); ; @@ -106,7 +107,8 @@ namespace xo { m.def("make_sqrt_pm", []() { return make_primitive("sqrt", sqrt); }, py::doc("create primitive representing the ::sqrt() function")); - m.def("make_sin_pm", []() { return make_primitive("sin", ::sin); }, + m.def("make_sin_pm", + []() { return make_primitive("sin", ::sin); }, py::doc("create primitive representing the ::sin() function")); m.def("make_cos_pm", []() { return make_primitive("cos", ::cos); }, py::doc("create primitive representing the ::cos() function")); From 34123662b8d33735318e987fb8aa0f60aec86388 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Wed, 19 Jun 2024 18:16:47 -0400 Subject: [PATCH 15/21] xo-pyexpression: supply explicit_symbol_def to make_primitive --- src/pyexpression/pyexpression.cpp | 38 +++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/src/pyexpression/pyexpression.cpp b/src/pyexpression/pyexpression.cpp index a69828d1..10307d68 100644 --- a/src/pyexpression/pyexpression.cpp +++ b/src/pyexpression/pyexpression.cpp @@ -103,27 +103,45 @@ namespace xo { py::doc("number of arguments to this function (not counting return value)")) ; - using Fn_dbl_dbl_type = double (*)(double); + using int32_t = std::int32_t; - m.def("make_sqrt_pm", []() { return make_primitive("sqrt", sqrt); }, - py::doc("create primitive representing the ::sqrt() function")); - m.def("make_sin_pm", - []() { return make_primitive("sin", ::sin); }, - py::doc("create primitive representing the ::sin() function")); - m.def("make_cos_pm", []() { return make_primitive("cos", ::cos); }, - py::doc("create primitive representing the ::cos() function")); - m.def("make_pow_pm", []() { return make_primitive("pow", ::pow); }, - py::doc("create primitive representing the ::pow() function")); + py::class_, + PrimitiveInterface, + rp>>(m, "Primitive_i32_i32") + ; py::class_, PrimitiveInterface, rp>>(m, "Primitive_double_double") ; + using Fn_dbl_dbl_type = double (*)(double); + + m.def("make_sqrt_pm", []() { return make_primitive("sqrt", + ::sqrt, + false /*!explicit_symbol_def*/); }, + py::doc("create primitive representing the ::sqrt() function")); + m.def("make_sin_pm", + []() { return make_primitive("sin", + ::sin, + false /*!explicit_symbol_def*/); }, + py::doc("create primitive representing the ::sin() function")); + m.def("make_cos_pm", + []() { return make_primitive("cos", + ::cos, + false /*!explicit_symbol_def*/); }, + py::doc("create primitive representing the ::cos() function")); + py::class_, PrimitiveInterface, rp>>(m, "Primitive_double_double_double") ; + m.def("make_pow_pm", + []() { return make_primitive("pow", + ::pow, + false /*!explicit_symbol_def*/); }, + py::doc("create primitive representing the ::pow() function")); + // ----- Apply ----- py::class_>(m, "Apply") From f4efdd970060c9b6d96495b8a47f8dbee6087df8 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Fri, 21 Jun 2024 14:06:26 -0400 Subject: [PATCH 16/21] xo-pyexpression: supply llvm intrinsic to each primitive --- src/pyexpression/pyexpression.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/pyexpression/pyexpression.cpp b/src/pyexpression/pyexpression.cpp index 10307d68..0768c502 100644 --- a/src/pyexpression/pyexpression.cpp +++ b/src/pyexpression/pyexpression.cpp @@ -118,17 +118,20 @@ namespace xo { m.def("make_sqrt_pm", []() { return make_primitive("sqrt", ::sqrt, - false /*!explicit_symbol_def*/); }, + false /*!explicit_symbol_def*/, + llvmintrinsic::fp_sqrt); }, py::doc("create primitive representing the ::sqrt() function")); m.def("make_sin_pm", []() { return make_primitive("sin", ::sin, - false /*!explicit_symbol_def*/); }, + false /*!explicit_symbol_def*/, + llvmintrinsic::fp_sin); }, py::doc("create primitive representing the ::sin() function")); m.def("make_cos_pm", []() { return make_primitive("cos", ::cos, - false /*!explicit_symbol_def*/); }, + false /*!explicit_symbol_def*/, + llvmintrinsic::fp_cos); }, py::doc("create primitive representing the ::cos() function")); py::class_, @@ -139,7 +142,8 @@ namespace xo { m.def("make_pow_pm", []() { return make_primitive("pow", ::pow, - false /*!explicit_symbol_def*/); }, + false /*!explicit_symbol_def*/, + llvmintrinsic::fp_pow); }, py::doc("create primitive representing the ::pow() function")); // ----- Apply ----- From 38ed17cd9f5297c05d1225ef817e0f1d372c6ee8 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Tue, 2 Jul 2024 12:25:18 -0400 Subject: [PATCH 17/21] + Expression.get_free_variables + fix primitives --- src/pyexpression/pyexpression.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/pyexpression/pyexpression.cpp b/src/pyexpression/pyexpression.cpp index bc58917d..a5a931e4 100644 --- a/src/pyexpression/pyexpression.cpp +++ b/src/pyexpression/pyexpression.cpp @@ -55,6 +55,7 @@ namespace xo { py::class_>(m, "Expression") .def_property_readonly("extype", &Expression::extype) + .def("get_free_variables", &Expression::get_free_variables) .def("__repr__", &Expression::display_string); ; @@ -104,13 +105,13 @@ namespace xo { using Fn_dbl_dbl_type = double (*)(double); - m.def("make_sqrt_pm", []() { return make_primitive("sqrt", sqrt); }, + m.def("make_sqrt_pm", []() { return make_primitive("sqrt", sqrt, false /*!explicit*/, llvmintrinsic::invalid); }, py::doc("create primitive representing the ::sqrt() function")); - m.def("make_sin_pm", []() { return make_primitive("sin", ::sin); }, + m.def("make_sin_pm", []() { return make_primitive("sin", ::sin, false /*!explicit*/, llvmintrinsic::invalid); }, py::doc("create primitive representing the ::sin() function")); - m.def("make_cos_pm", []() { return make_primitive("cos", ::cos); }, + m.def("make_cos_pm", []() { return make_primitive("cos", ::cos, false /*!explicit*/, llvmintrinsic::invalid); }, py::doc("create primitive representing the ::cos() function")); - m.def("make_pow_pm", []() { return make_primitive("pow", ::pow); }, + m.def("make_pow_pm", []() { return make_primitive("pow", ::pow, false /*!explicit*/, llvmintrinsic::invalid); }, py::doc("create primitive representing the ::pow() function")); py::class_, From 563b7250d29873f08876eec8eec84ca66345e0cb Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sun, 15 Sep 2024 11:13:09 -0500 Subject: [PATCH 18/21] xo-pyexpression: build: drop xo-pyreflect dep --- src/pyexpression/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pyexpression/CMakeLists.txt b/src/pyexpression/CMakeLists.txt index 6e81f021..0c9714bb 100644 --- a/src/pyexpression/CMakeLists.txt +++ b/src/pyexpression/CMakeLists.txt @@ -5,5 +5,5 @@ set(SELF_SRCS pyexpression.cpp) xo_pybind11_library(${SELF_LIB} ${PROJECT_NAME}Targets ${SELF_SRCS}) xo_pybind11_dependency(${SELF_LIB} xo_expression) -xo_pybind11_dependency(${SELF_LIB} xo_pyreflect) +#xo_pybind11_dependency(${SELF_LIB} xo_pyreflect) xo_dependency(${SELF_LIB} refcnt) From c393512912ac851a6416866cc79e4d34bd2425b1 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sun, 15 Sep 2024 13:37:03 -0500 Subject: [PATCH 19/21] xo-pyexpression: bugfix: xo::ref::rp -> xo::rp --- src/pyexpression/pyexpression.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pyexpression/pyexpression.cpp b/src/pyexpression/pyexpression.cpp index d5a3cf47..fe51f6fb 100644 --- a/src/pyexpression/pyexpression.cpp +++ b/src/pyexpression/pyexpression.cpp @@ -33,7 +33,6 @@ namespace xo { using xo::ast::IfExpr; using xo::ast::make_ifexpr; using xo::reflect::TaggedPtr; - using xo::ref::rp; namespace py = pybind11; PYBIND11_MODULE(XO_PYEXPRESSION_MODULE_NAME(), m) { From 38f5e58ed51f777cc09d480e0e1d608bb24f0f46 Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Sat, 3 May 2025 09:18:34 -0700 Subject: [PATCH 20/21] nit: xo::ref::rp -> xo::rp --- src/pyexpression/pyexpression.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pyexpression/pyexpression.cpp b/src/pyexpression/pyexpression.cpp index d5a3cf47..8536e34e 100644 --- a/src/pyexpression/pyexpression.cpp +++ b/src/pyexpression/pyexpression.cpp @@ -33,7 +33,7 @@ namespace xo { using xo::ast::IfExpr; using xo::ast::make_ifexpr; using xo::reflect::TaggedPtr; - using xo::ref::rp; + using xo::rp; namespace py = pybind11; PYBIND11_MODULE(XO_PYEXPRESSION_MODULE_NAME(), m) { From 7fdf5b4a78d2e74ef554d35106ccf456cb51e50d Mon Sep 17 00:00:00 2001 From: Roland Conybeare Date: Thu, 8 May 2025 23:58:58 -0500 Subject: [PATCH 21/21] xo-pyexpression: cmake dep fixes --- src/pyexpression/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pyexpression/CMakeLists.txt b/src/pyexpression/CMakeLists.txt index 0c9714bb..1f49b0b9 100644 --- a/src/pyexpression/CMakeLists.txt +++ b/src/pyexpression/CMakeLists.txt @@ -5,5 +5,6 @@ set(SELF_SRCS pyexpression.cpp) xo_pybind11_library(${SELF_LIB} ${PROJECT_NAME}Targets ${SELF_SRCS}) xo_pybind11_dependency(${SELF_LIB} xo_expression) -#xo_pybind11_dependency(${SELF_LIB} xo_pyreflect) +# always use this when xo_pyfoo depends on xo_pybar +xo_pybind11_header_dependency(${SELF_LIB} xo_pyreflect) xo_dependency(${SELF_LIB} refcnt)