diff --git a/.xo-interpreter/CMakeLists.txt b/.xo-interpreter/CMakeLists.txt deleted file mode 100644 index a14ee394..00000000 --- a/.xo-interpreter/CMakeLists.txt +++ /dev/null @@ -1,41 +0,0 @@ -# xo-interpreter/CMakeLists.txt - -cmake_minimum_required(VERSION 3.10) - -project (xo_interpreter VERSION 0.1) - -include(GNUInstallDirs) -include(cmake/xo-bootstrap-macros.cmake) - -xo_cxx_toplevel_options3() - -# ---------------------------------------------------------------- -# c++ settings - -set(PROJECT_CXX_FLAGS "") -#set(PROJECT_CXX_FLAGS "-fconcepts-diagnostics-depth=2") # gcc-only! -add_definitions(${PROJECT_CXX_FLAGS}) - -# ---------------------------------------------------------------- - -# note on ordering: must read .cmake defn of lib before configuring any examples -add_subdirectory(src/interpreter) -xo_export_cmake_config(${PROJECT_NAME} ${PROJECT_VERSION} ${PROJECT_NAME}Targets) - -# ---------------------------------------------------------------- - -add_subdirectory(example) -add_subdirectory(utest) - -# ---------------------------------------------------------------- - -#if (XO_ENABLE_EXAMPLES) -# install(TARGETS xo_interpreter_ex1 DESTINATION bin/xo/example) -#endif() - -# ---------------------------------------------------------------- -# docs targets depend on all other library/utest targets -# -#add_subdirectory(docs) - -# end CMakeLists.txt diff --git a/.xo-interpreter/README.md b/.xo-interpreter/README.md deleted file mode 100644 index 133805c0..00000000 --- a/.xo-interpreter/README.md +++ /dev/null @@ -1 +0,0 @@ -# xo-interpreter diff --git a/.xo-interpreter/cmake/xo-bootstrap-macros.cmake b/.xo-interpreter/cmake/xo-bootstrap-macros.cmake deleted file mode 100644 index 592272c0..00000000 --- a/.xo-interpreter/cmake/xo-bootstrap-macros.cmake +++ /dev/null @@ -1,41 +0,0 @@ -# ---------------------------------------------------------------- -# 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 (XO_SUBMODULE_BUILD) - if (("${CMAKE_MODULE_PATH}" STREQUAL "") OR ("${CMAKE_MODULE_PATH}" STREQUAL prefix)) - # local version of xo-cmake macros - set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/xo-cmake/cmake") - message(STATUS "CMAKE_MODULE_PATH=${CMAKE_MODULE_PATH}") - endif() -else() - 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/.xo-interpreter/cmake/xo_interpreterConfig.cmake.in b/.xo-interpreter/cmake/xo_interpreterConfig.cmake.in deleted file mode 100644 index a1dba569..00000000 --- a/.xo-interpreter/cmake/xo_interpreterConfig.cmake.in +++ /dev/null @@ -1,8 +0,0 @@ -@PACKAGE_INIT@ - -include(CMakeFindDependencyMacro) -find_dependency(xo_alloc) -#find_dependency(xo_flatstring) -include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Targets.cmake") -include("${CMAKE_CURRENT_LIST_DIR}/@PROJECT_NAME@Share.cmake") -check_required_components("@PROJECT_NAME@") diff --git a/.xo-interpreter/docs/CMakeLists.txt b/.xo-interpreter/docs/CMakeLists.txt deleted file mode 100644 index b9df2dd6..00000000 --- a/.xo-interpreter/docs/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -# xo-alloc/docs/CMakeLists.txt - -xo_doxygen_collect_deps() -xo_docdir_doxygen_config() -xo_docdir_sphinx_config( - index.rst install.rst) - -# see xo-reader/doc or xo-unit/doc for working examples -# example.rst install.rst implementation.rst diff --git a/.xo-interpreter/docs/README b/.xo-interpreter/docs/README deleted file mode 100644 index 6aff5d41..00000000 --- a/.xo-interpreter/docs/README +++ /dev/null @@ -1,41 +0,0 @@ -standalone build - - +-----------------------------------------------+ - | cmake | - | CMakeLists.txt | - | $PREFIX/share/cmake/xo_macros/xo_cxx.cmake | - +-----------------------------------------------+ - | - | +----------------------+ - +------------------------------------------------->| .build/docs/Doxyfile | - | +----------------------+ - | ^ - | (cmake) | - | /------------/ - | | - | +---------------------------------------+ +-----------------+ - +---->| doxygen |--------->| .build/docs/dox | - | | $PREFIX/share/xo-macros/Doxyfile.in | (doxygen)| +- html/ | - | +---------------------------------------+ | +- xml/ | - | +-----------------+ - | | - | |(sphinx) - | | - | v - | +---------------------------------------+ +--------------------+ - \---->| sphinx |------->| .build/docs/sphinx | - | +- conf.py | | +- html/ | - | +- _static/ | +--------------------+ - | +- *.rst | - +---------------------------------------+ - -umbrella build relies on top-level cmake macros - -files - - README this file - CMakeLists.txt build entry point - conf.py sphinx config - _static static files for sphinx - - index.rst toplevel sphinx document; entry point diff --git a/.xo-interpreter/docs/_static/README b/.xo-interpreter/docs/_static/README deleted file mode 100644 index 8230095c..00000000 --- a/.xo-interpreter/docs/_static/README +++ /dev/null @@ -1 +0,0 @@ -add any static {.html, .js, ..} files for sphinx to pickup here \ No newline at end of file diff --git a/.xo-interpreter/docs/_static/img/favicon.ico b/.xo-interpreter/docs/_static/img/favicon.ico deleted file mode 100644 index 4163dd69..00000000 Binary files a/.xo-interpreter/docs/_static/img/favicon.ico and /dev/null differ diff --git a/.xo-interpreter/docs/conf.py b/.xo-interpreter/docs/conf.py deleted file mode 100644 index e5855955..00000000 --- a/.xo-interpreter/docs/conf.py +++ /dev/null @@ -1,39 +0,0 @@ -# Configuration file for the Sphinx documentation builder. -# -# For the full list of built-in configuration values, see the documentation: -# https://www.sphinx-doc.org/en/master/usage/configuration.html - -# -- Project information ----------------------------------------------------- -# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information - -project = 'xo interpreter documentation' -copyright = '2025, Roland Conybeare' -author = 'Roland Conybeare' - -# -- General configuration --------------------------------------------------- -# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration - -#extensions = [] -extensions = [ "breathe", - "sphinx.ext.mathjax", # inline math - "sphinx.ext.autodoc", # generate info from docstrings - "sphinxcontrib.ditaa", # diagrams-through-ascii-art - "sphinxcontrib.plantuml" # text -> uml diagrams - ] - -# note: breathe requires doxygen xml output -> must have GENERATE_XML = YES in Doxyfile.in -# match project name in Doxyfile.in -breathe_default_project = "xodoxxml" - -templates_path = ['_templates'] -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] - -pygments_style = 'sphinx' - -# -- Options for HTML output ------------------------------------------------- -# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output - -#html_theme = 'alabaster' -html_theme = 'sphinx_rtd_theme' -html_static_path = ['_static'] -html_favicon = '_static/img/favicon.ico' diff --git a/.xo-interpreter/docs/index.rst b/.xo-interpreter/docs/index.rst deleted file mode 100644 index e5b5a1c2..00000000 --- a/.xo-interpreter/docs/index.rst +++ /dev/null @@ -1,12 +0,0 @@ -.. xo-interpreter documentation master file. - -xo-interpreter documentation -============================ - -xo-interpreter provides an interpreter for the Schematika language - -.. toctree:: - :maxdepth: 2 - :caption: xo-interpreter contents - - install diff --git a/.xo-interpreter/docs/install.rst b/.xo-interpreter/docs/install.rst deleted file mode 100644 index 827bb1b0..00000000 --- a/.xo-interpreter/docs/install.rst +++ /dev/null @@ -1,202 +0,0 @@ -.. _install: - -.. toctree: - :maxdepth: 2 - -Source -====== - -Source code lives on github `here`_ - -.. _here: https://github.com/rconybea/xo-interpreter - -To clone from git: - -.. code-block:: bash - - git clone https://github.com/rconybea/xo-interpreter - -Tested with gcc 14.2 - -Install -======= - -One-step Install ----------------- - -Install xo-interpreter along with the rest of *XO* from `xo-umbrella2 source`_: -see install instructions for xo-umbrella2. - -.. _xo-umbrella2 source: https://github.com/rconybea/xo-umbrella2 - -Essential Xo Dependencies -------------------------- - -``xo-interpreter`` uses several supporting libraries from elsewhere in the *XO* project: - -- `xo-reader source`_ (Schematika expression parser) -- `xo-expression source`_ (Schematika AST representation) -- `xo-tokenizer source`_ (Schematika lexer) -- `xo-object source`_ (gc-eligible runtime polymorphism) -- `xo-randomgen source`_ (fast pseudo-random number generators) -- `xo-alloc source`_ (arena allocators, garbage collector) -- `xo-unit source`_ (dimension checking library) -- `xo-ratio source`_ (exact ratio library) -- `xo-flatstring source`_ (no-allocation string library) -- `xo-callback source`_ (callback library) -- `xo-reflectutil source`_ (reflection utils for participating libs) -- `xo-reflect source`_ (reflection library) -- `xo-refcnt source`_ (reference-counting library) -- `xo-subsys source`_ (utility library) -- `xo-indentlog source`_ (structured logging, pretty-printing) -- `xo-cmake source`_ (shared cmake macros) - -.. _xo-reader source: https://github.com/rconybea/xo-reader -.. _xo-expression source: https://github.com/rconybea/xo-expression -.. _xo-tokenizer source: https://github.com/rconybea/xo-tokenizer -.. _xo-object source: https://github.com/rconybea/xo-object -.. _xo-randomgen source: https://github.com/rconybea/xo-randomgen -.. _xo-alloc source: https://github.com/rconybea/xo-alloc -.. _xo-unit source: https://github.com/rconybea/xo-unit -.. _xo-ratio source: https://github.com/rconybea/xo-ratio -.. _xo-flatstring source: https://github.comr/rconybea/xo-flatstring -.. _xo-callback source: https://github.com/rconybea/xo-callback -.. _xo-reflect source: https://github.com/rconybea/xo-reflect -.. _xo-refcnt source: https://github.com/rconybea/refcnt -.. _xo-subsys source: https://github.com/rconybea/subsys -.. _xo-indentlog source: https://github.com/rconybea/indentlog -.. _xo-cmake source: https://github.com/rconybea/xo-cmake - -Building from source --------------------- - -Instructions for building xo-interpreter from source, along with only its essential dependencies. - -Install scripts for XO libraries depend on helper scripts installed from `xo-cmake`. - -Preamble: - -.. code-block:: bash - - mkdir -p ~/proj/xo - cd ~/proj/xo - - git clone https://github.com/rconybea/xo-cmake - - PREFIX=$HOME/local # or desired installation path - - # will want PREFIX/bin in PATH to use xo-cmake helpers - PATH=$PREFIX/bin:$PATH - -Isntall `xo-cmake`: - -.. code-block:: bash - - cmake -B xo-cmake/.build -S xo-cmake - cmake --install xo-cmake/.build - -Now that we have xo-build in PATH, can build+install XO components in topological order: - -.. code-block:: bash - - xo-build --clone --configure --build --install xo-indentlog - xo-build --clone --configure --build --install xo-subsys - xo-build --clone --configure --build --install xo-refcnt - xo-build --clone --configure --build --install xo-reflect - xo-build --clone --configure --build --install xo-reflectutil - xo-build --clone --configure --build --install xo-callback - xo-build --clone --configure --build --install xo-flatstring - xo-build --clone --configure --build --install xo-ratio - xo-build --clone --configure --build --install xo-unit - xo-build --clone --configure --build --install xo-alloc - xo-build --clone --configure --build --install xo-randomgen - xo-build --clone --configure --build --install xo-object - xo-build --clone --configure --build --install xo-tokenizer - xo-build --clone --configure --build --install xo-expression - xo-build --clone --configure --build --install xo-reader - -Directories under ``PREFIX`` will then contain something like: - -.. code-block:: - - PREFIX - += bin - | +- xo-build - │ +- xo-cmake-config - │ \- xo-cmake-lcov-harness - +─ include - | \- xo - │ +- alloc/ - | +- callback/ - | +- cxxutil/ - | +- expression/ - | | +- typeinf/ - | | .. - | +- flatstring/ - | +- indentlog/ - | | +- machdep/ - | | +- print/ - | | +- timeutil/ - | | .. - | +- object/ - | +- randomgen/ - | +- ratio/ - | +- reader/ - | +- refcnt/ - | +- reflect/ - | | +- atomic/ - | | +- function/ - | | +- pointer/ - | | +- struct/ - | | +- vector/ - | | .. - | +- reflectutil/ - | +- subsys/ - | +- tokenizer/ - | \- unit/ - +- lib - | +- cmake - | | +- callback/ - | | +- indentlog/ - | | +- randomgen/ - | | +- refcnt/ - | | +- reflect/ - | | +- subsys/ - | | +- xo_alloc/ - | | +- xo_expression/ - | | +- xo_flatstring/ - | | +- xo_object/ - | | +- xo_ratio/ - | | +- xo_reader/ - | | +- xo_reflectutil/ - | | +- xo_tokenizer/ - | | \- xo_unit/ - | +- librefcnt.so - | .. - \- share - +- cmake - | \- xo-macros - | +- code-coverage.cmake - | +- xo_cxx.cmake - | \- xo-project-macros.cmake - +- etc - | \- xo - | \- subsystem_list - +- xo-macros - +- Doxyfile.in - +- gen-ccov.in - \- xo-bootstrap-macros.cmake - -CMake Support -------------- - -To use built-in cmake support, when using ``xo-interpreter`` from another project: - -Make sure ``PREFIX/lib/cmake`` is searched by cmake (for example include it in ``CMAKE_PREFIX_PATH``) - -Add to your ``CMakeLists.txt``: - -.. code-block:: cmake - - FindPackage(xo_interpreter CONFIG REQUIRED) - target_link_libraries(mytarget PUBLIC xo_interpreter) diff --git a/.xo-interpreter/example/CMakeLists.txt b/.xo-interpreter/example/CMakeLists.txt deleted file mode 100644 index ce7aaf20..00000000 --- a/.xo-interpreter/example/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -add_subdirectory(replxx) diff --git a/.xo-interpreter/example/replxx/CMakeLists.txt b/.xo-interpreter/example/replxx/CMakeLists.txt deleted file mode 100644 index 96f11ae4..00000000 --- a/.xo-interpreter/example/replxx/CMakeLists.txt +++ /dev/null @@ -1,17 +0,0 @@ -# xo-interpreter/example/replxx/CMakeLists.txt - -set(SELF_EXE xo_interpreter_replxx) -set(SELF_SRCS replxx.cpp) - -if (XO_ENABLE_EXAMPLES) - xo_add_executable(${SELF_EXE} ${SELF_SRCS}) - xo_self_dependency(${SELF_EXE} xo_interpreter) - # TODO: consider promoting to regular app - xo_dependency(${SELF_EXE} xo_reader) - xo_external_target_dependency(${SELF_EXE} replxx replxx::replxx) - - find_package(Threads REQUIRED) - target_link_libraries(${SELF_EXE} PUBLIC Threads::Threads) -endif() - -# end CMakeLists.txt diff --git a/.xo-interpreter/example/replxx/replxx.cpp b/.xo-interpreter/example/replxx/replxx.cpp deleted file mode 100644 index ef677594..00000000 --- a/.xo-interpreter/example/replxx/replxx.cpp +++ /dev/null @@ -1,19 +0,0 @@ -/** @file replxx.cpp **/ - -#include "xo/interpreter/Schematika.hpp" - -int -main(int argc, char ** argv) -{ - using xo::log_level; - using xo::scm::Schematika; - - Schematika::Config cfg; - cfg.debug_flag = true; - cfg.vsm_log_level_ = log_level::verbose; - Schematika scm = Schematika::make(cfg); - - scm.interactive_repl(); -} - -/* end replxx.cpp */ diff --git a/.xo-interpreter/include/xo/interpreter/BuiltinPrimitives.hpp b/.xo-interpreter/include/xo/interpreter/BuiltinPrimitives.hpp deleted file mode 100644 index 39995b23..00000000 --- a/.xo-interpreter/include/xo/interpreter/BuiltinPrimitives.hpp +++ /dev/null @@ -1,36 +0,0 @@ -/** @file BuiltinPrimitives.hpp - * - * @author Roland Conybeare, Nov 2025 - **/ - -#include "xo/object/ObjectConverter.hpp" -#include "xo/allocutil/IAlloc.hpp" -#include "Primitive.hpp" -#include "GlobalEnv.hpp" - -namespace xo { - namespace scm { - struct BuiltinPrimitives { - public: - using ObjectConverter = xo::obj::ObjectConverter; - - template - static void install_pm(gc::IAlloc * mm, rp pm_expr, gp env) { - gp rhs - = xo::obj::make_primitive(mm, pm_expr->name(), pm_expr->value()); - - /* store in env using this variable-expr */ - rp lhs - = Variable::make(pm_expr->name(), pm_expr->value_td()); - - gp * addr = env->establish_var(lhs.borrow()); - - *addr = rhs; - } - - static void install(gc::IAlloc * mm, gp env); - }; - } -} - -/* end BuiltinPrimitives.hpp */ diff --git a/.xo-interpreter/include/xo/interpreter/Env.hpp b/.xo-interpreter/include/xo/interpreter/Env.hpp deleted file mode 100644 index bce51319..00000000 --- a/.xo-interpreter/include/xo/interpreter/Env.hpp +++ /dev/null @@ -1,47 +0,0 @@ -/** @file Env.hpp - * - * @author Roland Conybeare, Nov 2025 - **/ - -#pragma once - -#include "xo/alloc/Object.hpp" -#include "xo/refcnt/Refcounted.hpp" - -namespace xo { - namespace scm { - class Variable; // see xo::scm::Variable in xo/expression/Variable.hpp - - /** @class Env - * @brief runtime environment, holding variable bindings for schematika interpreter - * - * Garbage-collected - * - * TODO: rename xo-expression xo::scm::Environment -> xo::scm::SymbolTable - **/ - class Env : public Object { - public: - /** true iff @p vname is present in Symtab for innermost environment **/ - virtual bool local_contains_var(const std::string & vname) const = 0; - - /** Fetch storage location for innermost binding of variable with name @p vname. - * nullptr if not found - **/ - virtual gp * lookup_slot(const std::string & vname) = 0; - - /** require storage for variable @p v. - * will also establish binding path. - * - * Intended for introducing a new variable, - * replacing any previous variable with the same name. - * - * Beware of invalidating type correctness - * - * @return slot address for runtime value of @p v - **/ - virtual gp * establish_var(bp v) = 0; - - //gp lookup_symbol(const std::string & name) const; - }; - } /*namespace scm*/ -} /*namespace xo*/ diff --git a/.xo-interpreter/include/xo/interpreter/ExpressionBoxed.hpp b/.xo-interpreter/include/xo/interpreter/ExpressionBoxed.hpp deleted file mode 100644 index 5668a08a..00000000 --- a/.xo-interpreter/include/xo/interpreter/ExpressionBoxed.hpp +++ /dev/null @@ -1,48 +0,0 @@ -/** @file ExpressionBoxed.hpp - * - * @author Roland Conybeare, Nov 2025 - **/ - -#pragma once - -#include "xo/alloc/Object.hpp" -#include "xo/expression/Expression.hpp" - -namespace xo { - namespace scm { - /** @class ExpressionBoxed - * @brief xo::scm::Expression, adapted to xo::Object interface - **/ - class ExpressionBoxed : public Object { - public: - explicit ExpressionBoxed(bp c); - - /** create boxed version of @p c, using allocator @p mm **/ - static gp make(gc::IAlloc * mm, - bp c); - - /** runtime downcast **/ - static gp from(gp x) { - return gp::from(x); - } - - const rp & contents() const { return contents_; } - - // inherited from Object - virtual TaggedPtr self_tp() const final override; - virtual void display(std::ostream & os) const final override; - virtual std::size_t _shallow_size() const final override; - virtual Object * _shallow_copy(gc::IAlloc * mm) const final override; - virtual std::size_t _forward_children(gc::IAlloc * /*gc*/) final override; - - private: - /** reference-counted Expression pointer - * - * NOTE correctness requires finalization support in xo::gc::GC - **/ - rp contents_; - }; - } /*namespace scm*/ -} /*namespace xo*/ - -/* end ExpressionBoxed.hpp */ diff --git a/.xo-interpreter/include/xo/interpreter/GlobalEnv.hpp b/.xo-interpreter/include/xo/interpreter/GlobalEnv.hpp deleted file mode 100644 index 50e765ba..00000000 --- a/.xo-interpreter/include/xo/interpreter/GlobalEnv.hpp +++ /dev/null @@ -1,73 +0,0 @@ -/** @file GlobalEnv.hpp **/ - -#pragma once - -#include "Env.hpp" -#include "xo/allocutil/IAlloc.hpp" -#include "xo/expression/GlobalSymtab.hpp" - -namespace xo { - namespace scm { - /** @class GlobalEnv - * @brief Top-level global environment - **/ - class GlobalEnv : public Env { - public: - using map_type = std::map>; - - public: - /** Create top-level global environment, allocating via @p mm. - * Expect one of these per interpreter session. - **/ - static gp make_empty(gc::IAlloc * mm, - const rp & symtab); - -#ifdef NOT_USING - gc::IAlloc * get_mm() const { return mm_; } -#endif - - const rp & symtab() const { return symtab_; } - - // inherited from Env.. - virtual bool local_contains_var(const std::string & vname) const final override; - virtual gp * lookup_slot(const std::string & vname) final override; - virtual gp * establish_var(bp var) final override; - - // inherited from Object.. - virtual TaggedPtr self_tp() const final override; - virtual void display(std::ostream & os) const final override; - virtual std::size_t _shallow_size() const final override; - virtual Object * _shallow_copy(gc::IAlloc * mm) const final override; - virtual std::size_t _forward_children(gc::IAlloc * mm) final override; - - private: - GlobalEnv(const GlobalEnv & x); - GlobalEnv(gc::IAlloc * mm, const rp & symtab); - - private: - /** memory manager to use **/ - gc::IAlloc * mm_ = nullptr; - - /** global symbol table. - * variables known to @c symtab_ are represented by - * corresponding values in @p slot_map_ - **/ - rp symtab_; - - /** environment contents. - * expression @c symtab_->lookup_binding(vname) - * has associated value @c slot_map_.at(vname) - * - * TODO: replace with something subject to GC ? - * every member of @ref slot_map_ will have to be a - * GC root - * - * TODO: probably want to hash here instead. - * May also want lhs names to be separately hashed symbols - **/ - up slot_map_; - }; - } /*namespace scm*/ -} /*namespace xo*/ - -/* end GlobalEnv.hpp */ diff --git a/.xo-interpreter/include/xo/interpreter/LocalEnv.hpp b/.xo-interpreter/include/xo/interpreter/LocalEnv.hpp deleted file mode 100644 index 9745a854..00000000 --- a/.xo-interpreter/include/xo/interpreter/LocalEnv.hpp +++ /dev/null @@ -1,95 +0,0 @@ -/** @file LocalEnv.hpp **/ - -#include "Env.hpp" -#include "CVector.hpp" -#include "xo/allocutil/IAlloc.hpp" -#include "xo/expression/LocalSymtab.hpp" -#include -#include - -namespace xo { - namespace scm { - /** @class LocalEnv - * @brief Represent a single runtime stack frame for a Schematika function - * - * LocalEnv intended to be used for interpreted functions. - * - * Compiled functions will still likely have stack frames, but need not use the - * @ref LocalEnv class - * - * memory layout: - * ^ - * +-----------------------+ | - * | vtable | | - * +-----------------------+ | - * | .parent +------/ - * +------------+----------+ - * | .slot_v_ | .n_ | - * | +----------+ - * | | .v_ +------\ - * +------------+----------+ <--/ - * | .v_[0] +---------> Object(1) - * +-----------------------+ - * . .. . - * +-----------------------+ - * | .v_[.n_-1] +---------> Object(n) - * +-----------------------+ - **/ - class LocalEnv : public Env { - public: - using TaggedPtr = xo::reflect::TaggedPtr; - - public: - LocalEnv(gc::IAlloc * mm, gp p, const rp & s, std::size_t n); - - /** create frame using allocator @p mm, - * with parent @p p and exactly @p n_slot object pointers. - * variable types are taken from symbol table @p s. - **/ - static gp make(gc::IAlloc * mm, - gp p, - const rp & s, - std::size_t n_slot); - - /** reflect LocalEnv object representation **/ - static void reflect_self(); - - gp parent() const { return parent_; } - std::size_t size() const { return slot_v_.size(); } - - gp operator[](std::size_t i) const { return slot_v_[i]; } - gp & operator[](std::size_t i) { return slot_v_[i]; } - - // inherited from Env.. - - virtual bool local_contains_var(const std::string & vname) const final override; - - virtual gp * lookup_slot(const std::string & vname) final override; - - /** LocalEnv policy is that variable can be established once only. - * For example function arguments must all have distinct names. - **/ - virtual gp * establish_var(bp v) final override; - - // inherited from Object.. - virtual TaggedPtr self_tp() const final override; - virtual void display(std::ostream & os) const final override; - virtual std::size_t _shallow_size() const final override; - virtual Object * _shallow_copy(gc::IAlloc * mm) const final override; - virtual std::size_t _forward_children(gc::IAlloc * /*gc*/) final override; - - private: - /** parent stack frame **/ - gp parent_; - /** origin symbol table. records variable names and bindings. - * for a binding path p with leaf slot index j = p.j_slot_: - * @c slot_v_[j] holds value associated with variable @c symtab_->argv_[j] - **/ - rp symtab_; - /** environment contents **/ - obj::CVector> slot_v_; - }; - } /*namespace scm*/ -} /*namespace xo*/ - -/* end LocalEnv.hpp */ diff --git a/.xo-interpreter/include/xo/interpreter/Schematika.hpp b/.xo-interpreter/include/xo/interpreter/Schematika.hpp deleted file mode 100644 index 0c02d974..00000000 --- a/.xo-interpreter/include/xo/interpreter/Schematika.hpp +++ /dev/null @@ -1,70 +0,0 @@ -/** @file Schematika.hpp - * - * @author Roland Conybeare, Nov 2025 - **/ - -#pragma once - -#include "xo/alloc/GC.hpp" - -namespace xo { - namespace scm { - /** @class Schematika - * @brief schematika interpreter state - **/ - class Schematika { - public: - class Impl; - - struct Config { - /** true to enable welcome message **/ - bool welcome_flag_ = true; - /** number of command history items to preserve **/ - std::size_t history_size = 100; - /** on startup: load command history from this file; - persist last @ref history_size commands to the same file - **/ - std::string history_file = "scm_history.txt"; - /** when true enable console logging for repl internals **/ - bool debug_flag = false; - - /** garbage collector configuration **/ - gc::Config gc_config_; - - /** control schematika vsm logging **/ - log_level vsm_log_level_; - }; - - using IAlloc = xo::gc::IAlloc; - - public: - ~Schematika(); - - /** create instance with configuration @p cfg **/ - static Schematika make(const Config & cfg); - - /** interactive read-eval-print loop. - * Uses replxx to read from stdin. - * If stdin is interactive, accepts line editing commands: - * - ctrl-a goto beginning of line - * - ctrl-e goto end of line - * - ctrl-k delete to end of line - * - meta- backwards delete word - * - meta-p| retrieve previous command from history - * - meta-n| retrieve next command from history - * - / page through history faster - * - ctrl-s forward history search - * - ctrl-r backward history search - **/ - void interactive_repl(); - - private: - explicit Schematika(const Config & cfg); - - private: - up p_impl_; - }; - } -} - -/* end Schematika.hpp */ diff --git a/.xo-interpreter/include/xo/interpreter/SchematikaError.hpp b/.xo-interpreter/include/xo/interpreter/SchematikaError.hpp deleted file mode 100644 index 6baabad3..00000000 --- a/.xo-interpreter/include/xo/interpreter/SchematikaError.hpp +++ /dev/null @@ -1,28 +0,0 @@ -/** @file SchematikaError.hpp - * - * @author Roland Conybeare, Nov 2025 - **/ - -#pragma once - -#include - -namespace xo { - namespace scm { - class SchematikaError { - public: - SchematikaError() = default; - explicit SchematikaError(std::string x) : what_{std::move(x)} {} - - const std::string & what() const { return what_; } - - bool is_error() const { return !what_.empty(); } - bool is_not_an_error() const { return what_.empty(); } - - private: - std::string what_; - }; - } -} - -/* end SchematikaError.hpp */ diff --git a/.xo-interpreter/include/xo/interpreter/VirtualSchematikaMachine.hpp b/.xo-interpreter/include/xo/interpreter/VirtualSchematikaMachine.hpp deleted file mode 100644 index a8a182d9..00000000 --- a/.xo-interpreter/include/xo/interpreter/VirtualSchematikaMachine.hpp +++ /dev/null @@ -1,187 +0,0 @@ -/** @file VirtualSchematikaMachine.hpp **/ - -#pragma once - -#include "VsmInstr.hpp" -#include "VsmStackFrame.hpp" -#include "SchematikaError.hpp" -#include "GlobalEnv.hpp" -#include "xo/expression/Expression.hpp" -#include "xo/object/ObjectConverter.hpp" -#include "xo/alloc/Object.hpp" - -namespace xo { - namespace scm { - /** @brief state that may be shared across VirtualSchematikaMachine instances **/ - struct VirtualSchematikaMachineFlyweight { - explicit VirtualSchematikaMachineFlyweight(gc::IAlloc * mm, - gp env, - log_level log_level); - - /** memory allocator for interpreter operation. **/ - gc::IAlloc * object_mm_ = nullptr; - /** global environment **/ - gp toplevel_env_; - /** convert TaggedPtr->Object **/ - xo::obj::ObjectConverter object_converter_; - /** control logging level. higher values -> more logging **/ - log_level log_level_; - }; - - /** @class VirtualSchematikaMachine - * @brief Virtual machine implementing a Schematika interpreter - * - **/ - class VirtualSchematikaMachine { - public: - using IAlloc = xo::gc::IAlloc; - - public: - VirtualSchematikaMachine(IAlloc * mm, gp toplevel_env, log_level log_level); - ~VirtualSchematikaMachine(); - - gp toplevel_env() const { return flyweight_.toplevel_env_; } - - /** evaluate expression @p expr. - * borrows calling thread until completion - * return [value, error]. error ignored unless value is nullptr. - * conversely when value is nullptr, error gives details of original - * error. - * - * Evaluate schematika expression @p expr in environment @p env - **/ - std::pair, SchematikaError> eval(bp expr, gp env); - - /** evaluate expression @p expr in toplevel environment **/ - std::pair, SchematikaError> toplevel_eval(bp expr); - - private: - /** Not moveable or copyable. - * One constraint is member variables added to flyweight_.object_mm_ - * as GC roots, with no provision for unwinding later. - **/ - VirtualSchematikaMachine(const VirtualSchematikaMachine &) = delete; - VirtualSchematikaMachine(VirtualSchematikaMachine &&) = delete; - - /** borrow calling thread to run schematika machine - * indefinitely, or until null continuation - **/ - void run(); - - /** execute vsm instruction in program counter. - * Note: may possibly be able to replace with just opcode - * - * Registers: - * - expr_ input, caller saves - * - env_ input, caller saves - * - cont_ input, caller saves - * - stack_ input, caller saves - * - value_ output - * - error_ output - * - **/ - void execute_one(); - - /* design note: - * - eval_xxx_op() methods are primary VSM transitions, - * in the sense that they begin a sequence of transitions to interpret a - * particular kind of expression - * - do_xxx_op() methods represent secondary VSM transitions, - * that continue an instruction sequence that was initiated by a preceding - * eval_xxx_op() method - */ - - /** interpret literal constant expression **/ - void eval_constant_op(); - - /** interpreter literal primitive expression - * (these appear implicitly as result of builtin operators like {+, ==, ..}) - **/ - void eval_primitive_op(); - - /** execute define expression (finished in do_complete_assign_op()) **/ - void eval_define_op(); - /** execute assign expression (finishes in do_complete_assign_op()) **/ - void eval_assign_op(); - /** continue after establishing value fo rhs of define exprsssion **/ - void do_complete_assign_op(); - - /** interpret variable expression **/ - void eval_variable_op(); - - /** interpret if-expression **/ - void eval_ifexpr_op(); - /** continue after establish value of test expression **/ - void do_complete_ifexpr_op(); - - /** interpret sequence **/ - void eval_sequence_op(); - /** continue after establishing value for a sequence element **/ - void do_complete_sequence_op(); - - /** interpret apply-expression (i.e. function call) **/ - void eval_apply_op(); - /** continue assembling args for a function call; - * transition to (interpretation of) called function once all arguments - * are evaluated. - **/ - void do_complete_evalargs_op(); - - /** execute function application, given actuals in top stack frame **/ - void apply_op(); - - /** goto error state with message @p err **/ - void report_error(const std::string & err); - - /** implementation class; contains instruction implementations **/ - friend struct VsmOps; - - private: - /** program counter. - * (Perhaps replace with VsmInstr::Opcode ?) - **/ - const VsmInstr * pc_ = nullptr; - - /** register to hold Schematika expression to drive @ref execute_one. - * - * caller saves! - **/ - rp expr_; - /** holds bindings for all schematika variables, to drive @ref execute_one. - * execute_one will not save this - * - * caller saves! - **/ - gp env_; - - /** vsm stack. callee saves! - **/ - gp stack_; - - /** non-error result value from eval() / apply() - * - * output register: caller must save - **/ - gp value_; - - /** error result value from eval() / apply() - * - * output regisetr: caller must save - **/ - SchematikaError error_; - - /** continuation - * (Perhaps replace with VsmInstr::Opcode ?) - * - * input register: callee saves! - **/ - const VsmInstr * cont_ = nullptr; - - /** possibly-shared data **/ - VirtualSchematikaMachineFlyweight flyweight_; - }; - - } /*namespace scm*/ -} /*namespace xo*/ - -/* end VirtualSchematikaMachine.hpp */ diff --git a/.xo-interpreter/include/xo/interpreter/VsmInstr.hpp b/.xo-interpreter/include/xo/interpreter/VsmInstr.hpp deleted file mode 100644 index a1539bd0..00000000 --- a/.xo-interpreter/include/xo/interpreter/VsmInstr.hpp +++ /dev/null @@ -1,80 +0,0 @@ -/** @file VsmInstr.hpp **/ - -#pragma once - -#include - -namespace xo { - namespace scm { - class VirtualSchematikaMachine; // see VirtualSchematikaMachine.hpp - - /** @class VmInstr - * @brief Represent a particular vritual schematika machine instruction - * - * A vsm instruction acts on a virtual schematika machine instance. - **/ - class VsmInstr - { - public: - enum class Opcode { - /** Halt virtual schematika machine **/ - halt, - - /** Evaluate a schematika expression. - * See VirtualSchematikaMachine::eval() - **/ - eval, - - /** assign to variable + continue - * - * stack: frame with: - * [0] lhs : variable to assign - **/ - complete_assign, - - /** execute ifexpr branch, given - * result of test expression has been established - **/ - complete_ifexpr, - - /** execute remainder of expression sequence - **/ - complete_sequence, - - /** execute remainder of argument sequence evaluation; - * subsidiary to marshalling a function call - **/ - complete_evalargs, - - /** Call a function. Arguments have been evaluated - * and are in top stack frame, in order, - * starting with target function itself - **/ - apply, - - /** choose branch of if-expression + continue - * - * stack: frame with - * [0] ifexpr : original if-expression - **/ - N_Opcode - }; - - //using ActionFn = void (*)(VirtualSchematikaMachine * vm); - - public: - VsmInstr(Opcode opcode, std::string_view name); - - Opcode opcode() const { return opcode_; } - - private: - /** unique opcode for this instruction **/ - Opcode opcode_; - /** **/ - std::string_view name_; - //ActionFn action_; - }; - } -} - -/* end VsmInstr.hpp */ diff --git a/.xo-interpreter/include/xo/interpreter/VsmStackFrame.hpp b/.xo-interpreter/include/xo/interpreter/VsmStackFrame.hpp deleted file mode 100644 index 0fc0dee7..00000000 --- a/.xo-interpreter/include/xo/interpreter/VsmStackFrame.hpp +++ /dev/null @@ -1,83 +0,0 @@ -/** @file VsmStackFrame.hpp - * - * @author Roland Conybeare, Nov 2025 - **/ - -#pragma once - -#include "VsmInstr.hpp" -#include "xo/object/CVector.hpp" -#include "xo/alloc/Object.hpp" - -namespace xo { - namespace scm { - /** @class VsmStackFrame - * @brief Virtual Schematika Machine stack frame - * - * Intending to use the "cheney on the MTA" strategy, - * i.e. allocate frames using GC's bump allocator. - * - * Parallels LocalEnv, but VSM implementation isn't reflected - **/ - class VsmStackFrame : public Object { - public: - VsmStackFrame(gc::IAlloc * mm, gp p, std::size_t n, const VsmInstr * cont); - - /** create frame using allocator @p mm, - * with parent @p p and exactly @p n_slot object pointers. - **/ - static gp make(gc::IAlloc * mm, - gp p, - std::size_t n_slot, - const VsmInstr * cont); - - /** create new stack frame using allocator @p mm, - * with parent frame @p p; new frame contains values @p s0 - **/ - static gp push1(gc::IAlloc * mm, - gp p, - gp s0, - const VsmInstr * cont); - - /** create new stack frame using allocator @p mm, - * with parent frame @p p; new frame contains values @p s0, @p s1 - **/ - static gp push2(gc::IAlloc * mm, - gp p, - gp s0, - gp s1, - const VsmInstr * cont); - - - /** reflect VsmStackFrame object representation **/ - static void reflect_self(); - - gp parent() const { return parent_; } - std::size_t size() const { return slot_v_.size(); } - const obj::CVector> & argv() const { return slot_v_; } - const VsmInstr * continuation() const { return cont_; } - - gp operator[](std::size_t i) const { return slot_v_[i]; } - gp & operator[](std::size_t i) { return slot_v_[i]; } - - // inherited from Object.. - virtual TaggedPtr self_tp() const final override; - virtual void display(std::ostream & os) const final override; - virtual std::size_t _shallow_size() const final override; - virtual Object * _shallow_copy(gc::IAlloc *) const final override; - virtual std::size_t _forward_children(gc::IAlloc *) final override; - - private: - /** parent stack frame **/ - gp parent_; - - /** stored state **/ - obj::CVector> slot_v_; - - /** proceed to this continuation when popping this frame **/ - const VsmInstr * cont_ = nullptr; - }; - } /*namespace scm*/ -} /*namespace xo*/ - -/* end VsmStackFrame.hpp */ diff --git a/.xo-interpreter/include/xo/interpreter/init_interpreter.hpp b/.xo-interpreter/include/xo/interpreter/init_interpreter.hpp deleted file mode 100644 index 91e4828c..00000000 --- a/.xo-interpreter/include/xo/interpreter/init_interpreter.hpp +++ /dev/null @@ -1,21 +0,0 @@ -/** @file init_interpreter.hpp - * - * author: Roland Conybeare, Nov 2025 - **/ - -#pragma once - -#include "xo/subsys/Subsystem.hpp" - -namespace xo { - /* tag to represent the interpreter/ subsystem in ordered initialization */ - enum S_interpreter_tag {}; - - template<> - struct InitSubsys { - static void init(); - static InitEvidence require(); - }; -} - -/* end init_interpreter.hpp */ diff --git a/.xo-interpreter/src/interpreter/BuiltinPrimitives.cpp b/.xo-interpreter/src/interpreter/BuiltinPrimitives.cpp deleted file mode 100644 index bead7c87..00000000 --- a/.xo-interpreter/src/interpreter/BuiltinPrimitives.cpp +++ /dev/null @@ -1,94 +0,0 @@ -/** @file BuiltinPrimitives.cpp - * - * @author Roland Conybeare, Nov 2025 - **/ - -#include "BuiltinPrimitives.hpp" -#include "Integer.hpp" -#include "Primitive.hpp" -#include "xo/expression/PrimitiveExpr.hpp" -#include "xo/object/ObjectConversion.hpp" -#include "xo/reflect/Reflect.hpp" -#include - -namespace xo { - using xo::reflect::Reflect; - using xo::reflect::TaggedPtr; - using xo::reflect::TypeDescr; - - namespace scm { - int64_t - add64(int64_t x, int64_t y) - { - return x + y; - } - - void - BuiltinPrimitives::install(gc::IAlloc * mm, gp env) - { - scope log(XO_DEBUG(true)); - - // add(x,y) - { - gp rhs = xo::obj::make_primitive(mm, "add", add64); - - TypeDescr td = Reflect::require_function(); - - rp lhs = Variable::make("add", td); - gp * addr = env->establish_var(lhs.borrow()); - - *addr = rhs; - } - - // i64 comparisons - - // @cmp_eq2_i64 - install_pm(mm, PrimitiveExpr_cmp_i64::make_cmp_eq2_i64(), env); - - // @cmp_ne2_i64 - install_pm(mm, PrimitiveExpr_cmp_i64::make_cmp_ne2_i64(), env); - - // @cmp_lt2_i64 - install_pm(mm, PrimitiveExpr_cmp_i64::make_cmp_lt2_i64(), env); - - // @cmp_le2_i64 - install_pm(mm, PrimitiveExpr_cmp_i64::make_cmp_le2_i64(), env); - - // @cmp_gt2_i64 - install_pm(mm, PrimitiveExpr_cmp_i64::make_cmp_gt2_i64(), env); - - // @cmp_ge2_i64 - install_pm(mm, PrimitiveExpr_cmp_i64::make_cmp_ge2_i64(), env); - - // i64 arithmetic - - // @add2_i64 - install_pm(mm, PrimitiveExpr_i64::make_add2_i64(), env); - - // @sub2_i64 - install_pm(mm, PrimitiveExpr_i64::make_sub2_i64(), env); - - // @mul2_i64 - install_pm(mm, PrimitiveExpr_i64::make_mul2_i64(), env); - - // @div2_i64 - install_pm(mm, PrimitiveExpr_i64::make_div2_i64(), env); - - // ---------------------------------------------------------------- - - // @add2_f64 - install_pm(mm, PrimitiveExpr_f64::make_add2_f64(), env); - - // @sub2_f64 - install_pm(mm, PrimitiveExpr_f64::make_sub2_f64(), env); - - // @mul2_f64 - install_pm(mm, PrimitiveExpr_f64::make_mul2_f64(), env); - - // @div2_f64 - install_pm(mm, PrimitiveExpr_f64::make_div2_f64(), env); - } - } -} - -/* end BuiltinPrimitives.cpp */ diff --git a/.xo-interpreter/src/interpreter/CMakeLists.txt b/.xo-interpreter/src/interpreter/CMakeLists.txt deleted file mode 100644 index 912d4a93..00000000 --- a/.xo-interpreter/src/interpreter/CMakeLists.txt +++ /dev/null @@ -1,24 +0,0 @@ -# interpreter/CMakeLists.txt - -set(SELF_LIB xo_interpreter) -set(SELF_SRCS - init_interpreter.cpp - Schematika.cpp - BuiltinPrimitives.cpp - LocalEnv.cpp - GlobalEnv.cpp - VirtualSchematikaMachine.cpp - VsmInstr.cpp - VsmStackFrame.cpp - ExpressionBoxed.cpp -) - -find_package(Threads REQUIRED) - -xo_add_shared_library4(${SELF_LIB} ${PROJECT_NAME}Targets ${PROJECT_VERSION} 1 ${SELF_SRCS}) -xo_dependency(${SELF_LIB} xo_object) -xo_dependency(${SELF_LIB} xo_expression) -xo_dependency(${SELF_LIB} xo_reader) -xo_external_target_dependency(${SELF_LIB} replxx replxx::replxx) -target_link_libraries(${SELF_LIB} PUBLIC Threads::Threads) -xo_headeronly_dependency(${SELF_LIB} subsys) diff --git a/.xo-interpreter/src/interpreter/ExpressionBoxed.cpp b/.xo-interpreter/src/interpreter/ExpressionBoxed.cpp deleted file mode 100644 index 2d72ef33..00000000 --- a/.xo-interpreter/src/interpreter/ExpressionBoxed.cpp +++ /dev/null @@ -1,59 +0,0 @@ -/** @file ExpressionBoxed.cpp - * - * @author Roland Conybeare, Nov 2025 - **/ - -#include "ExpressionBoxed.hpp" -#include "xo/reflect/Reflect.hpp" - -namespace xo { - using xo::reflect::Reflect; - using xo::reflect::TaggedPtr; - - namespace scm { - ExpressionBoxed::ExpressionBoxed(bp c) : contents_{c.promote()} - {} - - gp - ExpressionBoxed::make(gc::IAlloc * mm, - bp c) - { - return new (MMPtr(mm)) ExpressionBoxed(c); - } - - - TaggedPtr - ExpressionBoxed::self_tp() const - { - return Reflect::make_tp(const_cast(this)); - } - - void - ExpressionBoxed::display(std::ostream & os) const - { - os << contents_; - } - - std::size_t - ExpressionBoxed::_shallow_size() const - { - return sizeof(ExpressionBoxed); - } - - Object * - ExpressionBoxed::_shallow_copy(gc::IAlloc * mm) const - { - Cpof cpof(mm, this); - - return new (cpof) ExpressionBoxed(*this); - } - - std::size_t - ExpressionBoxed::_forward_children(gc::IAlloc *) - { - return _shallow_size(); - } - } /*namespace scm*/ -} /*namespace xo*/ - -/* end ExpressionBoxed.cpp */ diff --git a/.xo-interpreter/src/interpreter/GlobalEnv.cpp b/.xo-interpreter/src/interpreter/GlobalEnv.cpp deleted file mode 100644 index 736af083..00000000 --- a/.xo-interpreter/src/interpreter/GlobalEnv.cpp +++ /dev/null @@ -1,127 +0,0 @@ -/** @file GlobalEnv.cpp **/ - -#include "GlobalEnv.hpp" -#include "xo/reflect/Reflect.hpp" - -namespace xo { - using xo::reflect::Reflect; - using xo::reflect::TaggedPtr; - - namespace scm { - gp - GlobalEnv::make_empty(gc::IAlloc * mm, const rp & symtab) - { - /* by design: GlobalEnv and GlobalEnv.slot_map_ are heap-allocated */ - - return new GlobalEnv(mm, symtab); - } - - GlobalEnv::GlobalEnv(const GlobalEnv & x) - : mm_{x.mm_}, - symtab_{x.symtab_}, - slot_map_{std::make_unique(*x.slot_map_)} - { - } - - GlobalEnv::GlobalEnv(gc::IAlloc * mm, - const rp & symtab) : mm_{mm}, - symtab_{symtab}, - slot_map_{std::make_unique()} - {} - - bool - GlobalEnv::local_contains_var(const std::string & vname) const - { - return symtab_->lookup_local(vname).get(); - } - - gp * - GlobalEnv::lookup_slot(const std::string & vname) - { - scope log(XO_DEBUG(true), xtag("name", vname)); - - assert(slot_map_.get()); - - auto ix = slot_map_->find(vname); - - if (ix == slot_map_->end()) { - return nullptr; - } else { - log && log("binding found", xtag("vname", vname)); - return &(ix->second); - } - } - - gp * - GlobalEnv::establish_var(bp var) - { - scope log(XO_DEBUG(true), xtag("name", var->name()), xtag("type", var->valuetype())); - - // Warning: altering declared type for an already-existing variable - // invalidates any type checking that relied on that variable. - // - // Ignoring this problem for now. - // - // Actual solution might look like: - // - keep track of which functions/defs depend on each global variable. - // - invalidate any jit / types for such variables. - // - maybe use seqno's to track - // - re-check / re-complie - // - need to admit invalid states. - // suppose have mutually recursive functions f(), g() - // want ability to modify type signatures separately - // - // Alternatives: - // - forbid changing type of an already-established variable - // Actually: can't even change values if we intend supporting dependent types - // - quietly number variables so new definitions shadow old ones but don't - // affect previously-encountered expressions - - this->symtab_->require_global(var->name(), var); - - gp &slot = (*this->slot_map_)[var->name()]; - - /* discard any pre-existing value, we're redefining a variable */ - slot = gp(); - - return &slot; - } - - TaggedPtr - GlobalEnv::self_tp() const - { - return Reflect::make_tp(const_cast(this)); - } - - void - GlobalEnv::display(std::ostream & os) const - { - os << "size()) << ">"; - } - - std::size_t - GlobalEnv::_shallow_size() const - { - return sizeof(GlobalEnv); - } - - Object * - GlobalEnv::_shallow_copy(gc::IAlloc * mm) const - { - Cpof cpof(mm, this); - - return new (cpof) GlobalEnv(*this); - } - - std::size_t - GlobalEnv::_forward_children(gc::IAlloc * gc) - { - for (auto & ix : *slot_map_) { - Object::_forward_inplace(ix.second, gc); - } - return _shallow_size(); - } - } /*namespace scm*/ -} /*namespace xo*/ - -/* end GlobalEnv.cpp */ diff --git a/.xo-interpreter/src/interpreter/LocalEnv.cpp b/.xo-interpreter/src/interpreter/LocalEnv.cpp deleted file mode 100644 index 8085f126..00000000 --- a/.xo-interpreter/src/interpreter/LocalEnv.cpp +++ /dev/null @@ -1,185 +0,0 @@ -/** @file LocalEnv.cpp **/ - -#include "LocalEnv.hpp" -#include "xo/reflect/Reflect.hpp" -#include "xo/reflect/StructReflector.hpp" -#include - -namespace xo { - using xo::reflect::Reflect; - using xo::reflect::StructReflector; - using xo::reflect::TypeDescrW; - using xo::reflect::TaggedPtr; - using xo::reflect::TypeDescrExtra; - using xo::reflect::EstablishTypeDescr; - using xo::reflect::StlVectorTdx; - using xo::print::quot; - - namespace scm { - namespace { - std::size_t - slot_array_size(std::size_t n) { - return n * sizeof(gp); - } - } - - gp - LocalEnv::make(gc::IAlloc * mm, - gp p, - const rp & s, - std::size_t n) - { - if (s) { - assert(static_cast(n) == s->n_arg()); - } - - return new (MMPtr(mm)) LocalEnv(mm, p, s, n); - } - - LocalEnv::LocalEnv(gc::IAlloc * mm, - gp p, - const rp & s, - std::size_t n) : parent_{p}, - symtab_{s}, - slot_v_{mm, n} - {} - - bool - LocalEnv::local_contains_var(const std::string & vname) const - { - assert(symtab_.get()); - - return symtab_->lookup_local(vname); - } - - gp * - LocalEnv::lookup_slot(const std::string & vname) - { - binding_path b = symtab_->lookup_local_binding(vname); - - if (b.i_link_ == 0) { - assert((b.j_slot_ >= 0) && (static_cast(b.j_slot_) < slot_v_.size())); - - return &(slot_v_[b.j_slot_]); - } - - if (parent_.get()) { - return parent_->lookup_slot(vname); - } - - return nullptr; - } - - gp * - LocalEnv::establish_var(bp v) - { - assert(v); - - throw std::runtime_error(tostr("LocalEnv::establish_var:" - " inserting new variables not supported for LocalEnv", - xtag("v.name", v->name()))); - } - - TaggedPtr - LocalEnv::self_tp() const - { - return Reflect::make_tp(const_cast(this)); - } - - void - LocalEnv::display(std::ostream & os) const - { - os << ""; - } - - std::size_t - LocalEnv::_shallow_size() const - { - std::size_t retval = sizeof(LocalEnv); - - retval += gc::IAlloc::with_padding(slot_array_size(slot_v_.size())); - - return retval; - } - - Object * - LocalEnv::_shallow_copy(gc::IAlloc * mm) const - { - Cpof cpof(mm, this); - - size_t z = this->size(); - - LocalEnv * copy = new (cpof) LocalEnv(cpof.mm_, parent_, symtab_, z); - - void * v_dest = copy->slot_v_.v_; - - if (slot_v_.v_) { - ::memcpy(v_dest, slot_v_.v_, slot_array_size(z)); - } - -#ifdef OBSOLETE - for (size_t i = 0, n = n_slot_; i < n; ++i) { - copy->v_[i] = v_[i]; - } -#endif - - return copy; - } - - std::size_t - LocalEnv::_forward_children(gc::IAlloc * gc) - { - static_assert(decltype(symtab_)::is_gc_ptr == false); - - Object::_forward_inplace(parent_, gc); - // Object::_forward_inplace(symtab_); // not a gp yet - for (std::size_t i = 0, n = slot_v_.size(); i < n; ++i) { - Object::_forward_inplace((*this)[i], gc); - } - - return _shallow_size(); - } - - void - LocalEnv::reflect_self() - { - StructReflector sr; - - if (sr.is_incomplete()) { - /* reflect CVector> - * - * note: placement here works b/c CVector not used anywhere else - */ - using VectorType = obj::CVector>; - - /* custom reflection for array of Object pointers. - * Can use StlVectorTdx here, treating CVector as a vector - * via .size() and .operator[] members - */ - std::unique_ptr tdx1 - = std::make_unique>(); - TypeDescrW td1 - = EstablishTypeDescr::establish(); - td1->assign_tdextra(Reflect::get_final_invoker(), - std::move(tdx1)); - - REFLECT_MEMBER(sr, parent); - REFLECT_MEMBER(sr, slot_v); - } - } - } /*namespace scm*/ -} /*namespace xo*/ - -/* end LocalEnv.cpp */ diff --git a/.xo-interpreter/src/interpreter/Schematika.cpp b/.xo-interpreter/src/interpreter/Schematika.cpp deleted file mode 100644 index 039b2e67..00000000 --- a/.xo-interpreter/src/interpreter/Schematika.cpp +++ /dev/null @@ -1,284 +0,0 @@ -/** @file Schematika.cpp - * - * @author Roland Conybeare, Nov 2025 - **/ - -#include "Schematika.hpp" -#include "VirtualSchematikaMachine.hpp" -#include "BuiltinPrimitives.hpp" -#include "GlobalEnv.hpp" -#include "xo/reader/reader.hpp" -#include -#include -#include // for STDIN_FILENO on OSX - -namespace xo { - using xo::gc::IAlloc; - using xo::gc::GC; - using xo::print::ppconfig; - using xo::print::ppstate_standalone; - using replxx::Replxx; - using namespace std; - - namespace scm { - - class Schematika::Impl { - public: - /** note: choosing to have Schemtika::Impl - * rather than VirtualSchematikaMachine to own allocator - * to preserve option to share it - **/ - Impl(const Config & config, up mm, gp toplevel_env); - ~Impl(); - - /** create instance + allocator **/ - static up make(const Config & cfg); - - /** borrow calling thread to run interactive read-eval-print loop; - * input from stdin, output to stdout. - **/ - void interactive_repl(); - - void welcome(std::ostream & os); - - /** get one line of input. prompt if @p interactive, - * with prompt depending on @p parser_stack_size. - * Use @p rx to perform line editing (when @p interactive). - * Store completed line in @p input. - **/ - bool replxx_getline(bool interactive, - std::size_t parser_stack_size, - replxx::Replxx & rx, - std::string & input); - - private: - /** configuration **/ - Config config_; - /** ownership for memory allocator / garbage collector; - * @ref vsm_ holds naked pointer, so this could in principle be nullptr - * in case want to maintain allocator ownership from outside. - * - * note: must appear before @ref vsm_, so latter gets destroyed first - **/ - up mm_; - /** schematika interpreter **/ - VirtualSchematikaMachine vsm_; - }; - - Schematika::Impl::Impl(const Config & config, up mm, gp toplevel_env) : - config_{config}, - mm_{std::move(mm)}, - vsm_{mm_.get(), toplevel_env, config.vsm_log_level_} - { - - } - - Schematika::Impl::~Impl() = default; - - up - Schematika::Impl::make(const Config & cfg) - { - up mm = GC::make(cfg.gc_config_); - rp symtab = GlobalSymtab::make_empty(); - gp env = GlobalEnv::make_empty(mm.get(), symtab); - - /* also see VirtualSchematikaMachineFlyweight::Impl::Impl, - * for BuiltinPrimitives::install_interpreter_conversions() - */ - BuiltinPrimitives::install(mm.get(), env); - - return std::make_unique(cfg, std::move(mm), env); - } - - void - Schematika::Impl::welcome(std::ostream & os) - { - using namespace std; - - os << "read-eval-print loop for schematika expressions" << endl; - os << " ctrl-a/ctrl-e beginning/end of line" << endl; - os << " ctrl-u delete entire line" << endl; - os << " ctrl-k delete to end of line" << endl; - os << " meta- backward delete word" << endl; - os << " |meta-p previous command from history" << endl; - os << " |meta-n next command from history" << endl; - os << " / page through history faster" << endl; - os << " ctrl-s/ctrl-r forward/backward history search" << endl; - os << endl; - } - - // similar helper in exprreplxx.cpp - // - bool - Schematika::Impl::replxx_getline(bool interactive, - std::size_t parser_stack_size, - replxx::Replxx & rx, - std::string & input) - { - using namespace std; - - char const * prompt = ""; - - if (interactive) { - if (parser_stack_size <= 1) - prompt = "> "; - else - prompt = ". "; - } - - /* input_cstr: next line of input from replxx library */ - const char * input_cstr = rx.input(prompt); - - bool retval = (input_cstr != nullptr); - - if (retval) { - /* got new input */ - input = input_cstr; - } - - rx.history_add(input); - - input.push_back('\n'); - - return retval; - } - - void - Schematika::Impl::interactive_repl() - { - scope log(XO_DEBUG(true)); - - using span_type = xo::scm::span; - - bool interactive = isatty(STDIN_FILENO); - - Replxx rx; - rx.set_max_history_size(config_.history_size); - rx.history_load(config_.history_file); - // rx.bind_key_internal(Replxx::KEY::control('p'), "history_previous"); - // rx.bind_key_internal(Replxx::KEY::control('n'), "history_next"); - - reader rdr(vsm_.toplevel_env()->symtab(), config_.debug_flag); - rdr.begin_interactive_session(); - - string input_str; - - bool eof = false; - - span_type input; - std::size_t parser_stack_size = 0; - - if (config_.welcome_flag_) - welcome(cerr); - - while (replxx_getline(interactive, parser_stack_size, rx, input_str)) { - input = span_type::from_string(input_str); - - while (!input.empty()) { - /** - * Three cases here: - * 1. available input is invalid (does not conform to schematika syntax). - * 1a. expr=nullptr - * 1b. consumed reads all available input - * 1c. psz=0 - * 1d. error.is_error(); details including exact location where parsing failed. - * 1e. parser reset to top level. - * 2. available input represents prefix of a possibly-valid expression - * 2a. expr=nullptr; - * 2b. consumed reads all available input - * 2c. psz reflects nesting level after reading available input. - * 2d. error.is_not_an_error() - * 3. available input completes at least one expression - * 3a. expr contains first completed top-level expression - * 3b. consumed reports portion of input up to end of expr - * 3c. psz=0 - * 3d. error.is_not_an_error() - * - * expr :: rp if non-null: the next expression from input - * consumed :: span extent of input read up to next Expression - * psz :: size_t parser stack size - * error :: reader_error error details on parsing failure - **/ - auto [expr, consumed, psz, error] = rdr.read_expr(input, eof); - - if (expr) { - /** configuration for pretty-printing **/ - ppconfig ppc; - ppstate_standalone pps(&cout, 0, &ppc); - - //pps.prettyn(expr); - - // TODO: - auto [ value, scm_error ] = this->vsm_.toplevel_eval(expr); - - if (scm_error.is_error()) { - /* print error */ - - cout << "scm error: " << scm_error.what() << endl; - cout << "top-level expression: " << expr << endl; - } else { - /* print value */ - - cout << "scm result:" << endl; - cout << value << endl; - //pps.pretty(value); - } - - } else if (error.is_error()) { - cout << "parsing error (detected in " << error.src_function() << "): " << endl << endl; - error.report(cout); - - /* discard stashed remainder of input line - * (for nicely-formatted errors) - */ - rdr.reset_to_idle_toplevel(); - break; - } - - input = input.after_prefix(consumed); - parser_stack_size = psz; - } - - /* here: input.empty() or error encountered */ - - cerr << endl; - } - - auto [expr, _1, _2, error] = rdr.read_expr(input, true /*eof*/); - - if (expr) { - ppconfig ppc; - ppstate_standalone pps(&cout, 0, &ppc); - - pps.prettyn>(rp(expr)); - } else if (error.is_error()) { - cout << "parsing error (detected in " << error.src_function() << "): " << endl; - error.report(cout); - } - - rx.history_save("repl_history.txt"); - } - - // ----- Schematika ----- - - Schematika::Schematika(const Config & cfg) : p_impl_{Impl::make(cfg)} - {} - - Schematika::~Schematika() - {} - - Schematika - Schematika::make(const Config & cfg) - { - return Schematika(cfg); - } - - void - Schematika::interactive_repl() - { - p_impl_->interactive_repl(); - } - } -} - -/* end Schematika.cpp */ diff --git a/.xo-interpreter/src/interpreter/VirtualSchematikaMachine.cpp b/.xo-interpreter/src/interpreter/VirtualSchematikaMachine.cpp deleted file mode 100644 index 25f620b0..00000000 --- a/.xo-interpreter/src/interpreter/VirtualSchematikaMachine.cpp +++ /dev/null @@ -1,865 +0,0 @@ -/** @file VirtualSchematikaMachine.cpp **/ - -#include "VirtualSchematikaMachine.hpp" -#include "VsmInstr.hpp" -#include "BuiltinPrimitives.hpp" -#include "ExpressionBoxed.hpp" -#include "xo/expression/Constant.hpp" -#include "xo/expression/PrimitiveExprInterface.hpp" -#include "xo/expression/DefineExpr.hpp" -#include "xo/expression/AssignExpr.hpp" -#include "xo/expression/Variable.hpp" -#include "xo/expression/IfExpr.hpp" -#include "xo/expression/Sequence.hpp" -#include "xo/expression/Apply.hpp" -#include "xo/object/Procedure.hpp" -#include "xo/object/Primitive.hpp" -#include "xo/object/Integer.hpp" -#include "xo/object/Boolean.hpp" -#include "xo/alloc/GC.hpp" - -/** continue after completing a VSM instruction; - * achieve by jumping to continuation. - **/ -#define VSM_CONTINUE() this->pc_ = this->cont_; return; - -/** report error and terminate VSM execution - **/ -#define VSM_ERROR(msg) report_error(msg); return; - - - -namespace xo { - using xo::gc::GC; - using xo::obj::Procedure; - using xo::obj::Integer; - using xo::obj::Boolean; - - namespace scm { - struct VsmOps { - /** halt virtual scheme machine. - * This will cause innermost run() to return to its caller - **/ - static VsmInstr halt_op; - - /** evaluate an expression. - * - opcode is Opcode::eval - * - expression in register @ref expr_ - **/ - static VsmInstr eval_op; - - /** assign variable after evaluating rhs of a define-expression or assign-expression - * - opcode is Opcode::complete_assign - * - top stack frame contains {lhs, cont} - **/ - static VsmInstr complete_assign_op; - - /** choose branch of if-expr after evaluating test condition. - * - opcode is Opcode::complete_ifexpr - * - top stack frame contains {ifexpr, cont} - **/ - static VsmInstr complete_ifexpr_op; - - /** proceed to next element of sequence-expr. - * - opcode is Opcode::complete_sequence - * - top stack frame contains {seq, next, cont} - */ - static VsmInstr complete_sequence_op; - - /** proceed to next argument in apply-expr - * - opcode is Opcode::eval_collect_args - * - top stack frame contains {apply, targetarg, cont} - */ - static VsmInstr complete_evalargs_op; - - /** call a procedure, where evaluated arguments (including target function) - * are in top stack frame. - * - opcode is Opcode::apply - * - top stack frame contains evaluated arguments. - **/ - static VsmInstr apply_op; - }; - - VsmInstr - VsmOps::halt_op{VsmInstr::Opcode::halt, "halt"}; - - VsmInstr - VsmOps::eval_op{VsmInstr::Opcode::eval, "eval"}; - - VsmInstr - VsmOps::complete_assign_op{VsmInstr::Opcode::complete_assign, "complete-assign"}; - - VsmInstr - VsmOps::complete_ifexpr_op{VsmInstr::Opcode::complete_ifexpr, "complete-ifexpr"}; - - VsmInstr - VsmOps::complete_sequence_op{VsmInstr::Opcode::complete_sequence, "complete-sequence"}; - - VsmInstr - VsmOps::complete_evalargs_op{VsmInstr::Opcode::complete_evalargs, "complete-evalargs"}; - - VsmInstr - VsmOps::apply_op{VsmInstr::Opcode::apply, "apply"}; - - // ----- VirtualSchematikaMachineFlyweight ----- - - VirtualSchematikaMachineFlyweight::VirtualSchematikaMachineFlyweight(gc::IAlloc * mm, - gp env, - log_level ll) : - object_mm_{mm}, - toplevel_env_{env}, - log_level_{ll} - { - } - - // ----- VirtualSchematikaMachine ----- - - VirtualSchematikaMachine::VirtualSchematikaMachine(gc::IAlloc * mm, - gp env, - log_level ll) : flyweight_{mm, env, ll} - { - scope log(XO_DEBUG(true), xtag("env", env), xtag("symtab", env->symtab())); - - this->env_ = env; - - // gc roots - gc::GC * gc = GC::from(mm); - - if (gc) { - assert((gc->gc_in_progress() == false) && "cannot add roots while GC running"); - - gc->add_gc_root_dwim(&env_); - gc->add_gc_root_dwim(&value_); - } else { - // Want to support VSM with arena-allocator-only; - // if only for unit testing. - } - - // TODO: install builtin primitives here - } - - VirtualSchematikaMachine::~VirtualSchematikaMachine() - { - gc::GC * gc = GC::from(flyweight_.object_mm_); - - if (gc) { - assert((gc->gc_in_progress() == false) && "cannot remove roots while GC running"); - - gc->remove_gc_root_dwim(&env_); - gc->remove_gc_root_dwim(&value_); - } else { - // nothing to do in arena-only mode - } - } - - std::pair, - SchematikaError> - VirtualSchematikaMachine::toplevel_eval(bp expr) - { - return this->eval(expr, this->env_); - } - - std::pair, - SchematikaError> - VirtualSchematikaMachine::eval(bp expr, gp env) - { - scope log(XO_DEBUG(true), xtag("env", env), xtag("symtab", env->symtab())); - - this->pc_ = &VsmOps::eval_op; - this->expr_ = expr.promote(); - this->env_ = env; - this->stack_ = nullptr; - this->value_ = nullptr; - this->error_ = SchematikaError(); - this->cont_ = &VsmOps::halt_op; - - this->run(); - - return std::make_pair(this->value_, this->error_); - } - - void - VirtualSchematikaMachine::run() - { - while(pc_) - this->execute_one(); - } - - void - VirtualSchematikaMachine::execute_one() - { - scope log(XO_DEBUG(true)); - log && log(xtag("pc", pc_), xtag("cont", cont_)); - log && log(xtag("stack", stack_)); - - using Opcode = VsmInstr::Opcode; - - switch (pc_->opcode()) { - - case Opcode::halt: - { - this->pc_ = nullptr; - this->cont_ = nullptr; - break; - } - - case Opcode::eval: - { - log && log("Opcode::eval"); - - /* generally speaking: opcode will be 1:1 with extypes */ - - switch (expr_->extype()) { - case exprtype::constant: - log && log("eval -> constant"); - this->eval_constant_op(); - break; - - case exprtype::primitive: - log && log("eval -> primitive"); - this->eval_primitive_op(); - break; - - case exprtype::define: - log && log("eval -> define"); - this->eval_define_op(); - break; - - case exprtype::assign: - log && log("eval -> assign"); - this->eval_assign_op(); - break; - - case exprtype::variable: - log && log("eval -> variable"); - this->eval_variable_op(); - break; - - case exprtype::ifexpr: - log && log("eval -> ifexpr"); - this->eval_ifexpr_op(); - break; - - case exprtype::sequence: - log && log("eval -> sequence"); - this->eval_sequence_op(); - break; - - case exprtype::apply: - log && log("eval -> apply"); - this->eval_apply_op(); - break; - - case exprtype::invalid: - - case exprtype::lambda: - case exprtype::convert: - case exprtype::n_expr: - this->pc_ = nullptr; - this->value_ = nullptr; - this->error_ = SchematikaError(tostr("execute_vsm: not implemented", - xtag("extype", expr_->extype()))); - this->cont_ = nullptr; - break; - } - } - break; - - case Opcode::complete_assign: - this->do_complete_assign_op(); - break; - - case Opcode::complete_ifexpr: - this->do_complete_ifexpr_op(); - break; - - case Opcode::complete_sequence: - this->do_complete_sequence_op(); - break; - - case Opcode::complete_evalargs: - this->do_complete_evalargs_op(); - break; - - case Opcode::apply: - this->apply_op(); - break; - - case Opcode::N_Opcode: - assert(false); - break; - } - } - - void - VirtualSchematikaMachine::report_error(const std::string & err) - { - /* error short-circuits vsm operation */ - - this->pc_ = nullptr; - this->value_ = nullptr; - this->error_ = SchematikaError(err); - this->cont_ = nullptr; - } - - void - VirtualSchematikaMachine::eval_constant_op() - { - using xo::scm::ConstantInterface; - - scope log(XO_DEBUG(true)); - - bp expr = ConstantInterface::from(expr_); - - assert(expr); - - this->value_ = flyweight_.object_converter_.tp_to_object(flyweight_.object_mm_, - expr->value_tp(), - false); - if (this->value_.ptr()) { - log && log("got object: ", xtag("value", value_)); - - VSM_CONTINUE(); - } else { - /* see ObjectConverter::ctor to add more builtin types - * - * generally conversion for a type Foo will appear in Foo.hpp - * see - * xo/object/Boolean.hpp - * xo/object/Integer.hpp - * xo/object/Float.hpp - * xo/object/String.hpp - */ - - VSM_ERROR(tostr("constant_op: unable to convert native value to object", - xtag("id", expr->value_tp().td()->id()), - xtag("short_name", expr->value_tp().td()->short_name()))); - } - } - - void - VirtualSchematikaMachine::eval_primitive_op() - { - using xo::obj::Primitive; - using xo::reflect::TaggedPtr; - - scope log(XO_DEBUG(true)); - - bp expr = PrimitiveExprInterface::from(expr_); - - const gp * slot = env_->lookup_slot(expr->name()); - - if (slot) { - this->value_ = *slot; - this->pc_ = cont_; - } else { - std::string err = tostr("no binding for primitive", xtag("name", expr->name())); - - this->value_ = nullptr; - this->error_ = SchematikaError(err); - - /* note: poor man's exception */ - this->pc_ = nullptr; - this->cont_ = nullptr; - } - } - - void - VirtualSchematikaMachine::eval_define_op() - { - using xo::scm::DefineExpr; - - scope log(XO_DEBUG(true)); - - auto mm = flyweight_.object_mm_; - - bp expr = DefineExpr::from(expr_); - - assert(expr); - assert(env_.get()); - - // note: expecting nested define to have expanded iteself into - // applying a lambda - - // note: establish lhs_var first, to allow for recursion, for example: - // def fact(n: i64) { if (n == 0) then 1; else n * fact(n-1); } - - /** remembers promised variable type **/ - this->env_->establish_var(expr->lhs_variable()); - - /** must promote rp -> gp **/ - gp lhs_0 = ExpressionBoxed::make(mm, expr->lhs_variable()); - - this->pc_ = &VsmOps::eval_op; - this->expr_ = expr->rhs(); - - /* when control arrives at .cont_, will have: - * .value_ -> result of evaluating expr->rhs() - */ - this->stack_ = VsmStackFrame::push1(mm, this->stack_, lhs_0, cont_); - - /* .stack_: - * frame - * [0] = lhs_0 (boxed lhs Variable) - * .. - */ - - this->cont_ = &VsmOps::complete_assign_op; - } - - void - VirtualSchematikaMachine::eval_assign_op() - { - using xo::scm::AssignExpr; - - scope log(XO_DEBUG(true)); - - auto mm = flyweight_.object_mm_; - - bp assign = AssignExpr::from(expr_); - - assert(assign.get()); - assert(env_.get()); - - assert(assign->lhs().get()); - assert(assign->rhs().get()); - - /* verify slot exists, before we evaluate rhs */ - gp * slot = env_->lookup_slot(assign->lhs()->name()); - - if (slot) { - /** must promote rp -> gp **/ - gp lhs = ExpressionBoxed::make(mm, assign->lhs()); - - this->pc_ = &VsmOps::eval_op; - this->expr_ = assign->rhs(); - - /* when control arrives at .cont_, will have: - * .value_ -> result of evaluating assign->rhs() - */ - this->stack_ = VsmStackFrame::push1(mm, this->stack_, lhs, cont_); - - /* .stack_: - * frame - * [0] = lhs (boxed lhs Variable) - * .. - */ - - this->cont_ = &VsmOps::complete_assign_op; - } else { - std::string err = tostr("no binding for lhs of assignment", xtag("name", assign->lhs()->name())); - - this->value_ = nullptr; - this->error_ = SchematikaError(err); - - /* note: poor man's exception */ - this->pc_ = nullptr; - this->cont_ = nullptr; - } - } - - void - VirtualSchematikaMachine::do_complete_assign_op() - { - scope log(XO_DEBUG(true)); - - /* - * - value: contains result of evaluating rhs of define - * - stack: top frame has 1 slot, holds variable to receive assignment - */ - assert(value_.get()); - assert(stack_.get()); - assert(env_.get()); - - gp sp0 = this->stack_; - - bp var = Variable::from(ExpressionBoxed::from((*sp0)[0])->contents()); - - assert(var.get()); - - gp * slot = this->env_->establish_var(var); - assert(slot); - - *slot = this->value_; - - //this->value_ = this->value_; // preserve value from rhs of defexpr - - this->stack_ = sp0->parent(); - this->pc_ = this->cont_ = sp0->continuation(); - } - - void - VirtualSchematikaMachine::eval_variable_op() - { - using xo::scm::Variable; - - scope log(XO_DEBUG(true)); - - bp var = Variable::from(expr_); - - assert(var.get()); - assert(env_.get()); - - const gp * slot = env_->lookup_slot(var->name()); - - if (slot) { - this->value_ = *slot; - this->pc_ = cont_; - } else { - /* Unknown variable error will often be recognized in expression parser, - * in such cases this path won't be used. - * - * In interactive environment will need some kind of support for modifying - * code (e.g. replacing top-level functions/variables), and in particular, - * replacements may have different type signature. - * It's possible that allowing for such replacements winds up giving up - * typesafety guarantees. In that case this path may get activated after - * all. - */ - - std::string err = tostr("no binding for variable", xtag("name", var->name())); - - this->value_ = nullptr; - this->error_ = SchematikaError(err); - - /* note: poor man's exception */ - this->pc_ = nullptr; - this->cont_ = nullptr; - } - } - - void - VirtualSchematikaMachine::eval_ifexpr_op() - { - using xo::scm::IfExpr; - - scope log(XO_DEBUG(true)); - - gc::IAlloc * mm = flyweight_.object_mm_; - - /** must promote bp -> gp **/ - gp ifexpr_boxed = ExpressionBoxed::make(mm, expr_); - bp ifexpr = IfExpr::from(expr_); - - assert(ifexpr.get()); - assert(env_.get()); - - this->pc_ = &VsmOps::eval_op; - this->expr_ = ifexpr->test(); - - - /* when control arrives at .cont_ will have: - * .value_ -> result of evaluating ifexpr->test() - */ - this->stack_ = VsmStackFrame::push1(mm, this->stack_, ifexpr_boxed, cont_); - - /* .stack_: - * frame - * [0] = ifexpr (boxed expression) - */ - - this->cont_ = &VsmOps::complete_ifexpr_op; - } - - void - VirtualSchematikaMachine::do_complete_ifexpr_op() - { - using xo::scm::IfExpr; - - scope log(XO_DEBUG(true)); - - /* - * - value: contains result of evaluating test condition of if-expr - * - stack: top frame has 1 slot, holds (boxed) if-expr itself - */ - assert(value_.get()); - assert(stack_.get()); - assert(env_.get()); - - gp test_value = gp::from(value_); - - if (test_value.get()) { - gp sp0 = this->stack_; - - bp ifexpr = IfExpr::from(ExpressionBoxed::from((*sp0)[0])->contents()); - - assert(ifexpr.get()); - - this->pc_ = &VsmOps::eval_op; - - if (test_value->value()) { - this->expr_ = ifexpr->when_true(); - } else { - if (ifexpr->when_false()) { - this->expr_ = ifexpr->when_false(); - } else { - /* 1-sided if-expr; evaluate to false */ - this->expr_ = Constant::make(false); - } - } - - this->stack_ = sp0->parent(); - this->cont_ = sp0->continuation(); - } else { - std::string err = tostr("expect boolean value for result of if-expr test", xtag("value", test_value)); - - this->value_ = nullptr; - this->error_ = SchematikaError(err); - - /* note: poor man's exception */ - this->pc_ = nullptr; - this->cont_ = nullptr; - } - } - - void - VirtualSchematikaMachine::eval_sequence_op() - { - using xo::scm::Sequence; - - scope log(XO_DEBUG(true)); - - gc::IAlloc * mm = flyweight_.object_mm_; - - /** must promote bp -> gp **/ - gp seq_boxed = ExpressionBoxed::make(mm, expr_); - bp seq = Sequence::from(expr_); - - assert(seq.get()); - assert(env_.get()); - - this->pc_ = &VsmOps::eval_op; - - if (seq->size() == 0) { - /* for 0-size sequence, invent an expression */ - this->expr_ = Constant::make(false); - } else { - this->expr_ = (*seq)[0]; - } - - if (seq->size() > 1) { - /* remainder */ - - gp next = Integer::make(mm, 1); - - /* when control arrives at .cont_ will have: - * .value_ -> result of evaluating last expr in seq - */ - this->stack_ = VsmStackFrame::push2(mm, stack_, seq_boxed, next, cont_); - - /* .stack_: - * frame - * [0] = seq (boxed sequence) - * [1] = next (index of next seq member to evaluate) - * .. - */ - - this->cont_ = &VsmOps::complete_sequence_op; - } else { - /* sequence completes when expr_ evaluated - * -> proceed with o.g. cont_ - */ - } - } - - void - VirtualSchematikaMachine::do_complete_sequence_op() - { - using xo::scm::Sequence; - - scope log(XO_DEBUG(true)); - - /* - stack: top frame has 2 slots: - * [0] : seq (boxed Sequence) - * [1] : next (index of next seq element to eval - */ - - assert(value_.get()); - assert(stack_.get()); - - gp sp0 = this->stack_; - - assert(sp0->size() == 2); - - bp seq = Sequence::from(ExpressionBoxed::from((*sp0)[0])->contents()); - gp next_obj = Integer::from((*sp0)[1]); - size_t i_next = next_obj->value(); - - assert(i_next < seq->size()); - - this->pc_ = &VsmOps::eval_op; - this->expr_ = (*seq)[i_next]; - - if (i_next + 1 == seq->size()) { - /* last member of sequence -> tail call optimization */ - this->stack_ = sp0->parent(); - this->cont_ = sp0->continuation(); - } else { - /* we can modify next_obj in place, - * since it's unique to frame sp0 - */ - next_obj->assign_value(i_next + 1); - this->cont_ = &VsmOps::complete_sequence_op; - } - } - - void - VirtualSchematikaMachine::eval_apply_op() - { - /* strategy: - * 1. calling sequence will involve two stack frames. - * 1a. the outer frame will hold 'final evaluated arguments' - * to the called function. When control transfers to that - * function, this frame will be at the top of stack_ - * 1b. innert frame will be used by eval_apply_op() and - * helper do_eval_collect_args() to evaluate function - * arguments, and populate the outer frame. - */ - - using xo::scm::Apply; - - scope log(XO_DEBUG(true)); - - gc::IAlloc * mm = flyweight_.object_mm_; - - /** must promote bp -> gp **/ - gp apply_boxed = ExpressionBoxed::make(mm, expr_); - bp apply = Apply::from(expr_); - - assert(apply.get()); - - size_t n = apply->n_arg() + 1; - - /* reminder: argument 0 refers to the function being called */ - gp targetarg = Integer::make(mm, 0); - - /* outer frame */ - gp argstack = VsmStackFrame::make(mm, stack_, n, cont_); - - /* scratch frame during call sequence. - * probably collect->cont_ will not be used? - */ - gp collect = VsmStackFrame::push2(mm, - argstack, - apply_boxed, - targetarg, - &VsmOps::complete_evalargs_op); - - this->pc_ = &VsmOps::eval_op; - this->expr_ = apply->fn(); - this->stack_ = collect; - this->cont_ = &VsmOps::complete_evalargs_op; - } - - void - VirtualSchematikaMachine::do_complete_evalargs_op() - { - using xo::scm::Apply; - - scope log(XO_DEBUG(true)); - - /* - stack: top frame has 2 slots - * [0] : apply (boxed Apply) - * [1] : targetarg index of next evaluated argument to deliver. - * (to corresponding slot in 2nd frame) - * - 2nd frame has n slots, where n = #of arguments at this site - * [0] : actual #0 - * .. - * [targetarg-1] : actual #{targetarg-1} - */ - - assert(value_.get()); - assert(stack_.get()); - - gp sp0 = this->stack_; - - assert(sp0.get()); - assert(sp0->size() == 2); - - bp apply = Apply::from(ExpressionBoxed::from((*sp0)[0])->contents()); - assert(apply.get()); - gp targetarg_obj = Integer::from((*stack_)[1]); - size_t targetarg = targetarg_obj->value(); - - /* note: apply->n_arg() doesn't count function itself */ - assert(targetarg < apply->n_arg() + 1); - - gp argstack = sp0->parent(); - - assert(argstack.get()); - - /* storing actual parameter in its correct position in call stackframe */ - (*argstack)[targetarg] = value_; - - ++targetarg; - - if (targetarg < apply->n_arg() + 1) { - /* - * arguments 0 .. #targetarg-1 already present in argstack - * arguments #targetarg .. #n still need to be evaluated - */ - - /* ok to update in place, since Integer in sp0 is unique */ - targetarg_obj->assign_value(targetarg); - - rp targetexpr = apply->lookup_arg(targetarg - 1); - - this->pc_ = &VsmOps::eval_op; - this->expr_ = targetexpr; - assert(this->stack_.get() == sp0.get()); - this->cont_ = &VsmOps::complete_evalargs_op; - } else { - /* all args evaluated: proceed to invoke evaluated function */ - - this->pc_ = &VsmOps::apply_op; - this->expr_ = nullptr; - this->stack_ = argstack; - /* unnecessary - will actually be set by apply_op() */ - this->cont_ = argstack->continuation(); - } - } - - void - VirtualSchematikaMachine::apply_op() - { - scope log(XO_DEBUG(true)); - - auto mm = flyweight_.object_mm_; - - // NOTE: Closures will have special handling. - // Could alternatively forward the whole problem - // (along with VSM state) to procedure implementation - - /* stack: top frame has n slots for procedure with n canonical args */ - - gp sp0 = stack_; - - assert(sp0->size() > 0); - - gp fn = Procedure::from((*sp0)[0]); - - if (fn->n_args() + 1 != sp0->size()) { - throw std::runtime_error(tostr("VirtualSchematikaMachine::apply_op:" - " argument mismatch in apply" - ": k arguments supplied where n expected", - xtag("k", sp0->size() - 1), - xtag("n", fn->n_args()))); - } - - /* todo: - * check function signature? - * should have been guaranteed by expression parser, - * but complications in interactive session when variables redefined. - */ - - gp retval = fn->apply_nocheck(mm, sp0->argv()); - - this->pc_ = this->cont_; - this->stack_ = sp0->parent(); - this->value_ = retval; - } - - } /*namespace scm*/ -} /*namespace xo*/ - -/* end VirtualSchematikaMachine.cpp */ diff --git a/.xo-interpreter/src/interpreter/VsmInstr.cpp b/.xo-interpreter/src/interpreter/VsmInstr.cpp deleted file mode 100644 index 3ca138d9..00000000 --- a/.xo-interpreter/src/interpreter/VsmInstr.cpp +++ /dev/null @@ -1,16 +0,0 @@ -/** @file VsmInstr.cpp - * - * @author Roland Conybeare, Nov 2025 - **/ - -#include "VsmInstr.hpp" - -namespace xo { - namespace scm { - VsmInstr::VsmInstr(Opcode opcode, - std::string_view name) : opcode_{opcode}, name_{name} - {} - } -} - -/* end VsmInstr.cpp */ diff --git a/.xo-interpreter/src/interpreter/VsmStackFrame.cpp b/.xo-interpreter/src/interpreter/VsmStackFrame.cpp deleted file mode 100644 index 9bca575e..00000000 --- a/.xo-interpreter/src/interpreter/VsmStackFrame.cpp +++ /dev/null @@ -1,177 +0,0 @@ -/** @file VsmStackFrame.cpp - * - * @author Roland Conybeare, Nov 2025 - **/ - -#include "VsmStackFrame.hpp" -#include "xo/reflect/Reflect.hpp" -#include "xo/reflect/StructReflector.hpp" - -namespace xo { - using xo::reflect::Reflect; - using xo::reflect::StructReflector; - using xo::reflect::TypeDescrW; - using xo::reflect::TaggedPtr; - using xo::reflect::TypeDescrExtra; - using xo::reflect::EstablishTypeDescr; - using xo::reflect::StlVectorTdx; - - namespace scm { - namespace { - // TOOD: move into CVector - - std::size_t - slot_array_size(std::size_t n) { - return n * sizeof(gp); - } - } - - VsmStackFrame::VsmStackFrame(gc::IAlloc * mm, - gp p, - std::size_t n, - const VsmInstr * cont) : parent_{p}, - slot_v_{mm, n}, - cont_{cont} - {} - - gp - VsmStackFrame::make(gc::IAlloc * mm, - gp p, - std::size_t n, - const VsmInstr * cont) - { - gp retval = new (MMPtr(mm)) VsmStackFrame(mm, p, n, cont); - - for (std::size_t i = 0; i < n; ++i) - (*retval)[i] = nullptr; - - return retval; - } - - gp - VsmStackFrame::push1(gc::IAlloc * mm, - gp p, - gp s0, - const VsmInstr * cont) - { - gp retval = new (MMPtr(mm)) VsmStackFrame(mm, p, 1, cont); - - (*retval)[0] = s0; - - return retval; - } - - gp - VsmStackFrame::push2(gc::IAlloc * mm, - gp p, - gp s0, - gp s1, - const VsmInstr * cont) - { - gp retval = new (MMPtr(mm)) VsmStackFrame(mm, p, 2, cont); - - (*retval)[0] = s0; - (*retval)[1] = s1; - - return retval; - } - - TaggedPtr - VsmStackFrame::self_tp() const - { - return Reflect::make_tp(const_cast(this)); - } - - void - VsmStackFrame::display(std::ostream & os) const - { - os << ""; - } - - std::size_t - VsmStackFrame::_shallow_size() const - { - std::size_t retval = sizeof(VsmStackFrame); - - retval += gc::IAlloc::with_padding(slot_array_size(slot_v_.size())); - - return retval; - } - - Object * - VsmStackFrame::_shallow_copy(gc::IAlloc * mm) const - { - Cpof cpof(mm, this); - - size_t n = this->size(); - - VsmStackFrame * copy = new (cpof) VsmStackFrame(cpof.mm_, parent_, n, cont_); - - void * v_dest = copy->slot_v_.v_; - - if (slot_v_.v_) { - ::memcpy(v_dest, slot_v_.v_, slot_array_size(n)); - } - -#ifdef OBSOLETE - for (size_t i = 0, n = n_slot_; i < n; ++i) { - copy->v_[i] = v_[i]; - } -#endif - return copy; - } - - std::size_t - VsmStackFrame::_forward_children(gc::IAlloc * gc) - { - Object::_forward_inplace(parent_, gc); - - for (std::size_t i = 0, n = slot_v_.size(); i < n; ++i) { - Object::_forward_inplace((*this)[i], gc); - } - - return _shallow_size(); - } - - void - VsmStackFrame::reflect_self() - { - StructReflector sr; - - if (sr.is_incomplete() ) { - /* reflect CVector>. - * duplicates similar code in LocalEnv::reflect_self() - */ - using VectorType = obj::CVector>; - - /* custom reflection for array of Object pointers. - * Can use StlVectorTdx here, treating CVector as a vector - * via .size() and .operator[] members - */ - std::unique_ptr tdx1 - = std::make_unique>(); - TypeDescrW td1 - = EstablishTypeDescr::establish(); - td1->assign_tdextra(Reflect::get_final_invoker(), - std::move(tdx1)); - - REFLECT_MEMBER(sr, parent); - REFLECT_MEMBER(sr, slot_v); - } - } - } /*namespace scm*/ -} /*namespace xo*/ - -/* end VsmStackFrame.cpp */ diff --git a/.xo-interpreter/src/interpreter/init_interpreter.cpp b/.xo-interpreter/src/interpreter/init_interpreter.cpp deleted file mode 100644 index eaa0bffe..00000000 --- a/.xo-interpreter/src/interpreter/init_interpreter.cpp +++ /dev/null @@ -1,27 +0,0 @@ -/** @file init_interpreter.cpp - * - * author: Roland Conybeare, Nov 2025 - */ - -#include "init_interpreter.hpp" -#include "LocalEnv.hpp" -#include "xo/subsys/Subsystem.hpp" - -namespace xo { - using xo::scm::LocalEnv; - - void - InitSubsys::init() - { - LocalEnv::reflect_self(); - } - - InitEvidence - InitSubsys::require() - { - return Subsystem::provide("interpreter", &init); - } - -} /*namespace xo*/ - -/* end init_interpreter.cpp */ diff --git a/.xo-interpreter/utest/CMakeLists.txt b/.xo-interpreter/utest/CMakeLists.txt deleted file mode 100644 index 01cef051..00000000 --- a/.xo-interpreter/utest/CMakeLists.txt +++ /dev/null @@ -1,12 +0,0 @@ -# build unittest interpreter/utest - -set(UTEST_EXE utest.interpreter) -set(UTEST_SRCS - interpreter_utest_main.cpp - LocalEnv.test.cpp -) - -xo_add_utest_executable(${UTEST_EXE} ${UTEST_SRCS}) -xo_self_dependency(${UTEST_EXE} xo_interpreter) -xo_dependency(${UTEST_EXE} xo_object) -xo_external_target_dependency(${UTEST_EXE} Catch2 Catch2::Catch2) diff --git a/.xo-interpreter/utest/LocalEnv.test.cpp b/.xo-interpreter/utest/LocalEnv.test.cpp deleted file mode 100644 index 084d5a4d..00000000 --- a/.xo-interpreter/utest/LocalEnv.test.cpp +++ /dev/null @@ -1,134 +0,0 @@ -/** @file LocalEnv.test.cpp **/ - -#include "xo/interpreter/init_interpreter.hpp" -#include "xo/interpreter/LocalEnv.hpp" -#include "xo/object/Integer.hpp" -#include "xo/alloc/GC.hpp" -#include -#include -#include - -namespace xo { - using xo::scm::LocalEnv; - using xo::obj::Integer; - using xo::gc::GC; - using xo::gc::ArenaAlloc; - using xo::gc::generation; - using xo::gc::generation_result; - using xo::reflect::TaggedPtr; - - namespace ut { - static InitEvidence s_init = (InitSubsys::require()); - - namespace { - struct Testcase_LocalEnv { - Testcase_LocalEnv(const std::vector & contents) : contents_{contents} {} - - /* build xo::obj::Integer for each contents_[i], store in F[i] for new LocalEnv F */ - std::vector contents_; - }; - - std::vector - s_testcase_v = { - Testcase_LocalEnv({}), - Testcase_LocalEnv({}), - Testcase_LocalEnv({111}), - Testcase_LocalEnv({111, 222}), - }; - } - - TEST_CASE("LocalEnv", "[LocalEnv][interpreter]") - { - Subsystem::initialize_all(); - - constexpr bool c_debug_flag = false; - - for (std::size_t i_tc = 0, n_tc = s_testcase_v.size(); i_tc < n_tc; ++i_tc) { - scope log(XO_DEBUG(c_debug_flag), xtag("test", "LocalEnv2"), xtag("i_tc", i_tc)); - - const Testcase_LocalEnv & tc = s_testcase_v[i_tc]; - - up alloc = ArenaAlloc::make("utest", 16384, c_debug_flag); - REQUIRE(alloc.get()); - Object::mm = alloc.get(); - - std::size_t n = tc.contents_.size(); - gp frame = LocalEnv::make(alloc.get(), nullptr /*parent*/, nullptr /*symtab*/, n); - - TaggedPtr tp = frame->self_tp(); - - REQUIRE(tp.is_struct()); - } - } - - TEST_CASE("LocalEnv2", "[LocalEnv][gc][interpreter]") - { - Subsystem::initialize_all(); - - constexpr bool c_debug_flag = false; - - try { - for (std::size_t i_tc = 0, n_tc = s_testcase_v.size(); i_tc < n_tc; ++i_tc) { - scope log(XO_DEBUG(c_debug_flag), xtag("test", "LocalEnv2"), xtag("i_tc", i_tc)); - - const Testcase_LocalEnv & tc = s_testcase_v[i_tc]; - - up gc = GC::make( - {.initial_nursery_z_ = 16384, - .initial_tenured_z_ = 32768, - .incr_gc_threshold_ = 4096, - .full_gc_threshold_ = 4096, - .object_stats_flag_ = true, - .debug_flag_ = c_debug_flag, - }); - - REQUIRE(gc.get()); - - /* use gc for all Object allocs */ - GC * mm = gc.get(); - Object::mm = mm; - - std::size_t n = tc.contents_.size(); - - gp x = Integer::make(gc.get(), 42); - gc->add_gc_root(reinterpret_cast(&x)); - REQUIRE(gc->tospace_generation_of(x.ptr()) == generation_result::nursery); - - gp frame = LocalEnv::make(gc.get(), nullptr /*parent*/, nullptr /*symtab*/, n); - LocalEnv ** frame_pp = frame.ptr_address(); - gc->add_gc_root(reinterpret_cast(frame_pp)); - - /* verifying allocated in N1 */ - REQUIRE(gc->tospace_generation_of(frame.ptr()) == generation_result::nursery); - - for (std::size_t i = 0; i < n; ++i) - (*frame)[i] = Integer::make(mm, tc.contents_.at(i)); - - std::size_t expected_alloc_z = frame->_shallow_size(); - REQUIRE(expected_alloc_z >= sizeof(LocalEnv) + n * sizeof(gp)); - - gc->request_gc(generation::nursery); // <<<<<<<<< GC here <<<<<<<<< - - REQUIRE(gc->native_gc_statistics().gen_v_[gen2int(generation::nursery)].n_gc_ == 1); - REQUIRE(gc->native_gc_statistics().gen_v_[gen2int(generation::tenured)].n_gc_ == 0); - - /* verify Integer x preserved across gc */ - REQUIRE(gc->tospace_generation_of(x.ptr()) == generation_result::nursery); - - /* verify LocalEnv preserved across gc */ - REQUIRE(gc->tospace_generation_of(frame.ptr()) == generation_result::nursery); - REQUIRE(frame->size() == n); - for (std::size_t i = 0; i < n; ++i) { - //REQUIRE(Integer::from(frame->lookup(i)).ptr()); - //REQUIRE(Integer::from(frame->lookup(i))->value() == tc.contents_.at(i)); - } - } - } catch (std::exception & ex) { - std::cerr << "exception: " << ex.what() << std::endl; - REQUIRE(false); - } - } - } -} - -/* end LocalEnv.test.cpp */ diff --git a/.xo-interpreter/utest/interpreter_utest_main.cpp b/.xo-interpreter/utest/interpreter_utest_main.cpp deleted file mode 100644 index e385f9b4..00000000 --- a/.xo-interpreter/utest/interpreter_utest_main.cpp +++ /dev/null @@ -1,6 +0,0 @@ -/** @file interpreter_utest_main.cpp **/ - -#define CATCH_CONFIG_MAIN -#include "catch2/catch.hpp" - -/* end interpreter_utest_main.cpp */