Utilities
#########

Using Python's print function in SystemVerilog
==============================================

The usual way to write output in SystemVerilog is using ``$display`` while in Python one
would use ``print``. Since these methods use different buffers, mixing them can
lead to output order issues. To resolve this, PyStim modules can use the
:func:`pystim_pkg::print` function which writes to Python's ``sys.stdout`` for consistency.

.. code-block:: systemverilog

    py::print(py::str_("hello world")); // hello world
    py::print(py::str_("Pi value = "), py::float_(3.14159)); 
    py::print(some_prealocated_py_object); // prints the object

Evaluating Python expressions from strings and files
====================================================

PyStim provides the ``eval``, ``exec`` and ``eval_file`` functions to evaluate
Python expressions and statements. The following example illustrates how they
can be used.

.. code-block:: systemverilog

    ...

    // Evaluate in scope of main module
    py::dict global_scope = py_dict::create_empty();
    py::dict local_scope = py_dict::create_empty();

    // Evaluate an isolated expression
    int result = py::eval("2 + 10", global_scope, local_scope).cast_int();

    // Evaluate a sequence of statements
    py_object res = py::exec("print('Hello')\nprint('world!');",
        global_scope, local_scope);

    if(res.is_ok())begin
        // If the execution was successful, you can continue
        py::print(py::str_("Execution successful!"));
    end else begin
        // If there was an error, handle it accordingly
        py::print(py::str_("Execution failed with error: "));
    end

    // Evaluate the statements in an separate Python file on disk
    py::eval_file("script.py", scope);


In PyStim, the difference between `exec`` and `eval` mirrors the difference between Python’s built-in `exec()` and `eval()` functions.

Here's a breakdown:

- **`eval`**: This function evaluates a Python expression and returns the result. It is used when you want to compute a value from an expression.
- **`exec`**: This function executes Python code that can contain multiple statements but does not return a value. It is used for executing code that performs actions rather than computing a value.
- **`eval_file`**: This function reads a Python script from a file and executes it in the specified scope. It is similar to `exec`, but it allows you to run code from an external file.
  
In case of Python code execution error the result object returned from `exec` or `eval` will contain the error class `py_error`. You can check if the result is an error by using the `py::is_error` function.
It's a good idea to check the execution status before proceeding. You can also enable Python exception printing and halt the SystemVerilog simulation if a Python exception occurs.
