Running a cell: the prompt and the Jupyter kernel¶
The terminal prompt and the optional Xeus kernel run cells with
FortranEvaluator::execute(code, verbose, io) (src/lfortran/fortran_evaluator.h).
It evaluates one cell like evaluate(), with fresh diagnostics and the default
passes, and also runs the %%showast, %%showasr, %%showllvm, %%showasm,
%%showcpp and %%showfmt inspection cells (the magic is the first line of
the cell; trailing blanks and a CRLF line ending are ignored). An inspection
cell sees the session’s declarations, but it does not run, so its own
declarations do not join the session. CompilerOptions::interactive must be
set before the first cell; the evaluator keeps the session’s symbols across
cells (see Interactive evaluation: one TranslationUnit per cell). A failed cell is not rolled back.
The returned CellResult holds the typed EvalResult (or, when inspection
is set, the inspection output) and the rendered diagnostics; those of a
successful cell are its warnings, which both frontends show. For a failed cell
it holds an error name and message: CompilerError with the rendered
diagnostics, DisplayError, or, for an internal compiler error
(internal_error), the exception’s name and message, with its stack trace
apart in error_traceback. CellResult::error_text() is what a frontend shows
for it. The kernel sends the message as the Jupyter evalue and the stack
trace as the traceback.
EvalResult::text() formats a value the way the prompt and the kernel show it:
for real and complex, the shortest text that reads back as the same value (at
most 9/17 significant digits), always with a decimal point or an exponent, so
that 1.0 is not shown as 1; True/False; character text.
EvalResult::has_value() is false for statements and empty cells.
The lfortran_display module’s display_data and clear_output call the
lfortran_display_data and lfortran_clear_output C functions of the runtime
library. While execute() runs a cell, it registers hooks and a context with
the runtime (_lfortran_set_display_hooks) that forward to that cell’s
CellIO, including in WASM; at any other time, and in compiled programs, the
functions do nothing. The hooks are process-wide, so cells must not run
concurrently. An exception thrown by a hook does not unwind through generated
code; the cell fails with DisplayError and the exception’s message. The
module is built with or without Xeus. execute() does not capture
stdout/stderr; that is up to the frontend. Jupyter messages must be UTF-8, so
the kernel shows any other bytes of a cell’s output as U+FFFD.
Runtime input¶
CellIO::input, when set, supplies the records that READ from stdin consumes
while the cell runs: it returns 0 with one record (without a newline), -1 at
end of file, or a positive value when no input is available. An empty record
is a blank line, not end of file. Unset, the cell reads the process’s stdin as
a compiled program does. An exception thrown by the hook becomes unavailable
input. execute() installs the hook through the runtime’s C API
(src/libasr/runtime/lfortran_stdin.h) for that cell only and always removes
it, so a later cell can read again after end of file and unread bytes are
discarded.
The runtime keeps the record’s bytes, its cursor and delimiters, so one record can satisfy several list items and one READ can consume several records. Default stdin and units connected to it (normally unit 5) share this cursor for list-directed, formatted, nonadvancing and namelist reads of scalars, arrays and complex values, and PAUSE. End of file and unavailable input are latched for the rest of the cell: READs with IOSTAT see a negative or a positive value; READs without one stop the program, as they do outside the prompt. Named and internal files never consult the hook, and C code reading stdin directly is not affected.
The test_lfortran cases FortranEvaluator execute: * (also run in the WASM
build of the JupyterLite kernel), test_repl and, in Xeus builds,
test_kernel_evaluation cover this, with test_runtime_input for the
runtime’s record handling; the display_data_01 integration test covers
compiled programs and runtime_input_records checks that ordinary named and
internal file reads are unchanged. The complex-result cases of test_lfortran also
exercise the JIT result ABI on Windows: there complex(4) comes back as two
float bit patterns in an integer register and complex(8) through an output
pointer, and FortranEvaluator calls those signatures explicitly rather than
relying on the C++ std::complex return convention.