diff --git a/.github/workflows/premerge.yml b/.github/workflows/premerge.yml index 3a256729..2c2b46fc 100644 --- a/.github/workflows/premerge.yml +++ b/.github/workflows/premerge.yml @@ -49,6 +49,11 @@ jobs: with: create-symlink: true + - name: Upgrade CMake + run: | + sudo apt-get purge cmake + sudo snap install cmake --classic + - name: Configure CMake run: cmake --preset ${{env.CMAKE_PRESET}} diff --git a/CLAUDE.md b/CLAUDE.md index 2a8a229f..26eb5c12 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -9,8 +9,9 @@ This is an experimental Python 3.9-compatible interpreter implementation in C++. ## Build System ### Prerequisites -- CMake 3.25+ -- C++23 compiler +- CMake 3.30+ (`CMAKE_EXPERIMENTAL_CXX_IMPORT_STD`, used for `import std`) +- A C++26 compiler supporting C++20 named modules and `import std` + (built and tested with GCC 16) - LLVM 23+ with MLIR (required for MLIR backend) - GMP (GNU Multiple Precision library) - ICU (International Components for Unicode) diff --git a/CMakeLists.txt b/CMakeLists.txt index cc8a01c3..6b6f7e74 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,15 +1,29 @@ -cmake_minimum_required(VERSION 3.25) +cmake_minimum_required(VERSION 3.30) include(FetchContent) include(ExternalProject) include(CheckCXXSourceCompiles) +set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD "f35a9ac6-8463-4d38-8eec-5d6008153e7d") + project(python++) set(CMAKE_CXX_STANDARD 26) +set(CMAKE_CXX_SCAN_FOR_MODULES OFF) +set(CMAKE_CXX_STANDARD_REQUIRED ON) include(cmake/CPM.cmake) -CPMAddPackage("gh:gabime/spdlog@1.8.5") +# spdlog 1.11+ can format through std::format instead of its bundled fmt. +# SPDLOG_USE_STD_FORMAT keeps fmt out of the build entirely, which matters for +# modules: spdlog/fmt/fmt.h drags 231 libstdc++ headers, and anything reaching a +# module's global module fragment lands in its BMI and then collides with the +# same headers #included by consumers. +CPMAddPackage( + NAME spdlog + GITHUB_REPOSITORY gabime/spdlog + VERSION 1.15.3 + OPTIONS "SPDLOG_USE_STD_FORMAT ON" "SPDLOG_BUILD_PIC ON" +) CPMAddPackage("gh:google/googletest@1.18.0") CPMAddPackage("gh:jarro2783/cxxopts@3.3.1") CPMAddPackage("gh:Tessil/ordered-map@1.2.0") diff --git a/cmake/PythonCppFlags.cmake b/cmake/PythonCppFlags.cmake index 1a905b8f..05bbecf2 100644 --- a/cmake/PythonCppFlags.cmake +++ b/cmake/PythonCppFlags.cmake @@ -1,4 +1,5 @@ -# Helper for giving every first-party target the same compiler flags. +# Helper for giving every first-party target the same compiler flags and the +# same C++ module configuration. # # The flags come from the external `project_options` package (added with CPM in # the top-level CMakeLists.txt), which exposes them as two INTERFACE targets: @@ -16,6 +17,19 @@ # not the usage requirements of libraries linked afterwards. Linking the flags # to `` alone would therefore silently compile nothing with them, so this # always covers the `obj.` twin as well. +# +# The same `obj.` split applies to C++ module settings, and there it is +# easier to miss: `CXX_SCAN_FOR_MODULES` set on `` does not reach the +# object library that actually compiles the sources, so those sources are built +# by CMake's "unscanned" rule with no `-fmodule-mapper`. A TU that imports +# `py.runtime` then fails with either "'import' does not name a type" or, worse, +# a fallback lookup in `gcm.cache/`. Setting the properties on both twins is +# what makes `import py.runtime;` work inside the MLIR layer. +# +# Note: do NOT add `-fmodules` here. CMake supplies `-fmodules-ts` together with +# `-fmodule-mapper=` on its scanned compile rules; adding the flag by hand also +# applies it to unscanned targets, which turns a clear diagnostic into a +# confusing module-not-found error. include_guard(GLOBAL) @@ -28,8 +42,26 @@ function(python_cpp_link_project_options) get_target_property(type ${name} TYPE) if(type STREQUAL "INTERFACE_LIBRARY") target_link_libraries(${name} INTERFACE project_options project_warnings) - else() - target_link_libraries(${name} PRIVATE project_options project_warnings) + continue() + endif() + + target_link_libraries(${name} PRIVATE project_options project_warnings) + + # Everything first-party either provides or consumes `py.runtime`, so + # scan it all. Scanning costs ~0.16s per TU (a preprocess-only pass) and + # removes a whole class of "this target cannot see the module" failures. + set_target_properties(${name} PROPERTIES CXX_SCAN_FOR_MODULES ON + CXX_MODULE_STD ON) + + # Module imports resolve through link dependencies, so every consumer + # needs a path to python-runtime - the sole provider of `py.runtime`. + # It is linked directly rather than via python-cpp because python-cpp and + # python-mlir are mutually dependent: a module provider reached only + # through a link cycle cannot be ordered before its consumers, and they + # compile with an empty module map. python-runtime itself sits below that + # cycle, so linking it here is always acyclic. + if(TARGET python-runtime AND NOT ${target} STREQUAL "python-runtime") + target_link_libraries(${name} PRIVATE python-runtime) endif() endforeach() endforeach() diff --git a/integration/program.cpp b/integration/program.cpp index 36517a06..74674348 100644 --- a/integration/program.cpp +++ b/integration/program.cpp @@ -1,19 +1,17 @@ -#include "executable/Program.hpp" -#include "executable/bytecode/Bytecode.hpp" -#include "interpreter/Interpreter.hpp" -#include "parser/Parser.hpp" -#include "runtime/PyDict.hpp" -#include "runtime/PyFrame.hpp" -#include "runtime/PyInteger.hpp" -#include "runtime/PyList.hpp" -#include "runtime/PyNumber.hpp" -#include "runtime/PyObject.hpp" -#include "runtime/PyString.hpp" -#include "runtime/PyTuple.hpp" -#include "runtime/types/builtin.hpp" -#include "vm/VM.hpp" +#include "core.hpp" +#include "executable/common.hpp" #include "gtest/gtest.h" +#include +#include + +#include + +import py.ast; +import py.types; +import py.lexer; +import py.runtime; +import std; using namespace py; diff --git a/integration/tests/slots_uninitialised.py b/integration/tests/slots_uninitialised.py new file mode 100644 index 00000000..4fa9c06e --- /dev/null +++ b/integration/tests/slots_uninitialised.py @@ -0,0 +1,59 @@ +# An unset __slots__ entry must read as unset, however the slot storage was recycled. +# +# The storage lives in extra bytes past the object, and both the GC and the member +# accessor test each entry against null. Slab memory is poisoned rather than zeroed, +# so if the allocator does not clear those bytes an unset slot reads back as a +# non-null garbage pointer: the accessor returns it instead of raising AttributeError, +# and the GC dereferences it. + + +class C: + __slots__ = ("a", "b", "c") + + +def unset_raises(obj, name): + try: + getattr(obj, name) + except AttributeError: + return True + else: + return False + + +c = C() +c.a = 1 +assert c.a == 1 +assert unset_raises(c, "b"), "unset slot 'b' should raise AttributeError" +assert unset_raises(c, "c"), "unset slot 'c' should raise AttributeError" + +# Churn so that later instances land on slots that were freed and poisoned. +for i in range(2000): + x = C() + x.a = i + x.b = i + x.c = i + +for i in range(2000): + y = C() + y.a = i + assert y.a == i + assert unset_raises(y, "b"), "recycled slot 'b' should still read as unset" + assert unset_raises(y, "c"), "recycled slot 'c' should still read as unset" + +# Slots that are set must survive a collection with their values intact. The list is a +# heap object reachable only through the slot, so the GC has to trace the slot correctly. +kept = [] +for i in range(500): + z = C() + z.a = i + z.b = [i, i + 1] + kept.append(z) + +i = 0 +for z in kept: + assert z.a == i + assert z.b == [i, i + 1] + assert unset_raises(z, "c") + i += 1 + +print("slots_uninitialised: ok") diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7598e9ed..30a2f66e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,12 +1,108 @@ set(AST_SOURCE_FILES # cmake-format: sortable - ast/AST.cpp ast/ASTArena.cpp) + core.cpp memory/allocate.cpp) set(BYTECODE_SOURCE_FILES # cmake-format: sortable - executable/bytecode/Bytecode.cpp + executable/bytecode/Bytecode.cpp) + +set(EXECUTABLE_SOURCE_FILES # cmake-format: sortable + executable/Program.cpp) + +set(LEXER_SOURCE_FILES "") + +set(LLVM_BACKEND_FILES # cmake-format: sortable + executable/llvm/LLVMGenerator.cpp executable/llvm/LLVMProgram.cpp) + +set(INTERPRETER_SOURCE_FILES # cmake-format: sortable + interpreter/Interpreter.cpp) + +set(MEMORY_SOURCE_FILES # cmake-format: sortable + memory/GarbageCollector.cpp memory/Heap.cpp) + +set(PARSER_SOURCE_FILES "") + +# The Python standard library implemented in C++, plus the runtime types that are +# not `py.runtime` partitions yet. These are ordinary consumers - they import the +# module but define nothing belonging to it - so they build in python-cpp. +set(STDLIB_SOURCE_FILES + # cmake-format: sortable + runtime/AssertionError.cpp + runtime/AttributeError.cpp + runtime/Exception.cpp + runtime/Import.cpp + runtime/ImportError.cpp + runtime/IndexError.cpp + runtime/KeyError.cpp + runtime/LookupError.cpp + runtime/MemoryError.cpp + runtime/ModuleNotFoundError.cpp + runtime/NameError.cpp + runtime/NotImplemented.cpp + runtime/NotImplementedError.cpp + runtime/OSError.cpp + runtime/PyBool.cpp + runtime/PyBoundMethod.cpp + runtime/PyBuiltInMethod.cpp + runtime/PyByteArray.cpp + runtime/PyBytes.cpp + runtime/PyClassMethod.cpp + runtime/PyClassMethodDescriptor.cpp + runtime/PyComplex.cpp + runtime/PyEllipsis.cpp + runtime/PyEnumerate.cpp + runtime/PyGenericAlias.cpp + runtime/PyGetSetDescriptor.cpp + runtime/PyIterator.cpp + runtime/PyLLVMFunction.cpp + runtime/PyMap.cpp + runtime/PyMappingProxy.cpp + runtime/PyMemberDescriptor.cpp + runtime/PyMemoryView.cpp + runtime/PyMethodDescriptor.cpp + runtime/PyModule.cpp + runtime/PyNamespace.cpp + runtime/PyProperty.cpp + runtime/PyRange.cpp + runtime/PyReversed.cpp + runtime/PySet.cpp + runtime/PySlice.cpp + runtime/PySlotWrapper.cpp + runtime/PyStaticMethod.cpp + runtime/PySuper.cpp + runtime/PyZip.cpp + runtime/RuntimeError.cpp + runtime/SourceManager.cpp + runtime/StopIteration.cpp + runtime/SyntaxError.cpp + runtime/TypeError.cpp + runtime/UnboundLocalError.cpp + runtime/ValueError.cpp + runtime/warnings/DeprecationWarning.cpp + runtime/warnings/ImportWarning.cpp + runtime/warnings/PendingDeprecationWarning.cpp + runtime/warnings/ResourceWarning.cpp) + +# Translation units belonging to the `py.runtime` module: the .cpp counterparts of +# the interface partitions listed in python-runtime's FILE_SET. Each defines members +# of a module-owned class, so it must be an implementation unit (`module py.runtime;`) +# compiled in python-runtime - a definition has to share its declaration's module +# attachment, and a plain TU elsewhere is rejected with +# "redeclaring ... in global module conflicts with import". +set(RUNTIME_SOURCE_FILES + # cmake-format: sortable + ast/AST.cpp + ast/ASTArena.cpp + executable/bytecode/instructions/Instructions.cpp executable/bytecode/BytecodeProgram.cpp - executable/bytecode/codegen/BytecodeGenerator.cpp - executable/bytecode/codegen/VariablesResolver.cpp + runtime/warnings/Warning.cpp + runtime/modules/BuiltinsModule.cpp + runtime/modules/CodecsModule.cpp + runtime/modules/GcModule.cpp + runtime/modules/IOModule.cpp + runtime/modules/ImpModule.cpp + runtime/modules/SysModule.cpp + executable/Mangler.cpp + parser/Parser.cpp executable/bytecode/instructions/BinaryOperation.cpp executable/bytecode/instructions/BinarySubscript.cpp executable/bytecode/instructions/BuildDict.cpp @@ -36,7 +132,6 @@ set(BYTECODE_SOURCE_FILES executable/bytecode/instructions/GetIter.cpp executable/bytecode/instructions/GetYieldFromIter.cpp executable/bytecode/instructions/InplaceOp.cpp - executable/bytecode/instructions/Instructions.cpp executable/bytecode/instructions/ImportFrom.cpp executable/bytecode/instructions/ImportName.cpp executable/bytecode/instructions/ImportStar.cpp @@ -89,39 +184,8 @@ set(BYTECODE_SOURCE_FILES executable/bytecode/instructions/YieldFrom.cpp executable/bytecode/instructions/YieldLoad.cpp executable/bytecode/instructions/YieldValue.cpp - executable/Mangler.cpp) - -set(EXECUTABLE_SOURCE_FILES # cmake-format: sortable - executable/Program.cpp) - -set(LEXER_SOURCE_FILES # cmake-format: sortable - lexer/Lexer.cpp) - -set(LLVM_BACKEND_FILES # cmake-format: sortable - executable/llvm/LLVMGenerator.cpp executable/llvm/LLVMProgram.cpp) - -set(INTERPRETER_SOURCE_FILES - # cmake-format: sortable - interpreter/Interpreter.cpp interpreter/InterpreterSession.cpp) - -set(MEMORY_SOURCE_FILES # cmake-format: sortable - memory/GarbageCollector.cpp memory/Heap.cpp) - -set(PARSER_SOURCE_FILES # cmake-format: sortable - parser/Parser.cpp) - -set(RUNTIME_SOURCE_FILES - # cmake-format: sortable - runtime/CustomPyObject.cpp - runtime/modules/BuiltinsModule.cpp - runtime/modules/CodecsModule.cpp - runtime/modules/ImpModule.cpp - runtime/modules/IOModule.cpp - runtime/modules/collections/module.cpp - runtime/modules/collections/Deque.cpp runtime/modules/collections/DefaultDict.cpp - runtime/modules/errno/module.cpp - runtime/modules/itertools/module.cpp + runtime/modules/collections/Deque.cpp runtime/modules/itertools/Chain.cpp runtime/modules/itertools/Count.cpp runtime/modules/itertools/ISlice.cpp @@ -129,102 +193,52 @@ set(RUNTIME_SOURCE_FILES runtime/modules/itertools/Product.cpp runtime/modules/itertools/Repeat.cpp runtime/modules/itertools/StarMap.cpp - runtime/modules/math/module.cpp - runtime/modules/signal/module.cpp - runtime/modules/thread/module.cpp - runtime/modules/time/module.cpp - runtime/modules/weakref/module.cpp + runtime/modules/sre/Match.cpp + runtime/modules/sre/Pattern.cpp runtime/modules/weakref/PyCallableProxyType.cpp runtime/modules/weakref/PyWeakProxy.cpp runtime/modules/weakref/PyWeakRef.cpp runtime/modules/MarshalModule.cpp runtime/modules/PosixModule.cpp + runtime/modules/WarningsModule.cpp + runtime/modules/collections/module.cpp + runtime/modules/errno/module.cpp + runtime/modules/itertools/module.cpp + runtime/modules/math/module.cpp + runtime/modules/signal/module.cpp runtime/modules/sre/module.cpp - runtime/modules/sre/Match.cpp - runtime/modules/sre/Pattern.cpp runtime/modules/struct/module.cpp - runtime/modules/SysModule.cpp - runtime/modules/WarningsModule.cpp - runtime/modules/GcModule.cpp - runtime/types/builtin.cpp - runtime/warnings/DeprecationWarning.cpp - runtime/warnings/ImportWarning.cpp - runtime/warnings/PendingDeprecationWarning.cpp - runtime/warnings/ResourceWarning.cpp - runtime/warnings/Warning.cpp - runtime/AssertionError.cpp - runtime/AttributeError.cpp + runtime/modules/thread/module.cpp + runtime/modules/time/module.cpp + runtime/modules/weakref/module.cpp + executable/bytecode/codegen/BytecodeGenerator.cpp + executable/bytecode/codegen/VariablesResolver.cpp + lexer/Lexer.cpp + interpreter/InterpreterSession.cpp runtime/BaseException.cpp - runtime/Exception.cpp runtime/GeneratorInterface.cpp - runtime/IndexError.cpp - runtime/Import.cpp - runtime/ImportError.cpp - runtime/KeyError.cpp - runtime/LookupError.cpp - runtime/MemoryError.cpp - runtime/ModuleNotFoundError.cpp - runtime/NameError.cpp - runtime/NotImplemented.cpp - runtime/NotImplementedError.cpp - runtime/OSError.cpp runtime/PyAsyncGenerator.cpp - runtime/PyBoundMethod.cpp - runtime/PyBool.cpp - runtime/PyBuiltInMethod.cpp - runtime/PyBytes.cpp - runtime/PyByteArray.cpp runtime/PyCell.cpp - runtime/PyClassMethod.cpp - runtime/PyClassMethodDescriptor.cpp runtime/PyCode.cpp - runtime/PyComplex.cpp runtime/PyCoroutine.cpp runtime/PyDict.cpp - runtime/PyEllipsis.cpp - runtime/PyEnumerate.cpp runtime/PyFloat.cpp runtime/PyFrame.cpp runtime/PyFrozenSet.cpp runtime/PyFunction.cpp runtime/PyGenerator.cpp - runtime/PyGenericAlias.cpp - runtime/PyGetSetDescriptor.cpp runtime/PyInteger.cpp - runtime/PyIterator.cpp runtime/PyList.cpp - runtime/PyLLVMFunction.cpp - runtime/PyMap.cpp - runtime/PyMappingProxy.cpp - runtime/PyMemberDescriptor.cpp - runtime/PyMemoryView.cpp - runtime/PyMethodDescriptor.cpp - runtime/PyModule.cpp - runtime/PyNamespace.cpp runtime/PyNone.cpp runtime/PyNumber.cpp runtime/PyObject.cpp - runtime/PyProperty.cpp - runtime/PyRange.cpp - runtime/PyReversed.cpp - runtime/PySet.cpp - runtime/PySlice.cpp - runtime/PySlotWrapper.cpp runtime/PyString.cpp - runtime/PySuper.cpp - runtime/PyStaticMethod.cpp runtime/PyTraceback.cpp runtime/PyTuple.cpp runtime/PyType.cpp - runtime/PyZip.cpp - runtime/RuntimeError.cpp - runtime/SourceManager.cpp - runtime/StopIteration.cpp - runtime/SyntaxError.cpp - runtime/TypeError.cpp - runtime/UnboundLocalError.cpp runtime/Value.cpp - runtime/ValueError.cpp) + runtime/types/builtin.cpp +) set(VM_SOURCE_FILES # cmake-format: sortable vm/VM.cpp) @@ -245,6 +259,7 @@ set(UNITTEST_SOURCES runtime/PyString_tests.cpp runtime/PyType_tests.cpp runtime/SourceManager_tests.cpp + runtime/warnings/Warnings_tests.cpp testing/main.cpp) set(PYTHON_LIB_PATH ${cpython_SOURCE_DIR}/Lib) @@ -252,22 +267,171 @@ set(PYTHON_INSTALL_PATH ${CMAKE_INSTALL_PREFIX}) configure_file(runtime/modules/paths.hpp.in runtime/modules/paths.hpp) -add_library( - python-cpp - ${AST_SOURCE_FILES} - ${BYTECODE_SOURCE_FILES} - ${EXECUTABLE_SOURCE_FILES} - ${LEXER_SOURCE_FILES} - ${INTERPRETER_SOURCE_FILES} - ${MEMORY_SOURCE_FILES} - ${PARSER_SOURCE_FILES} - ${RUNTIME_SOURCE_FILES} - ${VM_SOURCE_FILES}) +# --------------------------------------------------------------------------- +# python-runtime: the sole provider of the `py.runtime` module. +# --------------------------------------------------------------------------- +add_library(python-runtime) +set_target_properties(python-runtime PROPERTIES CXX_SCAN_FOR_MODULES ON CXX_MODULE_STD ON) + +target_sources(python-runtime + PUBLIC + FILE_SET CXX_MODULES + FILES + executable/Function.cppm + executable/FunctionBlock.cppm + executable/Program.cppm + executable/bytecode/Bytecode.cppm + executable/bytecode/BytecodeProgram.cppm + executable/bytecode/codegen/codegen.cppm + executable/bytecode/codegen/VariablesResolver.cppm + executable/bytecode/codegen/BytecodeGenerator.cppm + memory/memory.cppm + memory/GarbageCollector.cppm + memory/Heap.cppm + lexer/Lexer.cppm + ast/ASTArena.cppm + ast/AST.cppm + interpreter/Interpreter.cppm + interpreter/InterpreterSession.cppm + runtime/runtime.cppm + executable/bytecode/instructions/Instructions.cppm + runtime/Klass.cppm + runtime/AssertionError.cppm + runtime/AttributeError.cppm + runtime/ImportError.cppm + runtime/IndexError.cppm + runtime/LookupError.cppm + runtime/MemoryError.cppm + runtime/ModuleNotFoundError.cppm + runtime/NotImplemented.cppm + runtime/NotImplementedError.cppm + runtime/OSError.cppm + runtime/PyArgParser.cppm + runtime/PyBoundMethod.cppm + runtime/PyBuiltInMethod.cppm + runtime/PyByteArray.cppm + runtime/PyBytes.cppm + runtime/PyClassMethod.cppm + runtime/PyClassMethodDescriptor.cppm + runtime/PyComplex.cppm + runtime/PyEllipsis.cppm + runtime/PyEnumerate.cppm + runtime/PyGenericAlias.cppm + runtime/PyGetSetDescriptor.cppm + runtime/PyIterator.cppm + runtime/PyLLVMFunction.cppm + runtime/PyMap.cppm + runtime/PyMappingProxy.cppm + runtime/PyMemberDescriptor.cppm + runtime/PyMemoryView.cppm + runtime/PyMethodDescriptor.cppm + runtime/PyNamespace.cppm + runtime/PyProperty.cppm + runtime/PyRange.cppm + runtime/PyReversed.cppm + runtime/PySet.cppm + runtime/PySlice.cppm + runtime/PySlotWrapper.cppm + runtime/PyStaticMethod.cppm + runtime/PySuper.cppm + runtime/PyZip.cppm + runtime/RuntimeError.cppm + runtime/StopIteration.cppm + runtime/SyntaxError.cppm + runtime/TypeError.cppm + runtime/UnboundLocalError.cppm + runtime/ValueError.cppm + runtime/utilities.cppm + runtime/warnings/DeprecationWarning.cppm + runtime/warnings/ImportWarning.cppm + runtime/warnings/PendingDeprecationWarning.cppm + runtime/warnings/ResourceWarning.cppm + runtime/warnings/Warning.cppm + runtime/modules/Modules.cppm + runtime/BaseException.cppm + runtime/concepts.cppm + runtime/Exception.cppm + runtime/GeneratorInterface.cppm + runtime/Import.cppm + runtime/KeyError.cppm + runtime/NameError.cppm + runtime/PyAsyncGenerator.cppm + runtime/PyBool.cppm + runtime/PyCell.cppm + runtime/PyCode.cppm + runtime/PyCoroutine.cppm + runtime/PyDict.cppm + runtime/PyFloat.cppm + runtime/PyFrame.cppm + runtime/PyFrozenSet.cppm + runtime/PyFunction.cppm + runtime/PyGenerator.cppm + runtime/PyInteger.cppm + runtime/PyList.cppm + runtime/PyModule.cppm + runtime/PyNone.cppm + runtime/PyNumber.cppm + runtime/PyObject.cppm + runtime/PyString.cppm + runtime/PyTraceback.cppm + runtime/PyTuple.cppm + runtime/PyType.cppm + runtime/Value.cppm + vm/VM.cppm + executable/Mangler.cppm + parser/Parser.cppm + runtime/types/types.cppm + runtime/types/builtin.cppm + runtime/types/api.cppm + PRIVATE + ${EXECUTABLE_SOURCE_FILES} + ${INTERPRETER_SOURCE_FILES} + ${MEMORY_SOURCE_FILES} + ${RUNTIME_SOURCE_FILES} +) + +target_include_directories(python-runtime + PUBLIC . + PRIVATE ${GMP_INCLUDES} ${CMAKE_CURRENT_BINARY_DIR} +) + +# Value.cppm exposes mpz_class through py::Number, so GMP is a usage requirement +# of the module interface rather than an implementation detail. +target_link_libraries(python-runtime + PUBLIC spdlog m ${GMPXX_LIBRARIES} ${GMP_LIBRARIES} + PRIVATE ICU::uc ICU::data tsl::ordered_map +) + +if(STL_SUPPORTS_BIT_CAST) + target_compile_definitions(python-runtime PUBLIC "STL_SUPPORTS_BIT_CAST") +endif() + +python_cpp_link_project_options(python-runtime) + +# --------------------------------------------------------------------------- +# python-cpp: everything that is not a `py.runtime` module unit. It consumes the +# module, so it still needs scanning, but it provides no modules of its own. +# --------------------------------------------------------------------------- +add_library(python-cpp) +set_target_properties(python-cpp PROPERTIES CXX_SCAN_FOR_MODULES ON CXX_MODULE_STD ON) + +target_sources(python-cpp + PRIVATE + ${AST_SOURCE_FILES} + ${BYTECODE_SOURCE_FILES} + ${LEXER_SOURCE_FILES} + ${PARSER_SOURCE_FILES} + ${STDLIB_SOURCE_FILES} + ${VM_SOURCE_FILES} +) add_executable(unittests_ ${UNITTEST_SOURCES}) +set_target_properties(unittests_ PROPERTIES CXX_SCAN_FOR_MODULES ON CXX_MODULE_STD ON) +# PUBLIC so that every consumer of python-cpp (unittests_, python, freeze, and +# the MLIR libraries) inherits an acyclic path to the py.runtime BMIs. target_link_libraries(python-cpp - PUBLIC spdlog m + PUBLIC spdlog m python-runtime PRIVATE ICU::uc ICU::data @@ -346,9 +510,11 @@ target_link_libraries(unittests_ PRIVATE python-cpp gtest gtest_main cxxopts tsl gtest_discover_tests(unittests_) add_executable(python repl/repl.cpp) +set_target_properties(python PROPERTIES CXX_SCAN_FOR_MODULES ON CXX_MODULE_STD ON) target_link_libraries(python PRIVATE linenoise cxxopts python-cpp stdc++) add_executable(freeze utilities/freeze.cpp) +set_target_properties(freeze PROPERTIES CXX_SCAN_FOR_MODULES ON CXX_MODULE_STD ON) target_link_libraries(freeze PRIVATE python-cpp cxxopts) target_include_directories(freeze SYSTEM PRIVATE ${MLIR_INCLUDE_DIRS}) diff --git a/src/ast/AST.cpp b/src/ast/AST.cpp index 218e7bdd..ada22803 100644 --- a/src/ast/AST.cpp +++ b/src/ast/AST.cpp @@ -1,7 +1,11 @@ -#include "AST.hpp" +module; +#include "ast/ASTNodeTypes.hpp" +#include "core.hpp" +#include -#include "runtime/PyObject.hpp" -#include "runtime/Value.hpp" + +module py.ast; +import py.runtime; namespace ast { @@ -786,245 +790,272 @@ std::vector NodeTransformVisitor::visit(SetComp * node) #endif Constant::Constant(double value, SourceLocation source_location) - : ASTNode(ASTNodeType::Constant, source_location), - m_value(std::make_unique(py::Number{ value })) + : ASTNode(ASTNodeType::Constant, source_location), m_value(value) {} -Constant::Constant(int64_t value, SourceLocation source_location) - : ASTNode(ASTNodeType::Constant, source_location), - m_value(std::make_unique(py::Number{ value })) +Constant::Constant(std::int64_t value, SourceLocation source_location) + : ASTNode(ASTNodeType::Constant, source_location), m_value(value) {} Constant::Constant(mpz_class value, SourceLocation source_location) - : ASTNode(ASTNodeType::Constant, source_location), - m_value(std::make_unique(py::Number{ value })) + : ASTNode(ASTNodeType::Constant, source_location), m_value(value) {} Constant::Constant(bool value, SourceLocation source_location) - : ASTNode(ASTNodeType::Constant, source_location), - m_value(std::make_unique(py::NameConstant{ value })) + : ASTNode(ASTNodeType::Constant, source_location), m_value(value) {} Constant::Constant(std::string value, SourceLocation source_location) - : ASTNode(ASTNodeType::Constant, source_location), - m_value(std::make_unique(py::String{ std::move(value) })) + : ASTNode(ASTNodeType::Constant, source_location), m_value(std::move(value)) +{} + +Constant::Constant(Bytes value, SourceLocation source_location) + : ASTNode(ASTNodeType::Constant, source_location), m_value(std::move(value)) {} Constant::Constant(const char *value, SourceLocation source_location) - : ASTNode(ASTNodeType::Constant, source_location), - m_value(std::make_unique(py::String{ std::string(value) })) + : ASTNode(ASTNodeType::Constant, source_location), m_value(std::string(value)) {} -Constant::Constant(const py::Value &value, SourceLocation source_location) - : ASTNode(ASTNodeType::Constant, source_location), m_value(std::make_unique(value)) +Constant::Constant(const Literal &value, SourceLocation source_location) + : ASTNode(ASTNodeType::Constant, source_location), m_value(value) {} void Expression::print_this_node(const std::string &indent) const { - spdlog::debug("{}Expression", indent); + ::detail::log_debug(std::format("{}Expression", indent).c_str()); std::string new_indent = indent + std::string(6, ' '); m_value->print_node(new_indent); } void Constant::print_this_node(const std::string &indent) const { - spdlog::debug("{}Constant [{}:{}-{}:{}]", + ::detail::log_debug(std::format("{}Constant [{}:{}-{}:{}]", indent, source_location().start.row + 1, source_location().start.column + 1, source_location().end.row + 1, - source_location().end.column + 1); - std::visit(overloaded{ [&indent](const py::String &value) { - spdlog::debug("{} - value: \"{}\"", indent, value.to_string()); - }, - [&indent](const auto &value) { - spdlog::debug("{} - value: {}", indent, value.to_string()); + source_location().end.column + 1) + .c_str()); + // Literal is a plain variant of C++ types now - the AST no longer stores a + // py::Value - so the alternatives are formatted directly. + std::visit( + overloaded{ [&indent](std::monostate) { + ::detail::log_debug(std::format("{} - value: ", indent).c_str()); }, - [&indent](py::PyObject *const value) { - spdlog::debug("{} - value: {}", indent, value->to_string()); - } }, - *m_value); + [&indent](const std::string &value) { + ::detail::log_debug(std::format("{} - value: \"{}\"", indent, value).c_str()); + }, + [&indent](EllipsisType) { + ::detail::log_debug(std::format("{} - value: ...", indent).c_str()); + }, + [&indent](const Bytes &value) { + ::detail::log_debug( + std::format("{} - value: <{} bytes>", indent, value.size()).c_str()); + }, + [&indent](const mpz_class &value) { + ::detail::log_debug( + std::format("{} - value: {}", indent, value.get_str()).c_str()); + }, + [&indent](const auto &value) { + ::detail::log_debug(std::format("{} - value: {}", indent, value).c_str()); + } }, + m_value); } void List::print_this_node(const std::string &indent) const { - spdlog::debug("{}List [{}:{}-{}:{}]", + ::detail::log_debug(std::format("{}List [{}:{}-{}:{}]", indent, source_location().start.row + 1, source_location().start.column + 1, source_location().end.row + 1, - source_location().end.column + 1); - spdlog::debug("{} context: {}", indent, static_cast(m_ctx)); - spdlog::debug("{} elements:", indent); + source_location().end.column + 1) + .c_str()); + ::detail::log_debug(std::format("{} context: {}", indent, static_cast(m_ctx)).c_str()); + ::detail::log_debug(std::format("{} elements:", indent).c_str()); std::string new_indent = indent + std::string(6, ' '); for (const auto &el : m_elements) { el->print_node(new_indent); } } void Tuple::print_this_node(const std::string &indent) const { - spdlog::debug("{}Tuple [{}:{}-{}:{}]", + ::detail::log_debug(std::format("{}Tuple [{}:{}-{}:{}]", indent, source_location().start.row + 1, source_location().start.column + 1, source_location().end.row + 1, - source_location().end.column + 1); - spdlog::debug("{} context: {}", indent, static_cast(m_ctx)); - spdlog::debug("{} elements:", indent); + source_location().end.column + 1) + .c_str()); + ::detail::log_debug(std::format("{} context: {}", indent, static_cast(m_ctx)).c_str()); + ::detail::log_debug(std::format("{} elements:", indent).c_str()); std::string new_indent = indent + std::string(6, ' '); for (const auto &el : m_elements) { el->print_node(new_indent); } } void Dict::print_this_node(const std::string &indent) const { - spdlog::debug("{}Dict [{}:{}-{}:{}]", + ::detail::log_debug(std::format("{}Dict [{}:{}-{}:{}]", indent, source_location().start.row + 1, source_location().start.column + 1, source_location().end.row + 1, - source_location().end.column + 1); - spdlog::debug("{} keys:", indent); + source_location().end.column + 1) + .c_str()); + ::detail::log_debug(std::format("{} keys:", indent).c_str()); std::string new_indent = indent + std::string(6, ' '); for (const auto &el : m_keys) { if (!el) { - spdlog::debug("{}None", new_indent); + ::detail::log_debug(std::format("{}None", new_indent).c_str()); } else { el->print_node(new_indent); } } - spdlog::debug("{} values:", indent); + ::detail::log_debug(std::format("{} values:", indent).c_str()); for (const auto &el : m_values) { el->print_node(new_indent); } } void Set::print_this_node(const std::string &indent) const { - spdlog::debug("{}Set [{}:{}-{}:{}]", + ::detail::log_debug(std::format("{}Set [{}:{}-{}:{}]", indent, source_location().start.row + 1, source_location().start.column + 1, source_location().end.row + 1, - source_location().end.column + 1); - spdlog::debug("{} context: {}", indent, static_cast(m_ctx)); - spdlog::debug("{} elements:", indent); + source_location().end.column + 1) + .c_str()); + ::detail::log_debug(std::format("{} context: {}", indent, static_cast(m_ctx)).c_str()); + ::detail::log_debug(std::format("{} elements:", indent).c_str()); std::string new_indent = indent + std::string(6, ' '); for (const auto &el : m_elements) { el->print_node(new_indent); } } void Name::print_this_node(const std::string &indent) const { - spdlog::debug("{}Name [{}:{}-{}:{}]", + ::detail::log_debug(std::format("{}Name [{}:{}-{}:{}]", indent, source_location().start.row + 1, source_location().start.column + 1, source_location().end.row + 1, - source_location().end.column + 1); - spdlog::debug("{} - id: \"{}\"", indent, m_id[0]); - spdlog::debug("{} - context_type: {}", indent, static_cast(m_ctx)); + source_location().end.column + 1) + .c_str()); + ::detail::log_debug(std::format("{} - id: \"{}\"", indent, m_id[0]).c_str()); + ::detail::log_debug( + std::format("{} - context_type: {}", indent, static_cast(m_ctx)).c_str()); } void Assign::print_this_node(const std::string &indent) const { - spdlog::debug("{}Assign [{}:{}-{}:{}]", + ::detail::log_debug(std::format("{}Assign [{}:{}-{}:{}]", indent, source_location().start.row + 1, source_location().start.column + 1, source_location().end.row + 1, - source_location().end.column + 1); - spdlog::debug("{} - targets:", indent); + source_location().end.column + 1) + .c_str()); + ::detail::log_debug(std::format("{} - targets:", indent).c_str()); std::string new_indent = indent + std::string(6, ' '); for (const auto &t : m_targets) { t->print_node(new_indent); } - spdlog::debug("{} - value:", indent); + ::detail::log_debug(std::format("{} - value:", indent).c_str()); m_value->print_node(new_indent); - spdlog::debug("{} - comment type: {}", indent, m_type_comment); + ::detail::log_debug(std::format("{} - comment type: {}", indent, m_type_comment).c_str()); } void BinaryExpr::print_this_node(const std::string &indent) const { - spdlog::debug("{}BinaryOp [{}:{}-{}:{}]", + ::detail::log_debug(std::format("{}BinaryOp [{}:{}-{}:{}]", indent, source_location().start.row + 1, source_location().start.column + 1, source_location().end.row + 1, - source_location().end.column + 1); - spdlog::debug("{} - op_type: {}", indent, stringify_binary_op(m_op_type)); - spdlog::debug("{} - lhs:", indent); + source_location().end.column + 1) + .c_str()); + ::detail::log_debug( + std::format("{} - op_type: {}", indent, stringify_binary_op(m_op_type)).c_str()); + ::detail::log_debug(std::format("{} - lhs:", indent).c_str()); std::string new_indent = indent + std::string(6, ' '); m_lhs->print_node(new_indent); - spdlog::debug("{} - rhs:", indent); + ::detail::log_debug(std::format("{} - rhs:", indent).c_str()); m_rhs->print_node(new_indent); } void AugAssign::print_this_node(const std::string &indent) const { - spdlog::debug("{}AugAssign [{}:{}-{}:{}]", + ::detail::log_debug(std::format("{}AugAssign [{}:{}-{}:{}]", indent, source_location().start.row + 1, source_location().start.column + 1, source_location().end.row + 1, - source_location().end.column + 1); + source_location().end.column + 1) + .c_str()); std::string new_indent = indent + std::string(6, ' '); - spdlog::debug("{} - target:", indent); + ::detail::log_debug(std::format("{} - target:", indent).c_str()); m_target->print_node(new_indent); - spdlog::debug("{} - op: {}", indent, stringify_binary_op(m_op)); - spdlog::debug("{} - value:", indent); + ::detail::log_debug(std::format("{} - op: {}", indent, stringify_binary_op(m_op)).c_str()); + ::detail::log_debug(std::format("{} - value:", indent).c_str()); m_value->print_node(new_indent); } void Return::print_this_node(const std::string &indent) const { - spdlog::debug("{}Return [{}:{}-{}:{}]", + ::detail::log_debug(std::format("{}Return [{}:{}-{}:{}]", indent, source_location().start.row + 1, source_location().start.column + 1, source_location().end.row + 1, - source_location().end.column + 1); - spdlog::debug("{} - value: {}", indent, m_value ? "" : "null"); + source_location().end.column + 1) + .c_str()); + ::detail::log_debug(std::format("{} - value: {}", indent, m_value ? "" : "null").c_str()); std::string new_indent = indent + std::string(6, ' '); if (m_value) { m_value->print_node(new_indent); } } void Yield::print_this_node(const std::string &indent) const { - spdlog::debug("{}Yield [{}:{}-{}:{}]", + ::detail::log_debug(std::format("{}Yield [{}:{}-{}:{}]", indent, source_location().start.row + 1, source_location().start.column + 1, source_location().end.row + 1, - source_location().end.column + 1); - spdlog::debug("{} - value:", indent); + source_location().end.column + 1) + .c_str()); + ::detail::log_debug(std::format("{} - value:", indent).c_str()); std::string new_indent = indent + std::string(6, ' '); m_value->print_node(new_indent); } void YieldFrom::print_this_node(const std::string &indent) const { - spdlog::debug("{}YieldFrom [{}:{}-{}:{}]", + ::detail::log_debug(std::format("{}YieldFrom [{}:{}-{}:{}]", indent, source_location().start.row + 1, source_location().start.column + 1, source_location().end.row + 1, - source_location().end.column + 1); - spdlog::debug("{} - value:", indent); + source_location().end.column + 1) + .c_str()); + ::detail::log_debug(std::format("{} - value:", indent).c_str()); std::string new_indent = indent + std::string(6, ' '); m_value->print_node(new_indent); } void Argument::print_this_node(const std::string &indent) const { - spdlog::debug("{}Argument [{}:{}-{}:{}]", + ::detail::log_debug(std::format("{}Argument [{}:{}-{}:{}]", indent, source_location().start.row + 1, source_location().start.column + 1, source_location().end.row + 1, - source_location().end.column + 1); - spdlog::debug("{} - arg: {}", indent, m_arg); + source_location().end.column + 1) + .c_str()); + ::detail::log_debug(std::format("{} - arg: {}", indent, m_arg).c_str()); if (m_annotation) { - spdlog::debug("{} - annotation:", indent); + ::detail::log_debug(std::format("{} - annotation:", indent).c_str()); std::string new_indent = indent + std::string(6, ' '); m_annotation->print_node(new_indent); } else { - spdlog::debug("{} - annotation: None", indent); + ::detail::log_debug(std::format("{} - annotation: None", indent).c_str()); } - spdlog::debug("{} - type_comment: {}", indent, m_type_comment); + ::detail::log_debug(std::format("{} - type_comment: {}", indent, m_type_comment).c_str()); } std::vector Arguments::argument_names() const @@ -1045,244 +1076,256 @@ std::vector Arguments::kw_only_argument_names() const void Arguments::print_this_node(const std::string &indent) const { - spdlog::debug("{}Arguments [{}:{}-{}:{}]", + ::detail::log_debug(std::format("{}Arguments [{}:{}-{}:{}]", indent, source_location().start.row + 1, source_location().start.column + 1, source_location().end.row + 1, - source_location().end.column + 1); + source_location().end.column + 1) + .c_str()); std::string new_indent = indent + std::string(6, ' '); - spdlog::debug("{} - posonlyarg:", indent); + ::detail::log_debug(std::format("{} - posonlyarg:", indent).c_str()); for (const auto &arg : m_posonlyargs) { arg->print_node(new_indent); } - spdlog::debug("{} - args:", indent); + ::detail::log_debug(std::format("{} - args:", indent).c_str()); for (const auto &arg : m_args) { arg->print_node(new_indent); } - spdlog::debug("{} - vararg:", indent); + ::detail::log_debug(std::format("{} - vararg:", indent).c_str()); if (m_vararg) { m_vararg->print_node(new_indent); } - spdlog::debug("{} - kwonlyargs:", indent); + ::detail::log_debug(std::format("{} - kwonlyargs:", indent).c_str()); for (const auto &kwarg : m_kwonlyargs) { kwarg->print_node(new_indent); } - spdlog::debug("{} - kw_defaults:", indent); + ::detail::log_debug(std::format("{} - kw_defaults:", indent).c_str()); for (const auto &arg : m_kw_defaults) { if (arg) arg->print_node(new_indent); else - spdlog::debug("{}null", new_indent); + ::detail::log_debug(std::format("{}null", new_indent).c_str()); } - spdlog::debug("{} - kwarg:", indent); + ::detail::log_debug(std::format("{} - kwarg:", indent).c_str()); if (m_kwarg) { m_kwarg->print_node(new_indent); } - spdlog::debug("{} - defaults:", indent); + ::detail::log_debug(std::format("{} - defaults:", indent).c_str()); for (const auto &arg : m_defaults) { if (arg) arg->print_node(new_indent); else - spdlog::debug("{}null", new_indent); + ::detail::log_debug(std::format("{}null", new_indent).c_str()); } } void FunctionDefinition::print_this_node(const std::string &indent) const { - spdlog::debug("{}FunctionDefinition [{}:{}-{}:{}]", + ::detail::log_debug(std::format("{}FunctionDefinition [{}:{}-{}:{}]", indent, source_location().start.row + 1, source_location().start.column + 1, source_location().end.row + 1, - source_location().end.column + 1); - spdlog::debug("{} - function_name: {}", indent, m_function_name); + source_location().end.column + 1) + .c_str()); + ::detail::log_debug(std::format("{} - function_name: {}", indent, m_function_name).c_str()); std::string new_indent = indent + std::string(6, ' '); - spdlog::debug("{} - args:", indent); + ::detail::log_debug(std::format("{} - args:", indent).c_str()); m_args->print_node(new_indent); - spdlog::debug("{} - body:", indent); + ::detail::log_debug(std::format("{} - body:", indent).c_str()); for (const auto &statement : m_body) { statement->print_node(new_indent); } - spdlog::debug("{} - decorator_list:", indent); + ::detail::log_debug(std::format("{} - decorator_list:", indent).c_str()); for (const auto &decorator : m_decorator_list) { decorator->print_node(new_indent); } - spdlog::debug("{} - returns:", indent); + ::detail::log_debug(std::format("{} - returns:", indent).c_str()); if (m_returns) m_returns->print_node(new_indent); - spdlog::debug("{} - type_comment:{}", indent, m_type_comment); + ::detail::log_debug(std::format("{} - type_comment:{}", indent, m_type_comment).c_str()); } void AsyncFunctionDefinition::print_this_node(const std::string &indent) const { - spdlog::debug("{}AsyncFunctionDefinition [{}:{}-{}:{}]", + ::detail::log_debug(std::format("{}AsyncFunctionDefinition [{}:{}-{}:{}]", indent, source_location().start.row + 1, source_location().start.column + 1, source_location().end.row + 1, - source_location().end.column + 1); - spdlog::debug("{} - function_name: {}", indent, m_function_name); + source_location().end.column + 1) + .c_str()); + ::detail::log_debug(std::format("{} - function_name: {}", indent, m_function_name).c_str()); std::string new_indent = indent + std::string(6, ' '); - spdlog::debug("{} - args:", indent); + ::detail::log_debug(std::format("{} - args:", indent).c_str()); m_args->print_node(new_indent); - spdlog::debug("{} - body:", indent); + ::detail::log_debug(std::format("{} - body:", indent).c_str()); for (const auto &statement : m_body) { statement->print_node(new_indent); } - spdlog::debug("{} - decorator_list:", indent); + ::detail::log_debug(std::format("{} - decorator_list:", indent).c_str()); for (const auto &decorator : m_decorator_list) { decorator->print_node(new_indent); } - spdlog::debug("{} - returns:", indent); + ::detail::log_debug(std::format("{} - returns:", indent).c_str()); if (m_returns) m_returns->print_node(new_indent); - spdlog::debug("{} - type_comment:{}", indent, m_type_comment); + ::detail::log_debug(std::format("{} - type_comment:{}", indent, m_type_comment).c_str()); } void Await::print_this_node(const std::string &indent) const { - spdlog::debug("{}Await [{}:{}-{}:{}]", + ::detail::log_debug(std::format("{}Await [{}:{}-{}:{}]", indent, source_location().start.row + 1, source_location().start.column + 1, source_location().end.row + 1, - source_location().end.column + 1); - spdlog::debug("{} - value:", indent); + source_location().end.column + 1) + .c_str()); + ::detail::log_debug(std::format("{} - value:", indent).c_str()); std::string new_indent = indent + std::string(6, ' '); m_value->print_node(new_indent); } void Lambda::print_this_node(const std::string &indent) const { - spdlog::debug("{}Lambda [{}:{}-{}:{}]", + ::detail::log_debug(std::format("{}Lambda [{}:{}-{}:{}]", indent, source_location().start.row + 1, source_location().start.column + 1, source_location().end.row + 1, - source_location().end.column + 1); + source_location().end.column + 1) + .c_str()); std::string new_indent = indent + std::string(6, ' '); - spdlog::debug("{} - args:", indent); + ::detail::log_debug(std::format("{} - args:", indent).c_str()); m_args->print_node(new_indent); - spdlog::debug("{} - body:", indent); + ::detail::log_debug(std::format("{} - body:", indent).c_str()); m_body->print_node(new_indent); } void Keyword::print_this_node(const std::string &indent) const { - spdlog::debug("{}Keyword [{}:{}-{}:{}]", + ::detail::log_debug(std::format("{}Keyword [{}:{}-{}:{}]", indent, source_location().start.row + 1, source_location().start.column + 1, source_location().end.row + 1, - source_location().end.column + 1); + source_location().end.column + 1) + .c_str()); if (m_arg.has_value()) { - spdlog::debug("{} - arg: {}", indent, *m_arg); + ::detail::log_debug(std::format("{} - arg: {}", indent, *m_arg).c_str()); } else { - spdlog::debug("{} - arg: null", indent); + ::detail::log_debug(std::format("{} - arg: null", indent).c_str()); } - spdlog::debug("{} - value:", indent); + ::detail::log_debug(std::format("{} - value:", indent).c_str()); std::string new_indent = indent + std::string(6, ' '); m_value->print_node(new_indent); } void ClassDefinition::print_this_node(const std::string &indent) const { - spdlog::debug("{}ClassDefinition [{}:{}-{}:{}]", + ::detail::log_debug(std::format("{}ClassDefinition [{}:{}-{}:{}]", indent, source_location().start.row + 1, source_location().start.column + 1, source_location().end.row + 1, - source_location().end.column + 1); - spdlog::debug("{} - function_name: {}", indent, m_class_name); + source_location().end.column + 1) + .c_str()); + ::detail::log_debug(std::format("{} - function_name: {}", indent, m_class_name).c_str()); std::string new_indent = indent + std::string(6, ' '); - spdlog::debug("{} - bases:", indent); + ::detail::log_debug(std::format("{} - bases:", indent).c_str()); for (const auto &base : m_bases) { base->print_node(new_indent); } - spdlog::debug("{} - keywords:", indent); + ::detail::log_debug(std::format("{} - keywords:", indent).c_str()); for (const auto &keyword : m_keywords) { keyword->print_node(new_indent); } - spdlog::debug("{} - body:", indent); + ::detail::log_debug(std::format("{} - body:", indent).c_str()); for (const auto &statement : m_body) { statement->print_node(new_indent); } - spdlog::debug("{} - decorator_list:", indent); + ::detail::log_debug(std::format("{} - decorator_list:", indent).c_str()); for (const auto &decorator : m_decorator_list) { decorator->print_node(new_indent); } } void Call::print_this_node(const std::string &indent) const { std::string new_indent = indent + std::string(6, ' '); - spdlog::debug("{}Call [{}:{}-{}:{}]", + ::detail::log_debug(std::format("{}Call [{}:{}-{}:{}]", indent, source_location().start.row + 1, source_location().start.column + 1, source_location().end.row + 1, - source_location().end.column + 1); - spdlog::debug("{} - function:", indent); + source_location().end.column + 1) + .c_str()); + ::detail::log_debug(std::format("{} - function:", indent).c_str()); m_function->print_node(new_indent); - spdlog::debug("{} - args:", indent); + ::detail::log_debug(std::format("{} - args:", indent).c_str()); for (const auto &arg : m_args) { arg->print_node(new_indent); } - spdlog::debug("{} - keywords:", indent); + ::detail::log_debug(std::format("{} - keywords:", indent).c_str()); for (const auto &keyword : m_keywords) { keyword->print_node(new_indent); } } void Module::print_this_node(const std::string &indent) const { - spdlog::debug("{}Module", indent); - spdlog::debug("{} - body:", indent); + ::detail::log_debug(std::format("{}Module", indent).c_str()); + ::detail::log_debug(std::format("{} - body:", indent).c_str()); std::string new_indent = indent + std::string(6, ' '); for (const auto &el : m_body) { el->print_node(new_indent); } } void If::print_this_node(const std::string &indent) const { - spdlog::debug("{}If [{}:{}-{}:{}]", + ::detail::log_debug(std::format("{}If [{}:{}-{}:{}]", indent, source_location().start.row + 1, source_location().start.column + 1, source_location().end.row + 1, - source_location().end.column + 1); + source_location().end.column + 1) + .c_str()); std::string new_indent = indent + std::string(6, ' '); - spdlog::debug("{} - test:", indent); + ::detail::log_debug(std::format("{} - test:", indent).c_str()); m_test->print_node(new_indent); - spdlog::debug("{} - body:", indent); + ::detail::log_debug(std::format("{} - body:", indent).c_str()); for (const auto &el : m_body) { el->print_node(new_indent); } - spdlog::debug("{} - orelse:", indent); + ::detail::log_debug(std::format("{} - orelse:", indent).c_str()); for (const auto &el : m_orelse) { el->print_node(new_indent); } } void For::print_this_node(const std::string &indent) const { - spdlog::debug("{}For [{}:{}-{}:{}]", + ::detail::log_debug(std::format("{}For [{}:{}-{}:{}]", indent, source_location().start.row + 1, source_location().start.column + 1, source_location().end.row + 1, - source_location().end.column + 1); + source_location().end.column + 1) + .c_str()); std::string new_indent = indent + std::string(6, ' '); - spdlog::debug("{} - target:", indent); + ::detail::log_debug(std::format("{} - target:", indent).c_str()); m_target->print_node(new_indent); - spdlog::debug("{} - iter:", indent); + ::detail::log_debug(std::format("{} - iter:", indent).c_str()); m_iter->print_node(new_indent); - spdlog::debug("{} - body:", indent); + ::detail::log_debug(std::format("{} - body:", indent).c_str()); for (const auto &el : m_body) { el->print_node(new_indent); } - spdlog::debug("{} - orelse:", indent); + ::detail::log_debug(std::format("{} - orelse:", indent).c_str()); for (const auto &el : m_orelse) { el->print_node(new_indent); } - spdlog::debug("{} - type_comment:", m_type_comment); + ::detail::log_debug(std::format("{} - type_comment:", m_type_comment).c_str()); } void While::print_this_node(const std::string &indent) const { - spdlog::debug("{}While [{}:{}-{}:{}]", + ::detail::log_debug(std::format("{}While [{}:{}-{}:{}]", indent, source_location().start.row + 1, source_location().start.column + 1, source_location().end.row + 1, - source_location().end.column + 1); + source_location().end.column + 1) + .c_str()); std::string new_indent = indent + std::string(6, ' '); - spdlog::debug("{} - target:", indent); + ::detail::log_debug(std::format("{} - target:", indent).c_str()); m_test->print_node(new_indent); - spdlog::debug("{} - body:", indent); + ::detail::log_debug(std::format("{} - body:", indent).c_str()); for (const auto &el : m_body) { el->print_node(new_indent); } - spdlog::debug("{} - orelse:", indent); + ::detail::log_debug(std::format("{} - orelse:", indent).c_str()); } void Compare::print_this_node(const std::string &indent) const { - spdlog::debug("{}Compare [{}:{}-{}:{}]", + ::detail::log_debug(std::format("{}Compare [{}:{}-{}:{}]", indent, source_location().start.row + 1, source_location().start.column + 1, source_location().end.row + 1, - source_location().end.column + 1); + source_location().end.column + 1) + .c_str()); std::string new_indent = indent + std::string(6, ' '); - spdlog::debug("{} - lhs:", indent); + ::detail::log_debug(std::format("{} - lhs:", indent).c_str()); m_lhs->print_node(new_indent); - spdlog::debug("{} - op:", indent); - for (size_t i = 0; i < m_ops.size(); ++i) { + ::detail::log_debug(std::format("{} - op:", indent).c_str()); + for (std::size_t i = 0; i < m_ops.size(); ++i) { const auto op = op_type_to_string(m_ops[i]); - spdlog::debug("{} - {}", indent, op); + ::detail::log_debug(std::format("{} - {}", indent, op).c_str()); } - spdlog::debug("{} - comparators:", indent); - for (size_t i = 0; i < m_comparators.size(); ++i) { + ::detail::log_debug(std::format("{} - comparators:", indent).c_str()); + for (std::size_t i = 0; i < m_comparators.size(); ++i) { const auto &comparator = m_comparators[i]; comparator->print_node(new_indent); } @@ -1290,89 +1333,92 @@ void Compare::print_this_node(const std::string &indent) const void Attribute::print_this_node(const std::string &indent) const { - spdlog::debug("{}Attribute [{}:{}-{}:{}]", + ::detail::log_debug(std::format("{}Attribute [{}:{}-{}:{}]", indent, source_location().start.row + 1, source_location().start.column + 1, source_location().end.row + 1, - source_location().end.column + 1); + source_location().end.column + 1) + .c_str()); std::string new_indent = indent + std::string(6, ' '); - spdlog::debug("{} - value:", indent); + ::detail::log_debug(std::format("{} - value:", indent).c_str()); m_value->print_node(new_indent); - spdlog::debug("{} - attr: \"{}\"", indent, m_attr); - spdlog::debug("{} - ctx: {}", indent, static_cast(m_ctx)); + ::detail::log_debug(std::format("{} - attr: \"{}\"", indent, m_attr).c_str()); + ::detail::log_debug(std::format("{} - ctx: {}", indent, static_cast(m_ctx)).c_str()); } void Import::print_this_node(const std::string &indent) const { - spdlog::debug("{}Import [{}:{}-{}:{}]", + ::detail::log_debug(std::format("{}Import [{}:{}-{}:{}]", indent, source_location().start.row + 1, source_location().start.column + 1, source_location().end.row + 1, - source_location().end.column + 1); + source_location().end.column + 1) + .c_str()); for (const auto &name : m_names) { - spdlog::debug("{} - alias:", indent); - spdlog::debug("{} asname: {}", indent, name.asname); - spdlog::debug("{} name: {}", indent, name.name); + ::detail::log_debug(std::format("{} - alias:", indent).c_str()); + ::detail::log_debug(std::format("{} asname: {}", indent, name.asname).c_str()); + ::detail::log_debug(std::format("{} name: {}", indent, name.name).c_str()); } } void ImportFrom::print_this_node(const std::string &indent) const { - spdlog::debug("{}ImportFrom [{}:{}-{}:{}]", + ::detail::log_debug(std::format("{}ImportFrom [{}:{}-{}:{}]", indent, source_location().start.row + 1, source_location().start.column + 1, source_location().end.row + 1, - source_location().end.column + 1); - spdlog::debug("{} - level: {}", indent, m_level); - spdlog::debug("{} - module: {}", indent, m_module); + source_location().end.column + 1) + .c_str()); + ::detail::log_debug(std::format("{} - level: {}", indent, m_level).c_str()); + ::detail::log_debug(std::format("{} - module: {}", indent, m_module).c_str()); for (const auto &name : m_names) { - spdlog::debug("{} - alias:", indent); - spdlog::debug("{} asname: {}", indent, name.asname); - spdlog::debug("{} name: {}", indent, name.name); + ::detail::log_debug(std::format("{} - alias:", indent).c_str()); + ::detail::log_debug(std::format("{} asname: {}", indent, name.asname).c_str()); + ::detail::log_debug(std::format("{} name: {}", indent, name.name).c_str()); } } void Subscript::Index::print(const std::string &indent) const { - spdlog::debug("{}Index", indent); + ::detail::log_debug(std::format("{}Index", indent).c_str()); std::string new_indent = indent + std::string(6, ' '); - spdlog::debug("{} - value:", indent); + ::detail::log_debug(std::format("{} - value:", indent).c_str()); value->print_node(new_indent); } void Subscript::Slice::print(const std::string &indent) const { - spdlog::debug("{}Slice", indent); + ::detail::log_debug(std::format("{}Slice", indent).c_str()); std::string new_indent = indent + std::string(6, ' '); if (lower) { - spdlog::debug("{} - lower:", indent); + ::detail::log_debug(std::format("{} - lower:", indent).c_str()); lower->print_node(new_indent); } else { - spdlog::debug("{} - lower: null", indent); + ::detail::log_debug(std::format("{} - lower: null", indent).c_str()); } if (upper) { - spdlog::debug("{} - upper:", indent); + ::detail::log_debug(std::format("{} - upper:", indent).c_str()); upper->print_node(new_indent); } else { - spdlog::debug("{} - upper: null", indent); + ::detail::log_debug(std::format("{} - upper: null", indent).c_str()); } if (step) { - spdlog::debug("{} - step:", indent); + ::detail::log_debug(std::format("{} - step:", indent).c_str()); step->print_node(new_indent); } else { - spdlog::debug("{} - step: null", indent); + ::detail::log_debug(std::format("{} - step: null", indent).c_str()); } } void Subscript::ExtSlice::print(const std::string &indent) const { - spdlog::debug("{}ExtSlice", indent); + ::detail::log_debug(std::format("{}ExtSlice", indent).c_str()); std::string new_indent = indent + std::string(6, ' '); for (const auto &d : dims) { std::visit([&new_indent](const auto &val) { val.print(new_indent); }, d); @@ -1381,324 +1427,351 @@ void Subscript::ExtSlice::print(const std::string &indent) const void Subscript::print_this_node(const std::string &indent) const { - spdlog::debug("{}Subscript [{}:{}-{}:{}]", + ::detail::log_debug(std::format("{}Subscript [{}:{}-{}:{}]", indent, source_location().start.row + 1, source_location().start.column + 1, source_location().end.row + 1, - source_location().end.column + 1); + source_location().end.column + 1) + .c_str()); std::string new_indent = indent + std::string(6, ' '); - spdlog::debug("{} - value:", indent); + ::detail::log_debug(std::format("{} - value:", indent).c_str()); if (m_value) { m_value->print_node(new_indent); } - spdlog::debug("{} - slice:", indent); + ::detail::log_debug(std::format("{} - slice:", indent).c_str()); if (m_slice) { std::visit([&new_indent](const auto &val) { val.print(new_indent); }, *m_slice); } - spdlog::debug("{} - ctx: {}", indent, m_ctx); + ::detail::log_debug(std::format("{} - ctx: {}", indent, static_cast(m_ctx)).c_str()); } void Raise::print_this_node(const std::string &indent) const { - spdlog::debug("{}Raise [{}:{}-{}:{}]", + ::detail::log_debug(std::format("{}Raise [{}:{}-{}:{}]", indent, source_location().start.row + 1, source_location().start.column + 1, source_location().end.row + 1, - source_location().end.column + 1); + source_location().end.column + 1) + .c_str()); std::string new_indent = indent + std::string(6, ' '); if (m_exception) { - spdlog::debug("{} - exception:", indent); + ::detail::log_debug(std::format("{} - exception:", indent).c_str()); m_exception->print_node(new_indent); } else { - spdlog::debug("{} - exception: null", indent); + ::detail::log_debug(std::format("{} - exception: null", indent).c_str()); } if (m_cause) { - spdlog::debug("{} - cause:", indent); + ::detail::log_debug(std::format("{} - cause:", indent).c_str()); m_cause->print_node(new_indent); } else { - spdlog::debug("{} - cause: null", indent); + ::detail::log_debug(std::format("{} - cause: null", indent).c_str()); } } void ExceptHandler::print_this_node(const std::string &indent) const { - spdlog::debug("{}ExceptHandler [{}:{}-{}:{}]", + ::detail::log_debug(std::format("{}ExceptHandler [{}:{}-{}:{}]", indent, source_location().start.row + 1, source_location().start.column + 1, source_location().end.row + 1, - source_location().end.column + 1); + source_location().end.column + 1) + .c_str()); std::string new_indent = indent + std::string(6, ' '); if (m_type) { - spdlog::debug("{} - type:", indent); + ::detail::log_debug(std::format("{} - type:", indent).c_str()); m_type->print_node(new_indent); } else { - spdlog::debug("{} - type: null", indent); + ::detail::log_debug(std::format("{} - type: null", indent).c_str()); } - spdlog::debug("{} - name: {}", indent, m_name); - spdlog::debug("{} - body:", indent); + ::detail::log_debug(std::format("{} - name: {}", indent, m_name).c_str()); + ::detail::log_debug(std::format("{} - body:", indent).c_str()); for (const auto &node : m_body) { node->print_node(new_indent); } } void Try::print_this_node(const std::string &indent) const { - spdlog::debug("{}Try [{}:{}-{}:{}]", + ::detail::log_debug(std::format("{}Try [{}:{}-{}:{}]", indent, source_location().start.row + 1, source_location().start.column + 1, source_location().end.row + 1, - source_location().end.column + 1); + source_location().end.column + 1) + .c_str()); std::string new_indent = indent + std::string(6, ' '); - spdlog::debug("{} - body:", indent); + ::detail::log_debug(std::format("{} - body:", indent).c_str()); for (const auto &node : m_body) { node->print_node(new_indent); } - spdlog::debug("{} - handlers:", indent); + ::detail::log_debug(std::format("{} - handlers:", indent).c_str()); for (const auto &node : m_handlers) { node->print_node(new_indent); } - spdlog::debug("{} - orelse:", indent); + ::detail::log_debug(std::format("{} - orelse:", indent).c_str()); for (const auto &node : m_orelse) { node->print_node(new_indent); } - spdlog::debug("{} - finalbody:", indent); + ::detail::log_debug(std::format("{} - finalbody:", indent).c_str()); for (const auto &node : m_finalbody) { node->print_node(new_indent); } } void Assert::print_this_node(const std::string &indent) const { - spdlog::debug("{}Assert [{}:{}-{}:{}]", + ::detail::log_debug(std::format("{}Assert [{}:{}-{}:{}]", indent, source_location().start.row + 1, source_location().start.column + 1, source_location().end.row + 1, - source_location().end.column + 1); + source_location().end.column + 1) + .c_str()); std::string new_indent = indent + std::string(6, ' '); - spdlog::debug("{} - test:", indent); + ::detail::log_debug(std::format("{} - test:", indent).c_str()); m_test->print_node(new_indent); if (m_msg) { - spdlog::debug("{} - message:", indent); + ::detail::log_debug(std::format("{} - message:", indent).c_str()); m_msg->print_node(new_indent); } else { - spdlog::debug("{} - message: null", indent); + ::detail::log_debug(std::format("{} - message: null", indent).c_str()); } } void UnaryExpr::print_this_node(const std::string &indent) const { - spdlog::debug("{}UnaryExpr [{}:{}-{}:{}]", + ::detail::log_debug(std::format("{}UnaryExpr [{}:{}-{}:{}]", indent, source_location().start.row + 1, source_location().start.column + 1, source_location().end.row + 1, - source_location().end.column + 1); + source_location().end.column + 1) + .c_str()); std::string new_indent = indent + std::string(6, ' '); - spdlog::debug("{} - op_type: {}", indent, stringify_unary_op(m_op_type)); + ::detail::log_debug( + std::format("{} - op_type: {}", indent, stringify_unary_op(m_op_type)).c_str()); m_operand->print_node(new_indent); } void BoolOp::print_this_node(const std::string &indent) const { - spdlog::debug("{}BoolOp [{}:{}-{}:{}]", + ::detail::log_debug(std::format("{}BoolOp [{}:{}-{}:{}]", indent, source_location().start.row + 1, source_location().start.column + 1, source_location().end.row + 1, - source_location().end.column + 1); + source_location().end.column + 1) + .c_str()); std::string new_indent = indent + std::string(6, ' '); - spdlog::debug("{} - op_type: {}", indent, op_type_to_string(m_op)); - spdlog::debug("{}Values:", indent); + ::detail::log_debug(std::format("{} - op_type: {}", indent, op_type_to_string(m_op)).c_str()); + ::detail::log_debug(std::format("{}Values:", indent).c_str()); for (const auto &value : m_values) { value->print_node(new_indent); } } -void Pass::print_this_node(const std::string &indent) const { spdlog::debug("{}Pass", indent); } +void Pass::print_this_node(const std::string &indent) const +{ + ::detail::log_debug(std::format("{}Pass", indent).c_str()); +} void Continue::print_this_node(const std::string &indent) const { - spdlog::debug("{}Continue", indent); + ::detail::log_debug(std::format("{}Continue", indent).c_str()); } -void Break::print_this_node(const std::string &indent) const { spdlog::debug("{}Break", indent); } +void Break::print_this_node(const std::string &indent) const +{ + ::detail::log_debug(std::format("{}Break", indent).c_str()); +} void Global::print_this_node(const std::string &indent) const { - spdlog::debug("{}Global [{}:{}-{}:{}]", + ::detail::log_debug(std::format("{}Global [{}:{}-{}:{}]", indent, source_location().start.row + 1, source_location().start.column + 1, source_location().end.row + 1, - source_location().end.column + 1); + source_location().end.column + 1) + .c_str()); std::string new_indent = indent + std::string(6, ' '); - for (const auto &name : m_names) { spdlog::debug("{} {}", new_indent, name); } + for (const auto &name : m_names) { + ::detail::log_debug(std::format("{} {}", new_indent, name).c_str()); + } } void NonLocal::print_this_node(const std::string &indent) const { - spdlog::debug("{}NonLocal [{}:{}-{}:{}]", + ::detail::log_debug(std::format("{}NonLocal [{}:{}-{}:{}]", indent, source_location().start.row + 1, source_location().start.column + 1, source_location().end.row + 1, - source_location().end.column + 1); + source_location().end.column + 1) + .c_str()); std::string new_indent = indent + std::string(6, ' '); - for (const auto &name : m_names) { spdlog::debug("{} {}", new_indent, name); } + for (const auto &name : m_names) { + ::detail::log_debug(std::format("{} {}", new_indent, name).c_str()); + } } void Delete::print_this_node(const std::string &indent) const { - spdlog::debug("{}Delete [{}:{}-{}:{}]", + ::detail::log_debug(std::format("{}Delete [{}:{}-{}:{}]", indent, source_location().start.row + 1, source_location().start.column + 1, source_location().end.row + 1, - source_location().end.column + 1); - spdlog::debug("{} - targets", indent); + source_location().end.column + 1) + .c_str()); + ::detail::log_debug(std::format("{} - targets", indent).c_str()); std::string new_indent = indent + std::string(6, ' '); for (const auto &target : m_targets) { target->print_node(new_indent); } } void With::print_this_node(const std::string &indent) const { - spdlog::debug("{}With [{}:{}-{}:{}]", + ::detail::log_debug(std::format("{}With [{}:{}-{}:{}]", indent, source_location().start.row + 1, source_location().start.column + 1, source_location().end.row + 1, - source_location().end.column + 1); - spdlog::debug("{} - items", indent); + source_location().end.column + 1) + .c_str()); + ::detail::log_debug(std::format("{} - items", indent).c_str()); std::string new_indent = indent + std::string(6, ' '); for (const auto &item : m_items) { item->print_node(new_indent); } - spdlog::debug("{} - body", indent); + ::detail::log_debug(std::format("{} - body", indent).c_str()); for (const auto &statement : m_body) { statement->print_node(new_indent); } - spdlog::debug("{} - type_comment: ", indent, m_type_comment); + ::detail::log_debug(std::format("{} - type_comment: ", indent, m_type_comment).c_str()); } void WithItem::print_this_node(const std::string &indent) const { - spdlog::debug("{}WithItem [{}:{}-{}:{}]", + ::detail::log_debug(std::format("{}WithItem [{}:{}-{}:{}]", indent, source_location().start.row + 1, source_location().start.column + 1, source_location().end.row + 1, - source_location().end.column + 1); + source_location().end.column + 1) + .c_str()); std::string new_indent = indent + std::string(6, ' '); - spdlog::debug("{} - context_expr", indent); + ::detail::log_debug(std::format("{} - context_expr", indent).c_str()); m_context_expr->print_node(new_indent); - spdlog::debug("{} - optional_vars: ", indent); + ::detail::log_debug(std::format("{} - optional_vars: ", indent).c_str()); if (m_optional_vars) { m_optional_vars->print_node(new_indent); } } void IfExpr::print_this_node(const std::string &indent) const { - spdlog::debug("{}IfExpr [{}:{}-{}:{}]", + ::detail::log_debug(std::format("{}IfExpr [{}:{}-{}:{}]", indent, source_location().start.row + 1, source_location().start.column + 1, source_location().end.row + 1, - source_location().end.column + 1); + source_location().end.column + 1) + .c_str()); std::string new_indent = indent + std::string(6, ' '); - spdlog::debug("{} - test", indent); + ::detail::log_debug(std::format("{} - test", indent).c_str()); m_test->print_node(new_indent); - spdlog::debug("{} - body", indent); + ::detail::log_debug(std::format("{} - body", indent).c_str()); m_body->print_node(new_indent); - spdlog::debug("{} - orelse", indent); + ::detail::log_debug(std::format("{} - orelse", indent).c_str()); m_orelse->print_node(new_indent); } void Starred::print_this_node(const std::string &indent) const { - spdlog::debug("{}Starred [{}:{}-{}:{}]", + ::detail::log_debug(std::format("{}Starred [{}:{}-{}:{}]", indent, source_location().start.row + 1, source_location().start.column + 1, source_location().end.row + 1, - source_location().end.column + 1); + source_location().end.column + 1) + .c_str()); std::string new_indent = indent + std::string(6, ' '); - spdlog::debug("{} - value", indent); + ::detail::log_debug(std::format("{} - value", indent).c_str()); m_value->print_node(new_indent); - spdlog::debug("{} - context: ", indent, m_ctx); + ::detail::log_debug(std::format("{} - context: {}", indent, static_cast(m_ctx)).c_str()); } void NamedExpr::print_this_node(const std::string &indent) const { - spdlog::debug("{}NamedExpr [{}:{}-{}:{}]", + ::detail::log_debug(std::format("{}NamedExpr [{}:{}-{}:{}]", indent, source_location().start.row + 1, source_location().start.column + 1, source_location().end.row + 1, - source_location().end.column + 1); + source_location().end.column + 1) + .c_str()); std::string new_indent = indent + std::string(6, ' '); - spdlog::debug("{} - target", indent); + ::detail::log_debug(std::format("{} - target", indent).c_str()); m_target->print_node(new_indent); - spdlog::debug("{} - value: ", indent); + ::detail::log_debug(std::format("{} - value: ", indent).c_str()); m_value->print_node(new_indent); } void JoinedStr::print_this_node(const std::string &indent) const { - spdlog::debug("{}JoinedStr", indent); + ::detail::log_debug(std::format("{}JoinedStr", indent).c_str()); std::string new_indent = indent + std::string(6, ' '); - spdlog::debug("{} - values: ", indent); + ::detail::log_debug(std::format("{} - values: ", indent).c_str()); for (const auto &v : m_values) { v->print_node(new_indent); } } void FormattedValue::print_this_node(const std::string &indent) const { - spdlog::debug("{}FormattedValue", indent); + ::detail::log_debug(std::format("{}FormattedValue", indent).c_str()); std::string new_indent = indent + std::string(6, ' '); - spdlog::debug("{} - value: ", indent); + ::detail::log_debug(std::format("{} - value: ", indent).c_str()); m_value->print_node(new_indent); - spdlog::debug("{} - conversion: ", indent, static_cast(m_conversion)); - spdlog::debug("{} - format_spec: ", indent); + ::detail::log_debug( + std::format("{} - conversion: ", indent, static_cast(m_conversion)).c_str()); + ::detail::log_debug(std::format("{} - format_spec: ", indent).c_str()); if (m_format_spec) m_format_spec->print_node(new_indent); } void Comprehension::print_this_node(const std::string &indent) const { - spdlog::debug("{}Comprehension", indent); + ::detail::log_debug(std::format("{}Comprehension", indent).c_str()); std::string new_indent = indent + std::string(6, ' '); - spdlog::debug("{} - target: ", indent); + ::detail::log_debug(std::format("{} - target: ", indent).c_str()); m_target->print_node(new_indent); - spdlog::debug("{} - iter: ", indent); + ::detail::log_debug(std::format("{} - iter: ", indent).c_str()); m_iter->print_node(new_indent); - spdlog::debug("{} - ifs: ", indent); + ::detail::log_debug(std::format("{} - ifs: ", indent).c_str()); for (const auto &if_ : m_ifs) { if_->print_node(new_indent); } - spdlog::debug("{} - is_async: {}", indent, m_is_async); + ::detail::log_debug(std::format("{} - is_async: {}", indent, m_is_async).c_str()); } void ListComp::print_this_node(const std::string &indent) const { - spdlog::debug("{}ListComp", indent); + ::detail::log_debug(std::format("{}ListComp", indent).c_str()); std::string new_indent = indent + std::string(6, ' '); - spdlog::debug("{} - elt: ", indent); + ::detail::log_debug(std::format("{} - elt: ", indent).c_str()); m_elt->print_node(new_indent); - spdlog::debug("{} - generators: ", indent); + ::detail::log_debug(std::format("{} - generators: ", indent).c_str()); for (const auto &generator : m_generators) { generator->print_node(new_indent); } } void DictComp::print_this_node(const std::string &indent) const { - spdlog::debug("{}DictComp", indent); + ::detail::log_debug(std::format("{}DictComp", indent).c_str()); std::string new_indent = indent + std::string(6, ' '); - spdlog::debug("{} - key: ", indent); + ::detail::log_debug(std::format("{} - key: ", indent).c_str()); m_key->print_node(new_indent); - spdlog::debug("{} - value: ", indent); + ::detail::log_debug(std::format("{} - value: ", indent).c_str()); m_value->print_node(new_indent); - spdlog::debug("{} - generators: ", indent); + ::detail::log_debug(std::format("{} - generators: ", indent).c_str()); for (const auto &generator : m_generators) { generator->print_node(new_indent); } } void GeneratorExp::print_this_node(const std::string &indent) const { - spdlog::debug("{}GeneratorExp", indent); + ::detail::log_debug(std::format("{}GeneratorExp", indent).c_str()); std::string new_indent = indent + std::string(6, ' '); - spdlog::debug("{} - elt: ", indent); + ::detail::log_debug(std::format("{} - elt: ", indent).c_str()); m_elt->print_node(new_indent); - spdlog::debug("{} - generators: ", indent); + ::detail::log_debug(std::format("{} - generators: ", indent).c_str()); for (const auto &generator : m_generators) { generator->print_node(new_indent); } } void SetComp::print_this_node(const std::string &indent) const { - spdlog::debug("{}SetComp", indent); + ::detail::log_debug(std::format("{}SetComp", indent).c_str()); std::string new_indent = indent + std::string(6, ' '); - spdlog::debug("{} - elt: ", indent); + ::detail::log_debug(std::format("{} - elt: ", indent).c_str()); m_elt->print_node(new_indent); - spdlog::debug("{} - generators: ", indent); + ::detail::log_debug(std::format("{} - generators: ", indent).c_str()); for (const auto &generator : m_generators) { generator->print_node(new_indent); } } }// namespace ast diff --git a/src/ast/AST.hpp b/src/ast/AST.cppm similarity index 93% rename from src/ast/AST.hpp rename to src/ast/AST.cppm index 313ee0c7..eebf3aa4 100644 --- a/src/ast/AST.hpp +++ b/src/ast/AST.cppm @@ -1,23 +1,17 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include +module; #include -#include "ast/ASTArena.hpp" -#include "forward.hpp" -#include "lexer/Lexer.hpp" -#include "utilities.hpp" +#include "ast/ASTNodeTypes.hpp" +#include "core.hpp" + +export module py.ast; -#include "spdlog/spdlog.h" +export import :arena; +import py.lexer; +import std; -struct SourceLocation +export struct SourceLocation { Position start; Position end; @@ -29,75 +23,8 @@ struct SourceLocation } }; -template<> struct fmt::formatter -{ - constexpr auto parse(format_parse_context &ctx) { return ctx.end(); } - - template auto format(const SourceLocation &sc, FormatContext &ctx) - { - return format_to(ctx.out(), "[{}-{}]", sc.start, sc.end); - } -}; - -namespace ast { - -#define AST_NODE_TYPES \ - __AST_NODE_TYPE(Argument) \ - __AST_NODE_TYPE(Arguments) \ - __AST_NODE_TYPE(Attribute) \ - __AST_NODE_TYPE(Assign) \ - __AST_NODE_TYPE(Assert) \ - __AST_NODE_TYPE(AsyncFunctionDefinition) \ - __AST_NODE_TYPE(Await) \ - __AST_NODE_TYPE(AugAssign) \ - __AST_NODE_TYPE(Break) \ - __AST_NODE_TYPE(BinaryExpr) \ - __AST_NODE_TYPE(BoolOp) \ - __AST_NODE_TYPE(Call) \ - __AST_NODE_TYPE(ClassDefinition) \ - __AST_NODE_TYPE(Continue) \ - __AST_NODE_TYPE(Compare) \ - __AST_NODE_TYPE(Comprehension) \ - __AST_NODE_TYPE(Constant) \ - __AST_NODE_TYPE(Delete) \ - __AST_NODE_TYPE(Dict) \ - __AST_NODE_TYPE(DictComp) \ - __AST_NODE_TYPE(ExceptHandler) \ - __AST_NODE_TYPE(Expression) \ - __AST_NODE_TYPE(For) \ - __AST_NODE_TYPE(FormattedValue) \ - __AST_NODE_TYPE(FunctionDefinition) \ - __AST_NODE_TYPE(GeneratorExp) \ - __AST_NODE_TYPE(Global) \ - __AST_NODE_TYPE(If) \ - __AST_NODE_TYPE(IfExpr) \ - __AST_NODE_TYPE(Import) \ - __AST_NODE_TYPE(ImportFrom) \ - __AST_NODE_TYPE(JoinedStr) \ - __AST_NODE_TYPE(Keyword) \ - __AST_NODE_TYPE(Lambda) \ - __AST_NODE_TYPE(List) \ - __AST_NODE_TYPE(ListComp) \ - __AST_NODE_TYPE(Module) \ - __AST_NODE_TYPE(NamedExpr) \ - __AST_NODE_TYPE(Name) \ - __AST_NODE_TYPE(NonLocal) \ - __AST_NODE_TYPE(Pass) \ - __AST_NODE_TYPE(Raise) \ - __AST_NODE_TYPE(Return) \ - __AST_NODE_TYPE(Set) \ - __AST_NODE_TYPE(SetComp) \ - __AST_NODE_TYPE(Starred) \ - __AST_NODE_TYPE(Subscript) \ - __AST_NODE_TYPE(Try) \ - __AST_NODE_TYPE(Tuple) \ - __AST_NODE_TYPE(UnaryExpr) \ - __AST_NODE_TYPE(While) \ - __AST_NODE_TYPE(With) \ - __AST_NODE_TYPE(WithItem) \ - __AST_NODE_TYPE(Yield) \ - __AST_NODE_TYPE(YieldFrom) +export namespace ast { class Value { @@ -135,24 +62,6 @@ enum class ContextType { LOAD = 0, STORE = 1, DELETE = 2, UNSET = 3 }; struct CodeGenerator; -class ASTContext -{ - std::stack m_local_args; - std::vector m_parent_nodes; - - public: - void push_local_args(const Arguments *args) { m_local_args.push(args); } - void pop_local_args() { m_local_args.pop(); } - - bool has_local_args() const { return !m_local_args.empty(); } - - void push_node(const ASTNode *node) { m_parent_nodes.push_back(node); } - void pop_node() { m_parent_nodes.pop_back(); } - - const Arguments *local_args() const { return m_local_args.top(); } - const std::vector &parent_nodes() const { return m_parent_nodes; } -}; - class ASTNode { const ASTNodeType m_node_type; @@ -173,7 +82,25 @@ class ASTNode const SourceLocation &source_location() const { return m_source_location; } virtual Value *codegen(CodeGenerator *) const = 0; -};// namespace ast +}; + +class ASTContext +{ + std::stack m_local_args; + std::vector m_parent_nodes; + + public: + void push_local_args(const Arguments *args) { m_local_args.push(args); } + void pop_local_args() { m_local_args.pop(); } + + bool has_local_args() const { return !m_local_args.empty(); } + + void push_node(const ASTNode *node) { m_parent_nodes.push_back(node); } + void pop_node() { m_parent_nodes.pop_back(); } + + const Arguments *local_args() const { return m_local_args.top(); } + const std::vector &parent_nodes() const { return m_parent_nodes; } +}; class Expression : public ASTNode { @@ -191,23 +118,45 @@ class Expression : public ASTNode void print_this_node(const std::string &indent) const override; }; + +// std::vector rather than py::Bytes: the AST deliberately does not +// depend on the runtime's value representation, so a bytes literal is carried +// as raw bytes and converted in codegen. +// Python's `...`. std::monostate already stands for None, so Ellipsis needs +// its own alternative. +struct EllipsisType +{ + bool operator==(const EllipsisType &) const = default; +}; + +using Bytes = std::vector; +using Literal = std::variant; + class Constant : public ASTNode { - std::unique_ptr m_value; + Literal m_value; private: void print_this_node(const std::string &indent) const override; public: Constant(double value, SourceLocation source_location); - Constant(int64_t value, SourceLocation source_location); + Constant(std::int64_t value, SourceLocation source_location); Constant(mpz_class value, SourceLocation source_location); Constant(bool value, SourceLocation source_location); Constant(std::string value, SourceLocation source_location); Constant(const char *value, SourceLocation source_location); - Constant(const py::Value &, SourceLocation source_location); + Constant(Bytes value, SourceLocation source_location); + Constant(const Literal &, SourceLocation source_location); - const py::Value *value() const { return m_value.get(); } + const Literal &value() const { return m_value; } Value *codegen(CodeGenerator *) const override; }; @@ -1093,19 +1042,19 @@ class Import : public ImportBase class ImportFrom : public ImportBase { std::string m_module; - size_t m_level{ 0 }; + std::size_t m_level{ 0 }; public: ImportFrom(std::string module, std::vector &&names, - size_t level, + std::size_t level, SourceLocation source_location) : ImportBase(ASTNodeType::ImportFrom, std::move(names), source_location), m_module(std::move(module)), m_level(level) {} const std::string &module() const { return m_module; } - size_t level() const { return m_level; } + std::size_t level() const { return m_level; } Value *codegen(CodeGenerator *) const override; diff --git a/src/ast/ASTArena.cpp b/src/ast/ASTArena.cpp index 0a07a378..d56339dc 100644 --- a/src/ast/ASTArena.cpp +++ b/src/ast/ASTArena.cpp @@ -1,30 +1,25 @@ -#include "ast/ASTArena.hpp" +module; +#include "core.hpp" +#include "memory/allocate.hpp" -#include -#include +module py.ast; namespace ast { - ASTArena::ASTArena() : m_next_slab_size(kInitialSlabSize) {} - ASTArena::~ASTArena() { for (auto it = m_destructors.rbegin(); it != m_destructors.rend(); ++it) { it->fn(it->object); } } - void ASTArena::grow(std::size_t at_least) { std::size_t size = std::max(m_next_slab_size, at_least); m_slabs.push_back(Slab{ std::make_unique(size), size, 0 }); m_next_slab_size = size * 2; } - void *ASTArena::allocate(std::size_t size, std::size_t alignment) { ASSERT(alignment > 0 && (alignment & (alignment - 1)) == 0); - if (m_slabs.empty()) { grow(size + alignment); } - for (;;) { Slab &slab = m_slabs.back(); auto base = reinterpret_cast(slab.data.get()) + slab.used; @@ -37,12 +32,10 @@ void *ASTArena::allocate(std::size_t size, std::size_t alignment) grow(size + alignment); } } - std::size_t ASTArena::bytes_allocated() const { std::size_t total = 0; for (const auto &slab : m_slabs) { total += slab.used; } return total; } - -}// namespace ast +}// namespace ast \ No newline at end of file diff --git a/src/ast/ASTArena.hpp b/src/ast/ASTArena.cppm similarity index 88% rename from src/ast/ASTArena.hpp rename to src/ast/ASTArena.cppm index 87f87d57..d5abbf0a 100644 --- a/src/ast/ASTArena.hpp +++ b/src/ast/ASTArena.cppm @@ -1,14 +1,11 @@ -#pragma once +module; -#include "utilities.hpp" +#include "core.hpp" -#include -#include -#include -#include -#include +export module py.ast:arena; +import std; -namespace ast { +export namespace ast { // Bump-pointer allocator with destructor tracking, owned by the Module. // diff --git a/src/ast/ASTArena_tests.cpp b/src/ast/ASTArena_tests.cpp index b7059c9c..c82c6337 100644 --- a/src/ast/ASTArena_tests.cpp +++ b/src/ast/ASTArena_tests.cpp @@ -1,10 +1,11 @@ -#include "ast/ASTArena.hpp" #include "gtest/gtest.h" #include #include -#include + +import py.ast; +import std; namespace { diff --git a/src/ast/ASTNodeTypes.hpp b/src/ast/ASTNodeTypes.hpp new file mode 100644 index 00000000..5cbef7cc --- /dev/null +++ b/src/ast/ASTNodeTypes.hpp @@ -0,0 +1,66 @@ +#pragma once + +// The AST node-type X-macro list. +// +// This lives in a plain header rather than in the py.ast module because macros +// are never exported by a module: every consumer that expands AST_NODE_TYPES to +// generate visitor declarations (MLIRGenerator.hpp, VariablesResolver.cppm, +// AST.cpp, ...) has to #include it directly. py.ast includes it in its global +// module fragment for the same reason. + +#define AST_NODE_TYPES \ + __AST_NODE_TYPE(Argument) \ + __AST_NODE_TYPE(Arguments) \ + __AST_NODE_TYPE(Attribute) \ + __AST_NODE_TYPE(Assign) \ + __AST_NODE_TYPE(Assert) \ + __AST_NODE_TYPE(AsyncFunctionDefinition) \ + __AST_NODE_TYPE(Await) \ + __AST_NODE_TYPE(AugAssign) \ + __AST_NODE_TYPE(Break) \ + __AST_NODE_TYPE(BinaryExpr) \ + __AST_NODE_TYPE(BoolOp) \ + __AST_NODE_TYPE(Call) \ + __AST_NODE_TYPE(ClassDefinition) \ + __AST_NODE_TYPE(Continue) \ + __AST_NODE_TYPE(Compare) \ + __AST_NODE_TYPE(Comprehension) \ + __AST_NODE_TYPE(Constant) \ + __AST_NODE_TYPE(Delete) \ + __AST_NODE_TYPE(Dict) \ + __AST_NODE_TYPE(DictComp) \ + __AST_NODE_TYPE(ExceptHandler) \ + __AST_NODE_TYPE(Expression) \ + __AST_NODE_TYPE(For) \ + __AST_NODE_TYPE(FormattedValue) \ + __AST_NODE_TYPE(FunctionDefinition) \ + __AST_NODE_TYPE(GeneratorExp) \ + __AST_NODE_TYPE(Global) \ + __AST_NODE_TYPE(If) \ + __AST_NODE_TYPE(IfExpr) \ + __AST_NODE_TYPE(Import) \ + __AST_NODE_TYPE(ImportFrom) \ + __AST_NODE_TYPE(JoinedStr) \ + __AST_NODE_TYPE(Keyword) \ + __AST_NODE_TYPE(Lambda) \ + __AST_NODE_TYPE(List) \ + __AST_NODE_TYPE(ListComp) \ + __AST_NODE_TYPE(Module) \ + __AST_NODE_TYPE(NamedExpr) \ + __AST_NODE_TYPE(Name) \ + __AST_NODE_TYPE(NonLocal) \ + __AST_NODE_TYPE(Pass) \ + __AST_NODE_TYPE(Raise) \ + __AST_NODE_TYPE(Return) \ + __AST_NODE_TYPE(Set) \ + __AST_NODE_TYPE(SetComp) \ + __AST_NODE_TYPE(Starred) \ + __AST_NODE_TYPE(Subscript) \ + __AST_NODE_TYPE(Try) \ + __AST_NODE_TYPE(Tuple) \ + __AST_NODE_TYPE(UnaryExpr) \ + __AST_NODE_TYPE(While) \ + __AST_NODE_TYPE(With) \ + __AST_NODE_TYPE(WithItem) \ + __AST_NODE_TYPE(Yield) \ + __AST_NODE_TYPE(YieldFrom) diff --git a/src/ast/SourceLocationFormatter.hpp b/src/ast/SourceLocationFormatter.hpp new file mode 100644 index 00000000..406a34a6 --- /dev/null +++ b/src/ast/SourceLocationFormatter.hpp @@ -0,0 +1,16 @@ +#pragma once + +// fmt formatting for ast::SourceLocation. Kept out of the py.ast module for the +// same reason as PositionFormatter.hpp: spdlog/fmt/fmt.h drags 231 libstdc++ +// headers into the BMI, which then collide with consumers' own #includes. + + +template<> struct std::formatter +{ + constexpr auto parse(std::format_parse_context &ctx) { return ctx.end(); } + + template auto format(const SourceLocation &sc, FormatContext &ctx) const + { + return std::format_to(ctx.out(), "[{}-{}]", sc.start, sc.end); + } +}; diff --git a/src/ast/optimizers/ConstantFolding.cpp b/src/ast/optimizers/ConstantFolding.cpp index f9a531b7..92bd8d70 100644 --- a/src/ast/optimizers/ConstantFolding.cpp +++ b/src/ast/optimizers/ConstantFolding.cpp @@ -1,5 +1,9 @@ -#include "ConstantFolding.hpp" -#include "runtime/Value.hpp" +module; +#include "core.hpp" + +module py.codegen; +import std; +import py.ast; namespace ast { namespace optimizer { diff --git a/src/ast/optimizers/ConstantFolding.hpp b/src/ast/optimizers/ConstantFolding.hpp deleted file mode 100644 index 34edf279..00000000 --- a/src/ast/optimizers/ConstantFolding.hpp +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include "ast/AST.hpp" - -namespace ast { -namespace optimizer { - - std::shared_ptr constant_folding(std::shared_ptr node); - -}// namespace optimizer -}// namespace ast \ No newline at end of file diff --git a/src/ast/optimizers/Optimizers_tests.cpp b/src/ast/optimizers/Optimizers_tests.cpp index 824d1461..b580b41d 100644 --- a/src/ast/optimizers/Optimizers_tests.cpp +++ b/src/ast/optimizers/Optimizers_tests.cpp @@ -1,12 +1,9 @@ -#include "ConstantFolding.hpp" -#include "ast/AST.hpp" -#include "executable/Program.hpp" -#include "parser/Parser.hpp" -#include "runtime/Value.hpp" -#include "utilities.hpp" - #include "gtest/gtest.h" +import py.lexer; +import py.ast; +import py.runtime; + using namespace ast; using namespace py; diff --git a/src/core.cpp b/src/core.cpp new file mode 100644 index 00000000..c743f3e6 --- /dev/null +++ b/src/core.cpp @@ -0,0 +1,21 @@ +#include "core.hpp" + +#include "spdlog/spdlog.h" + +#include + +namespace detail { +void assertion_failed(const char *what, const char *file, int line) +{ + spdlog::error("{} {}:{}", what, file, line); + std::abort(); +} + +void log_debug(const char *message) { spdlog::debug("{}", message); } +void log_trace(const char *message) { spdlog::trace("{}", message); } +void log_error(const char *message) { spdlog::error("{}", message); } + +// Lets callers skip formatting entirely when debug logging is off - the +// spdlog::debug("...", args) form did that for free. +bool log_debug_enabled() { return spdlog::should_log(spdlog::level::debug); } +}// namespace detail diff --git a/src/core.hpp b/src/core.hpp new file mode 100644 index 00000000..c1c95c89 --- /dev/null +++ b/src/core.hpp @@ -0,0 +1,63 @@ +#pragma once + +// Diagnostics macros and the two empty base classes, with no libstdc++ and no +// spdlog behind them. +// +// This header exists to be safe inside a module's global module fragment. +// Macros are never exported by a module, so any module unit that uses TODO() or +// ASSERT() has to #include them textually - and utilities.hpp, which used to be +// that include, drags in 272 libstdc++ headers through spdlog. Those headers +// then land in the module's BMI and collide with the same headers #included by +// its consumers ("redefinition of ...", "conflicting declaration of template +// ..."). Routing the macros through an out-of-line failure function keeps the +// formatting - and therefore spdlog - in core.cpp where it costs nothing. + +namespace detail { +// Defined in core.cpp; reports through spdlog and aborts. +[[noreturn]] void assertion_failed(const char *what, const char *file, int line); + +// Logging sinks. Module units cannot #include spdlog in their global module +// fragment - its libstdc++ headers land in the BMI and collide with the +// `import std;` the module interfaces use - so they format with std::format and +// pass the finished string through here. +void log_debug(const char *message); +void log_trace(const char *message); +void log_error(const char *message); +bool log_debug_enabled(); +}// namespace detail + +#define TODO() ::detail::assertion_failed("Not implemented", __FILE__, __LINE__) + +#define ASSERT(condition) \ + do { \ + if (!(condition)) { \ + ::detail::assertion_failed("Assertion failed " #condition, __FILE__, __LINE__); \ + } \ + } while (0) + +#define ASSERT_NOT_REACHED() \ + ::detail::assertion_failed("Reached unexpected line", __FILE__, __LINE__) + +// Pure templates, no spdlog behind them - safe in a module GMF. +template struct overloaded : Ts... +{ + using Ts::operator()...; +}; +// explicit deduction guide (not needed as of C++20) +template overloaded(Ts...) -> overloaded; + +using Register = __UINT8_TYPE__; + +struct NonCopyable +{ + NonCopyable() = default; + NonCopyable(const NonCopyable &) = delete; + NonCopyable &operator=(const NonCopyable &) = delete; +}; + +struct NonMoveable +{ + NonMoveable() = default; + NonMoveable(NonMoveable &&) = delete; + NonMoveable &operator=(NonMoveable &&) = delete; +}; diff --git a/src/executable/CodeFlags.hpp b/src/executable/CodeFlags.hpp new file mode 100644 index 00000000..8794b0b5 --- /dev/null +++ b/src/executable/CodeFlags.hpp @@ -0,0 +1,46 @@ +#pragma once +#include +#include + + +class CodeFlags +{ + public: + enum class Flag { + OPTIMIZED = 0, + NEWLOCALS = 1, + VARARGS = 2, + VARKEYWORDS = 3, + NESTED = 4, + GENERATOR = 5, + COROUTINE = 6, + CLASS = 7, + }; + + private: + std::bitset<8> m_flags; + + CodeFlags() = default; + + public: + template + // requires std::conjunction_v...> + static CodeFlags create(Args... args) + { + CodeFlags f; + (f.m_flags.set(static_cast(args)), ...); + return f; + } + + static CodeFlags from_byte(std::uint8_t b) + { + auto f = CodeFlags(); + f.m_flags = std::bitset<8>(b); + return f; + } + + void set(Flag f) { m_flags.set(static_cast(f)); } + void reset(Flag f) { m_flags.reset(static_cast(f)); } + bool is_set(Flag f) const { return m_flags[static_cast(f)]; } + std::bitset<8> bits() const { return m_flags; } +}; diff --git a/src/executable/Function.hpp b/src/executable/Function.cppm similarity index 60% rename from src/executable/Function.hpp rename to src/executable/Function.cppm index 89000db7..e9ac6789 100644 --- a/src/executable/Function.hpp +++ b/src/executable/Function.cppm @@ -1,23 +1,35 @@ -#pragma once +module; -#include "FunctionBlock.hpp" +#include "core.hpp" +#include +#include + +export module py.runtime:executable_function; +import :value; +import std; + +export class Program; + +export class VirtualMachine; enum class FunctionExecutionBackend { BYTECODE = 0, LLVM = 1 }; +export class Interpreter; + class Function : NonCopyable { protected: - size_t m_register_count; - size_t m_locals_count; - size_t m_stack_size; + std::size_t m_register_count; + std::size_t m_locals_count; + std::size_t m_stack_size; std::string m_function_name; FunctionExecutionBackend m_backend; std::shared_ptr m_program; public: - Function(size_t register_count, - size_t locals_count, - size_t stack_size, + Function(std::size_t register_count, + std::size_t locals_count, + std::size_t stack_size, std::string function_name, FunctionExecutionBackend backend, std::shared_ptr program) @@ -26,9 +38,9 @@ class Function : NonCopyable {} virtual ~Function() = default; - size_t register_count() const { return m_register_count; } - size_t locals_count() const { return m_locals_count; } - size_t stack_size() const { return m_stack_size; } + std::size_t register_count() const { return m_register_count; } + std::size_t locals_count() const { return m_locals_count; } + std::size_t stack_size() const { return m_stack_size; } FunctionExecutionBackend backend() const { return m_backend; } @@ -36,10 +48,10 @@ class Function : NonCopyable virtual std::string to_string() const = 0; - virtual std::vector serialize() const = 0; + virtual std::vector serialize() const = 0; std::shared_ptr program() const { return m_program; } virtual py::PyResult call(VirtualMachine &, Interpreter &) const = 0; virtual py::PyResult call_without_setup(VirtualMachine &, Interpreter &) const = 0; -}; \ No newline at end of file +}; diff --git a/src/executable/FunctionBlock.cppm b/src/executable/FunctionBlock.cppm new file mode 100644 index 00000000..62e79210 --- /dev/null +++ b/src/executable/FunctionBlock.cppm @@ -0,0 +1,54 @@ +module; + +#include "CodeFlags.hpp" + +export module py.runtime:executable_functionblock; +import :value; +import std; + +export class Instruction; + + +export using InstructionVector = std::vector>; + +export struct InstructionSourceLocation +{ + std::uint32_t instruction_index; + std::uint32_t line; + std::uint32_t column; +}; + +export struct FunctionMetaData +{ + std::string function_name; + std::size_t register_count{ 0 }; + std::size_t stack_size{ 0 }; + std::vector cellvars; + std::vector varnames; + std::vector freevars; + std::vector names; + std::string filename; + std::size_t first_line_number; + std::size_t arg_count; + std::size_t positional_arg_count; + std::size_t kwonly_arg_count; + std::size_t nlocals; + std::vector cell2arg; + std::vector consts; + CodeFlags flags = CodeFlags::create(); +}; + +export struct FunctionBlock +{ + FunctionMetaData metadata; + InstructionVector blocks; + std::vector instruction_locations; + std::string to_string() const; +}; + +export struct FunctionBlocks +{ + std::list functions; + + using FunctionType = decltype(functions)::value_type; +}; diff --git a/src/executable/FunctionBlock.hpp b/src/executable/FunctionBlock.hpp deleted file mode 100644 index 5e089960..00000000 --- a/src/executable/FunctionBlock.hpp +++ /dev/null @@ -1,53 +0,0 @@ -#pragma once - -#include "Program.hpp" -#include "forward.hpp" -#include -#include -#include -#include -#include - -using InstructionVector = std::vector>; - -struct InstructionSourceLocation -{ - uint32_t instruction_index; - uint32_t line; - uint32_t column; -}; - -struct FunctionMetaData -{ - std::string function_name; - size_t register_count{ 0 }; - size_t stack_size{ 0 }; - std::vector cellvars; - std::vector varnames; - std::vector freevars; - std::vector names; - std::string filename; - size_t first_line_number; - size_t arg_count; - size_t positional_arg_count; - size_t kwonly_arg_count; - size_t nlocals; - std::vector cell2arg; - std::vector consts; - CodeFlags flags = CodeFlags::create(); -}; - -struct FunctionBlock -{ - FunctionMetaData metadata; - InstructionVector blocks; - std::vector instruction_locations; - std::string to_string() const; -}; - -struct FunctionBlocks -{ - std::list functions; - - using FunctionType = decltype(functions)::value_type; -}; diff --git a/src/executable/Label.hpp b/src/executable/Label.hpp index ed1c6757..c1da2334 100644 --- a/src/executable/Label.hpp +++ b/src/executable/Label.hpp @@ -1,54 +1,51 @@ #pragma once - -#include "utilities.hpp" - +#include +#include #include #include -namespace codegen { -class BytecodeGenerator; -class PythonBytecodeEmitter; -}// namespace codegen +#include "core.hpp" + class Label : NonCopyable , NonMoveable { - friend codegen::BytecodeGenerator; - friend codegen::PythonBytecodeEmitter; - std::string m_label_name; - size_t m_function_id; - mutable std::optional m_position; + std::size_t m_function_id; + mutable std::optional m_position; - protected: - void set_position(int64_t position) const + public: + // Public rather than protected + friend: the two users (BytecodeGenerator, + // PythonBytecodeEmitter) live in py.codegen, and naming them here would + // declare them in the global module. + void set_position(std::int64_t position) const { ASSERT(!m_position.has_value()); m_position = position; } public: - Label(std::string name, size_t function_id) + Label(std::string name, std::size_t function_id) : m_label_name(std::move(name)), m_function_id(function_id) {} - Label(int64_t position) : m_position(position) {} + Label(std::int64_t position) : m_position(position) {} - int64_t position() const + std::int64_t position() const { ASSERT(m_position.has_value()); return *m_position; } - size_t function_id() const { return m_function_id; } + std::size_t function_id() const { return m_function_id; } const std::string &name() const { return m_label_name; } - size_t hash() const + std::size_t hash() const { - size_t seed = std::hash{}(m_label_name); - seed ^= std::hash{}(m_function_id) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + std::size_t seed = std::hash{}(m_label_name); + seed ^= std::hash{}(m_function_id) + 0x9e3779b9 + (seed << 6) + (seed >> 2); return seed; } diff --git a/src/executable/Mangler.cpp b/src/executable/Mangler.cpp index b46b50b4..7ad7a6b6 100644 --- a/src/executable/Mangler.cpp +++ b/src/executable/Mangler.cpp @@ -1,8 +1,9 @@ -#include "Mangler.hpp" +module; +#include "core.hpp" -#include "ast/AST.hpp" - -#include +module py.runtime; +import std; +import py.ast; class DefaultMangler : public Mangler { @@ -11,7 +12,7 @@ class DefaultMangler : public Mangler const std::string &function_name, const SourceLocation &source_location) const override { - return fmt::format("{}.{}.{}:{}", + return std::format("{}.{}.{}:{}", module, function_name, source_location.start.row, @@ -22,7 +23,7 @@ class DefaultMangler : public Mangler const std::string &class_name, const SourceLocation &source_location) const override { - return fmt::format("{}.__class__{}__.{}:{}", + return std::format("{}.__class__{}__.{}:{}", module, class_name, source_location.start.row, diff --git a/src/executable/Mangler.hpp b/src/executable/Mangler.cppm similarity index 86% rename from src/executable/Mangler.hpp rename to src/executable/Mangler.cppm index 987b44bc..81c13628 100644 --- a/src/executable/Mangler.hpp +++ b/src/executable/Mangler.cppm @@ -1,10 +1,9 @@ -#pragma once +export module py.runtime:mangler; -#include +import std; +import py.ast; -struct SourceLocation; - -class Mangler +export class Mangler { public: virtual ~Mangler() = default; @@ -22,4 +21,4 @@ class Mangler virtual std::string class_demangle(const std::string &mangled_name) const = 0; static Mangler &default_mangler(); -}; \ No newline at end of file +}; diff --git a/src/executable/Program.cpp b/src/executable/Program.cpp index 2e64f33c..6a92071c 100644 --- a/src/executable/Program.cpp +++ b/src/executable/Program.cpp @@ -1,10 +1,22 @@ -#include "Program.hpp" -#include "executable/bytecode/codegen/BytecodeGenerator.hpp" +module; +#include + +#include "core.hpp" +#include "executable/common.hpp" + +module py.runtime; +import py.ast; +import py.codegen; +import std; + +// These name py:: types, so they belong in the purview where the implicit +// import of py.runtime has already happened. Including LLVMGenerator.hpp +// unconditionally would attach codegen::LLVMGenerator to py.runtime and pull +// its virtual members into the vtable even though the backend is not built. +#if defined(ENABLE_LLVM_BACKEND) && defined(LLVM_FOUND) #include "executable/llvm/LLVMGenerator.hpp" -#include "executable/mlir/Dialect/Python/MLIRGenerator.hpp" +#endif #include "mlir/compile.hpp" -#include "utilities.hpp" - Program::Program(std::string &&filename, std::vector &&argv) : m_filename(std::move(filename)), m_argv(std::move(argv)) @@ -34,4 +46,4 @@ std::shared_ptr compile(std::shared_ptr node, } ASSERT_NOT_REACHED(); } -}// namespace compiler \ No newline at end of file +}// namespace compiler diff --git a/src/executable/Program.cppm b/src/executable/Program.cppm new file mode 100644 index 00000000..713c638f --- /dev/null +++ b/src/executable/Program.cppm @@ -0,0 +1,59 @@ +module; + +#include "common.hpp" +#include "core.hpp" +#include "executable/CodeFlags.hpp" + +export module py.runtime:executable_program; +import :object; +import std; +import py.ast; + +export namespace py { +struct Number; +class PyTuple; +}// namespace py + +export class VirtualMachine; + +export class Program + : NonCopyable + , public std::enable_shared_from_this +{ + std::string m_filename; + std::vector m_argv; + + protected: + Program() {} + + public: + Program(std::string &&filename, std::vector &&argv); + virtual ~Program() {} + + virtual int execute(VirtualMachine *) = 0; + + const std::string &filename() const { return m_filename; } + const std::vector &argv() const { return m_argv; } + + void set_filename(std::string filename) { m_filename = std::move(filename); } + + virtual std::string to_string() const = 0; + + virtual py::PyObject *as_pyfunction(const std::string &function_name, + const std::vector &default_values, + const std::vector &kw_default_values, + py::PyTuple *closure) const = 0; + + virtual py::PyObject *main_function() = 0; + + virtual void visit_functions(Cell::Visitor &) const = 0; + + virtual std::vector serialize() const = 0; +}; + +export namespace compiler { +std::shared_ptr compile(std::shared_ptr node, + std::vector argv, + Backend backend, + OptimizationLevel lvl); +} diff --git a/src/executable/Program.hpp b/src/executable/Program.hpp deleted file mode 100644 index 7d721ae5..00000000 --- a/src/executable/Program.hpp +++ /dev/null @@ -1,97 +0,0 @@ -#pragma once - -#include "common.hpp" -#include "forward.hpp" -#include "memory/GarbageCollector.hpp" -#include "runtime/forward.hpp" -#include "utilities.hpp" - -#include - -class Function; -class VirtualMachine; - - -class CodeFlags -{ - public: - enum class Flag { - OPTIMIZED = 0, - NEWLOCALS = 1, - VARARGS = 2, - VARKEYWORDS = 3, - NESTED = 4, - GENERATOR = 5, - COROUTINE = 6, - CLASS = 7, - }; - - private: - std::bitset<8> m_flags; - - CodeFlags() = default; - - public: - template - // requires std::conjunction_v...> - static CodeFlags create(Args... args) - { - CodeFlags f; - (f.m_flags.set(static_cast(args)), ...); - return f; - } - - static CodeFlags from_byte(uint8_t b) - { - auto f = CodeFlags(); - f.m_flags = std::bitset<8>(b); - return f; - } - - void set(Flag f) { m_flags.set(static_cast(f)); } - void reset(Flag f) { m_flags.reset(static_cast(f)); } - bool is_set(Flag f) const { return m_flags[static_cast(f)]; } - std::bitset<8> bits() const { return m_flags; } -}; - -class Program - : NonCopyable - , public std::enable_shared_from_this -{ - std::string m_filename; - std::vector m_argv; - - protected: - Program() {} - - public: - Program(std::string &&filename, std::vector &&argv); - virtual ~Program() {} - - virtual int execute(VirtualMachine *) = 0; - - const std::string &filename() const { return m_filename; } - const std::vector &argv() const { return m_argv; } - - void set_filename(std::string filename) { m_filename = std::move(filename); } - - virtual std::string to_string() const = 0; - - virtual py::PyObject *as_pyfunction(const std::string &function_name, - const std::vector &default_values, - const std::vector &kw_default_values, - py::PyTuple *closure) const = 0; - - virtual py::PyObject *main_function() = 0; - - virtual void visit_functions(Cell::Visitor &) const = 0; - - virtual std::vector serialize() const = 0; -}; - -namespace compiler { -std::shared_ptr compile(std::shared_ptr node, - std::vector argv, - Backend backend, - OptimizationLevel lvl); -} \ No newline at end of file diff --git a/src/executable/bytecode/Bytecode.cpp b/src/executable/bytecode/Bytecode.cpp index 80246ae3..255f7ec8 100644 --- a/src/executable/bytecode/Bytecode.cpp +++ b/src/executable/bytecode/Bytecode.cpp @@ -1,23 +1,27 @@ -#include "Bytecode.hpp" -#include "ast/AST.hpp" -#include "executable/FunctionBlock.hpp" -#include "instructions/Instructions.hpp" -#include "interpreter/Interpreter.hpp" -#include "runtime/BaseException.hpp" -#include "runtime/PyFrame.hpp" -#include "runtime/PyModule.hpp" -#include "runtime/PyTraceback.hpp" +module; +#include +#include + +#include "core.hpp" + +module py.runtime; +import py.ast; +import std; + +// After the module declaration and its imports: these name module-owned types. #include "serialization/deserialize.hpp" #include "serialization/serialize.hpp" -#include -#include +// Out of line so that ~unique_ptr instantiates here, where +// Instructions.hpp is included, rather than in the module interface. +Bytecode::~Bytecode() = default; + using namespace py; -Bytecode::Bytecode(size_t register_count, - size_t locals_count, - size_t stack_size, +Bytecode::Bytecode(std::size_t register_count, + std::size_t locals_count, + std::size_t stack_size, std::string function_name, InstructionVector instructions, std::vector instruction_locations, @@ -32,14 +36,14 @@ Bytecode::Bytecode(size_t register_count, m_instruction_locations(std::move(instruction_locations)) {} -std::optional Bytecode::location_for(size_t instruction_index) const +std::optional Bytecode::location_for(std::size_t instruction_index) const { if (m_instruction_locations.empty()) { return std::nullopt; } // Find the last entry whose instruction_index is <= the query. const auto it = std::upper_bound(m_instruction_locations.begin(), m_instruction_locations.end(), instruction_index, - [](size_t idx, const InstructionSourceLocation &entry) { + [](std::size_t idx, const InstructionSourceLocation &entry) { return idx < entry.instruction_index; }); if (it == m_instruction_locations.begin()) { return std::nullopt; } @@ -50,23 +54,23 @@ std::string Bytecode::to_string() const { std::ostringstream os; for (const auto &ins : m_instructions) { - os << fmt::format(" {} {}", (void *)ins.get(), ins->to_string()) << '\n'; + os << std::format(" {} {}", (void *)ins.get(), ins->to_string()) << '\n'; } return os.str(); } -std::vector Bytecode::serialize() const +std::vector Bytecode::serialize() const { - std::vector result; + std::vector result; py::serialize(m_register_count, result); py::serialize(m_locals_count, result); py::serialize(m_stack_size, result); py::serialize(m_function_name, result); - py::serialize(static_cast(m_backend), result); + py::serialize(static_cast(m_backend), result); - const size_t instruction_count = m_instructions.size(); + const std::size_t instruction_count = m_instructions.size(); py::serialize(instruction_count, result); for (const auto &ins : m_instructions) { @@ -77,20 +81,21 @@ std::vector Bytecode::serialize() const return result; } -std::unique_ptr Bytecode::deserialize(std::span &buffer, +std::unique_ptr Bytecode::deserialize(std::span &buffer, std::shared_ptr program) { - const auto register_count = py::deserialize(buffer); - const auto locals_count = py::deserialize(buffer); - const auto stack_size = py::deserialize(buffer); + const auto register_count = py::deserialize(buffer); + const auto locals_count = py::deserialize(buffer); + const auto stack_size = py::deserialize(buffer); const auto function_name = py::deserialize(buffer); - const auto backend = static_cast(py::deserialize(buffer)); + const auto backend = + static_cast(py::deserialize(buffer)); (void)backend; InstructionVector instructions; - const auto instruction_count = py::deserialize(buffer); + const auto instruction_count = py::deserialize(buffer); - for (size_t i = 0; i < instruction_count; ++i) { + for (std::size_t i = 0; i < instruction_count; ++i) { auto instruction = ::deserialize(buffer); if (!instruction) { for (const auto &ins : instructions) { std::cout << ins->to_string() << '\n'; } @@ -154,8 +159,9 @@ py::PyResult Bytecode::eval_loop(VirtualMachine &vm, Interpreter &int ASSERT((*vm.instruction_pointer()).get()); const auto ¤t_ip = vm.instruction_pointer(); const auto &instruction = *current_ip; - // spdlog::debug("{} {}", (void *)instruction.get(), instruction->to_string()); - // std::cout << std::format("{} {}", (void *)instruction.get(), instruction->to_string()) + // ::detail::log_debug(std::format("{} {}", (void *)instruction.get(), + // instruction->to_string()).c_str()); std::cout << std::format("{} {}", (void + // *)instruction.get(), instruction->to_string()) // << std::endl; auto result = instruction->execute(vm, vm.interpreter()); // we left the current stack frame in the previous instruction @@ -166,8 +172,8 @@ py::PyResult Bytecode::eval_loop(VirtualMachine &vm, Interpreter &int // vm.dump(); if (result.is_err()) { auto *exception = result.unwrap_err(); - const size_t tb_lasti = std::distance(initial_ip, current_ip); - const size_t tb_lineno = + const std::size_t tb_lasti = std::distance(initial_ip, current_ip); + const std::size_t tb_lineno = location_for(tb_lasti).value_or(InstructionSourceLocation{ 0, 0, 0 }).line; PyTraceback *tb_next = exception->traceback(); auto traceback = diff --git a/src/executable/bytecode/Bytecode.hpp b/src/executable/bytecode/Bytecode.cppm similarity index 56% rename from src/executable/bytecode/Bytecode.hpp rename to src/executable/bytecode/Bytecode.cppm index 06c6f6db..9ac77f4e 100644 --- a/src/executable/bytecode/Bytecode.hpp +++ b/src/executable/bytecode/Bytecode.cppm @@ -1,41 +1,39 @@ -#pragma once +export module py.runtime:bytecode; +import :value; +import :executable_function; +import :executable_program; +import :executable_functionblock; +import std; -#include "codegen/BytecodeGenerator.hpp" -#include "executable/Function.hpp" -#include "executable/FunctionBlock.hpp" +export class VirtualMachine; -#include "forward.hpp" -#include -#include -#include -#include -#include - -class Bytecode : public Function +export class Bytecode : public Function { const InstructionVector m_instructions; const std::vector m_instruction_locations; public: - Bytecode(size_t register_count, - size_t locals_count, - size_t stack_size, + Bytecode(std::size_t register_count, + std::size_t locals_count, + std::size_t stack_size, std::string function_name, InstructionVector instructions, std::vector instruction_locations, std::shared_ptr program); + ~Bytecode() override; + auto begin() const { return m_instructions.begin(); } auto end() const { return m_instructions.end(); } - std::optional location_for(size_t instruction_index) const; + std::optional location_for(std::size_t instruction_index) const; std::string to_string() const override; - std::vector serialize() const override; + std::vector serialize() const override; - static std::unique_ptr deserialize(std::span &buffer, + static std::unique_ptr deserialize(std::span &buffer, std::shared_ptr program); py::PyResult call(VirtualMachine &, Interpreter &) const override; diff --git a/src/executable/bytecode/BytecodeProgram.cpp b/src/executable/bytecode/BytecodeProgram.cpp index 29e54edd..b1a414db 100644 --- a/src/executable/bytecode/BytecodeProgram.cpp +++ b/src/executable/bytecode/BytecodeProgram.cpp @@ -1,15 +1,15 @@ -#include "BytecodeProgram.hpp" -#include "Bytecode.hpp" -#include "executable/Function.hpp" -#include "executable/Mangler.hpp" -#include "interpreter/Interpreter.hpp" -#include "runtime/PyCode.hpp" -#include "runtime/PyFrame.hpp" -#include "runtime/PyFunction.hpp" -#include "runtime/PyTraceback.hpp" -#include "runtime/PyTuple.hpp" - -#include +module; +#include "core.hpp" + +#include +#include +#include + +module py.runtime; +import py.ast; +import py.codegen; +import std; + using namespace py; @@ -227,16 +227,18 @@ std::shared_ptr BytecodeProgram::deserialize(const std::vector< auto deserialized_result = PyCode::deserialize(span, program); ASSERT(deserialized_result.first.is_ok()); program->m_main_function = deserialized_result.first.unwrap(); - spdlog::debug( - "Deserialized main function:\n{}\n\n", program->m_main_function->function()->to_string()); + ::detail::log_debug(std::format( + "Deserialized main function:\n{}\n\n", program->m_main_function->function()->to_string()) + .c_str()); while (!span.empty()) { deserialized_result = PyCode::deserialize(span, program); ASSERT(deserialized_result.first.is_ok()); program->m_functions.push_back(deserialized_result.first.unwrap()); - spdlog::debug("Deserialized function {}:\n{}\n\n", + ::detail::log_debug(std::format("Deserialized function {}:\n{}\n\n", program->m_functions.back()->function()->function_name(), - program->m_functions.back()->function()->to_string()); + program->m_functions.back()->function()->to_string()) + .c_str()); } return program; diff --git a/src/executable/bytecode/BytecodeProgram.hpp b/src/executable/bytecode/BytecodeProgram.cppm similarity index 73% rename from src/executable/bytecode/BytecodeProgram.hpp rename to src/executable/bytecode/BytecodeProgram.cppm index 30f15027..08944e05 100644 --- a/src/executable/bytecode/BytecodeProgram.hpp +++ b/src/executable/bytecode/BytecodeProgram.cppm @@ -1,14 +1,16 @@ -#pragma once +export module py.runtime:bytecode_program; +import :bytecode; +import :code; +import :object; +import :tuple; +import :value; +import :executable_program; +import std; -#include "Bytecode.hpp" -#include "executable/Function.hpp" -#include "executable/FunctionBlock.hpp" -#include "executable/Program.hpp" -#include "runtime/Value.hpp" -#include "runtime/forward.hpp" -#include +export class VirtualMachine; -class BytecodeProgram : public Program + +export class BytecodeProgram : public Program { std::vector m_functions; py::PyCode *m_main_function; @@ -26,7 +28,7 @@ class BytecodeProgram : public Program InstructionVector::const_iterator end() const; - size_t main_stack_size() const; + std::size_t main_stack_size() const; py::PyObject *as_pyfunction(const std::string &function_name, const std::vector &default_values, @@ -45,7 +47,7 @@ class BytecodeProgram : public Program void visit_functions(Cell::Visitor &) const override; - std::vector serialize() const final; + std::vector serialize() const final; - static std::shared_ptr deserialize(const std::vector &); -}; \ No newline at end of file + static std::shared_ptr deserialize(const std::vector &); +}; diff --git a/src/executable/bytecode/BytecodeProgram_tests.cpp b/src/executable/bytecode/BytecodeProgram_tests.cpp index 64f93874..258c3f8a 100644 --- a/src/executable/bytecode/BytecodeProgram_tests.cpp +++ b/src/executable/bytecode/BytecodeProgram_tests.cpp @@ -1,12 +1,14 @@ -#include "BytecodeProgram.hpp" -#include "codegen/BytecodeGenerator.hpp" +#include "core.hpp" #include "executable/common.hpp" -#include "lexer/Lexer.hpp" -#include "parser/Parser.hpp" -#include "vm/VM.hpp" - #include "gtest/gtest.h" +import py.lexer; +import py.runtime; +import py.codegen; +import py.ast; + +// After the import: these name module-owned types. + namespace { std::shared_ptr generate_bytecode(std::string_view program) { diff --git a/src/executable/bytecode/Bytecode_tests.cpp b/src/executable/bytecode/Bytecode_tests.cpp index 98b8b127..6b52ea64 100644 --- a/src/executable/bytecode/Bytecode_tests.cpp +++ b/src/executable/bytecode/Bytecode_tests.cpp @@ -1,11 +1,12 @@ -#include "Bytecode.hpp" -#include "executable/bytecode/BytecodeProgram.hpp" -#include "executable/bytecode/codegen/BytecodeGenerator.hpp" +#include "core.hpp" +#include "gtest/gtest.h" -#include "lexer/Lexer.hpp" -#include "parser/Parser.hpp" +import py.lexer; +import py.runtime; +import py.codegen; +import py.ast; -#include "gtest/gtest.h" +// After the import: these name module-owned types. namespace { Bytecode make_bytecode_with_locations(std::vector locations) diff --git a/src/executable/bytecode/codegen/BytecodeGenerator.cpp b/src/executable/bytecode/codegen/BytecodeGenerator.cpp index d1c40747..49b36c29 100644 --- a/src/executable/bytecode/codegen/BytecodeGenerator.cpp +++ b/src/executable/bytecode/codegen/BytecodeGenerator.cpp @@ -1,100 +1,94 @@ -#include "BytecodeGenerator.hpp" -#include "ast/AST.hpp" -#include "executable/bytecode/BytecodeProgram.hpp" -#include "executable/bytecode/instructions/BinaryOperation.hpp" -#include "executable/bytecode/instructions/BinarySubscript.hpp" -#include "executable/bytecode/instructions/BuildDict.hpp" -#include "executable/bytecode/instructions/BuildList.hpp" -#include "executable/bytecode/instructions/BuildSet.hpp" -#include "executable/bytecode/instructions/BuildSlice.hpp" -#include "executable/bytecode/instructions/BuildString.hpp" -#include "executable/bytecode/instructions/BuildTuple.hpp" -#include "executable/bytecode/instructions/ClearExceptionState.hpp" -#include "executable/bytecode/instructions/ClearTopCleanup.hpp" -#include "executable/bytecode/instructions/CompareOperation.hpp" -#include "executable/bytecode/instructions/DeleteFast.hpp" -#include "executable/bytecode/instructions/DeleteGlobal.hpp" -#include "executable/bytecode/instructions/DeleteName.hpp" -#include "executable/bytecode/instructions/DeleteSubscript.hpp" -#include "executable/bytecode/instructions/DictAdd.hpp" -#include "executable/bytecode/instructions/DictMerge.hpp" -#include "executable/bytecode/instructions/DictUpdate.hpp" -#include "executable/bytecode/instructions/ForIter.hpp" -#include "executable/bytecode/instructions/FormatValue.hpp" -#include "executable/bytecode/instructions/FunctionCall.hpp" -#include "executable/bytecode/instructions/FunctionCallEx.hpp" -#include "executable/bytecode/instructions/FunctionCallWithKeywords.hpp" -#include "executable/bytecode/instructions/GetAwaitable.hpp" -#include "executable/bytecode/instructions/GetIter.hpp" -#include "executable/bytecode/instructions/GetYieldFromIter.hpp" -#include "executable/bytecode/instructions/ImportFrom.hpp" -#include "executable/bytecode/instructions/ImportName.hpp" -#include "executable/bytecode/instructions/ImportStar.hpp" -#include "executable/bytecode/instructions/InplaceOp.hpp" -#include "executable/bytecode/instructions/Instructions.hpp" -#include "executable/bytecode/instructions/Jump.hpp" -#include "executable/bytecode/instructions/JumpForward.hpp" -#include "executable/bytecode/instructions/JumpIfExceptionMatch.hpp" -#include "executable/bytecode/instructions/JumpIfFalse.hpp" -#include "executable/bytecode/instructions/JumpIfFalseOrPop.hpp" -#include "executable/bytecode/instructions/JumpIfNotExceptionMatch.hpp" -#include "executable/bytecode/instructions/JumpIfTrue.hpp" -#include "executable/bytecode/instructions/JumpIfTrueOrPop.hpp" -#include "executable/bytecode/instructions/LeaveExceptionHandling.hpp" -#include "executable/bytecode/instructions/ListAppend.hpp" -#include "executable/bytecode/instructions/ListExtend.hpp" -#include "executable/bytecode/instructions/ListToTuple.hpp" -#include "executable/bytecode/instructions/LoadAssertionError.hpp" -#include "executable/bytecode/instructions/LoadAttr.hpp" -#include "executable/bytecode/instructions/LoadBuildClass.hpp" -#include "executable/bytecode/instructions/LoadClosure.hpp" -#include "executable/bytecode/instructions/LoadConst.hpp" -#include "executable/bytecode/instructions/LoadDeref.hpp" -#include "executable/bytecode/instructions/LoadFast.hpp" -#include "executable/bytecode/instructions/LoadGlobal.hpp" -#include "executable/bytecode/instructions/LoadMethod.hpp" -#include "executable/bytecode/instructions/LoadName.hpp" -#include "executable/bytecode/instructions/MakeFunction.hpp" -#include "executable/bytecode/instructions/MethodCall.hpp" -#include "executable/bytecode/instructions/Move.hpp" -#include "executable/bytecode/instructions/Pop.hpp" -#include "executable/bytecode/instructions/Push.hpp" -#include "executable/bytecode/instructions/RaiseVarargs.hpp" -#include "executable/bytecode/instructions/ReRaise.hpp" -#include "executable/bytecode/instructions/ReturnValue.hpp" -#include "executable/bytecode/instructions/SetAdd.hpp" -#include "executable/bytecode/instructions/SetupExceptionHandling.hpp" -#include "executable/bytecode/instructions/SetupWith.hpp" -#include "executable/bytecode/instructions/StoreAttr.hpp" -#include "executable/bytecode/instructions/StoreDeref.hpp" -#include "executable/bytecode/instructions/StoreFast.hpp" -#include "executable/bytecode/instructions/StoreGlobal.hpp" -#include "executable/bytecode/instructions/StoreName.hpp" -#include "executable/bytecode/instructions/StoreSubscript.hpp" -#include "executable/bytecode/instructions/Unary.hpp" -#include "executable/bytecode/instructions/UnpackSequence.hpp" -#include "executable/bytecode/instructions/WithExceptStart.hpp" -#include "executable/bytecode/instructions/YieldFrom.hpp" -#include "executable/bytecode/instructions/YieldLoad.hpp" -#include "executable/bytecode/instructions/YieldValue.hpp" - -#include "ast/optimizers/ConstantFolding.hpp" -#include "executable/FunctionBlock.hpp" -#include "executable/Mangler.hpp" -#include "executable/Program.hpp" -#include "executable/bytecode/instructions/Instructions.hpp" -#include "runtime/Value.hpp" - -#include "VariablesResolver.hpp" - -#include +module; +#include "core.hpp" +#include "executable/CodeFlags.hpp" +#include "executable/Label.hpp" +#include "executable/common.hpp" +#include +#include +#include + +module py.codegen; +import py.ast; +import py.runtime; +import std; + +// After the import: these name module-owned types. +#include "memory/allocate.hpp" + +#include "ast/SourceLocationFormatter.hpp" + namespace fs = std::filesystem; using namespace ast; +// ast::Literal (a plain C++ variant, so the AST does not depend on the runtime's +// value representation) -> py::Value, which is what the bytecode's static-value +// table stores. Kept here in codegen because this is the layer that legitimately +// knows both sides. +py::Value to_runtime_value(const ast::Literal &literal) +{ + return std::visit( + overloaded{ [](std::monostate) -> py::Value { return py::NameConstant{ py::NoneType{} }; }, + [](bool value) -> py::Value { return py::NameConstant{ value }; }, + [](std::int64_t value) -> py::Value { return py::Number{ py::BigIntType{ value } }; }, + [](const mpz_class &value) -> py::Value { return py::Number{ value }; }, + [](double value) -> py::Value { return py::Number{ value }; }, + [](const std::string &value) -> py::Value { return py::String{ value }; }, + [](const ast::Bytes &value) -> py::Value { return py::Bytes{ value }; }, + [](ast::EllipsisType) -> py::Value { return py::Ellipsis{}; } }, + literal); +} + + namespace codegen { +std::shared_ptr