RUNTIME VALUE CONVERSIONS

Runtime conversion and C use

Runtime value conversion generates C11 routines for Python values that are created, shared, and changed while the generated program runs.

Select runtime conversion

Open all required source documents, select Transpile → Runtime, then click the Transpile button or press Ctrl+Return. The checked selection is remembered; selecting it alone does not run conversion. Both modes produce normal .c files saved with Save Generated C. The terminal equivalent is:

pycforge convert input.py --runtime-values --output generated.c

For the Python API, use the complete runtime request options shown in Runtime value requests. Runtime conversion uses its own C value representation and does not provide exact ForgeLens mappings or the typed converter's C-IR validation.

Organize the source

Place functions, classes, immutable constants, and explicit imports at module level. Include at least one top-level function in the bundle; constants-only and empty companions are accepted. See Runtime modules for imports and initialization order. Nested def or class statements, decorators, general module execution, and writable globals are unsupported. Use lambdas for closures.

def greeting(name: str) -> str:
    return "Hello, " + name + "!"

def main() -> int:
    print(greeting("café"))
    return 0

This program prints Hello, café! when compiled and run externally.

Values and built-in calls

FormSupported use
None, bool, int, float, strScalar values, compatible arithmetic/comparisons, and truth tests.
len(value)Strings, lists, tuples, ranges, dictionaries, and dictionary views.
bool(value), bool()Truth conversion for admitted runtime values; the empty call returns False.
int(value, base), float(value)Numeric and string conversions. The optional int base is 0 or 2–36 and also accepts a keyword. Empty int/float calls return zero.
str(value), str()Strings, integers, finite floats, Booleans, and None. The empty call returns an empty string. Nested lists, tuples, dictionaries, and dictionary views also render as Python-style text. Object/function/class/module/range/iterator/file-handle representations are outside this profile.
list(value), tuple(value)Convert a supported string, list, tuple, range, dictionary, dictionary view, admitted iterator, or readable file handle. An omitted argument creates an empty container, like [] or ().
dict(source, name=value)Create an ordered mutable dictionary from another dictionary or key/value pairs, plus optional explicit keywords. Source is optional. See Dictionary operations.
range(stop), range(start, stop, step)Integer ranges, including a calculated nonzero step. Values are generated as needed during iteration.
print(value, ...)Strings, integers, finite floats, Booleans, and None. Optional sep and end keywords accept strings or None. Nested containers and dictionary views print with Python-style quoting and cycle markers. Object/function/class/module/range/iterator/file-handle printing and file/flush options are unsupported.

Everyday builtins

FormBehavior
sum(iterable, start=0)Accumulate admitted values. Strings are rejected; numeric sums use checked integers and Python 3.12-style compensated floating addition.
min, maxOne iterable or multiple positional values; optional key function. An empty iterable may use default=. Equal keys keep the first value.
abs(value), round(number, ndigits=None)Numeric absolute value and ties-to-even rounding. Integer overflow is reported; decimal rounding retains the actual binary64 input.
any(iterable), all(iterable)Short-circuit truth tests; empty input returns False for any and True for all.
sorted(iterable, key=None, reverse=False)New list in stable order. Keys are evaluated once per element. Numeric, string, and compatible list/tuple keys are supported.
enumerate(iterable, start=0), zip(*iterables, strict=False)Lazy, single-use iterators. Pass explicit iterable arguments to zip; starred-call unpacking remains unsupported. Strict zip reports unequal lengths during consumption.
iter(iterable), next(iterator, default)Share and consume iterator state. The next default is optional; exhaustion without it reports StopIteration through the C error channel.
repr(value), ascii(value), format(value, spec)Representation and bounded formatting; see formatting details.
def main() -> int:
    values = [-3, 2, -1, 2]
    print(sum(values), min(values), max(values), round(2.675, 2))
    print(sorted(values, key=abs))
    for position, pair in enumerate(zip("ab", [10, 20]), start=1):
        print(position, pair)
    return 0

Iterator inputs remain live and iterators retain their consumption position. They have no length or indexing. General generators and custom iterator protocols are not supported. An enumerate index outside int64 reports overflow. Builtins are function values, so key=abs and key=len work.

Numeric operations

Integers use checked signed 64-bit arithmetic. Overflow and division by zero report runtime errors. Integer // and % follow Python's floor and remainder rules. True division / produces a binary64 floating result. Floating operations require finite binary64 values; floating floor division and remainder are unsupported. Power and bitwise operators are outside the supported expression set.

Convert numeric text

def main() -> int:
    print(int("1_250"), int("ff", base=16), int("0b101", 0))
    print(float("  -1.25e2  "), float("١.٥"))
    print(str(1.5), str(-0.0), str(1e20))
    return 0

Expected output:

1250 255 5
-125.0 1.5
1.5 -0.0 1e+20

Integer parsing accepts an optional sign, surrounding numeric whitespace, Unicode decimal digits, valid underscore separators, and prefixes consistent with the selected base. Base 0 detects 0b, 0o, or 0x; a nonzero decimal value with a leading zero is invalid in that form. An explicit base requires a string. Values must fit signed 64-bit integers.

Float parsing accepts finite decimal text, optional exponent/sign, surrounding numeric whitespace, Unicode decimal digits, and underscores between digits. Invalid text and embedded NULs fail. NaN, infinity, hexadecimal float text, and non-finite results are outside the numeric domain. Underflow may produce a subnormal or signed zero.

Float-to-string conversion uses a shortest round-trip representation with Python's fixed/scientific notation rules, including -0.0. Integer conversion truncates a finite float toward zero and checks the int64 range. The generated C caller must keep a numeric locale whose decimal point is .; decimal parsing reports an error if the host selects a different separator.

Branches and loops

Use if/elif/else, while, and for over strings, lists, tuples, ranges, dictionaries, dictionary views, admitted iterators, or readable files. break, continue, and loop else follow the usual Python rules: else runs after normal exhaustion, including zero iterations, and is skipped by break.

Conditional expressions, chained comparisons, and short-circuit and/or preserve evaluation order and return the selected operand. Assign locals before reading them; a loop may leave its target unassigned if it never runs. Comprehensions have their own scope, described in List and dictionary comprehensions.

Use file-processing workflows to connect UTF-8 reads and writes with these operations. File contexts can nest inside loops and call imported processing helpers.

Call generated functions from C

Generated values use the PV type. A zero-initialized PC context owns all allocations. Create a function value with pv_top_function using its generated symbol from the conversion summary. This initializes module definitions and their defaults once in the context. Call it through pv_call with a positional argument count and PV array; optional parameters may be omitted. For keywords, pv_call_kw additionally takes a keyword count, name array, and value array. Use pv_i for integer arguments and pv_string for UTF-8 bytes with an explicit byte length.

Use the same context for connected calls, shared lists, dictionaries, objects, and closures. Check context.error after each call; context.error_source and context.error_line identify its logical source file and Python statement. On failure, discard the result. Always finish with pv_destroy(&context), including after an error.

Returned values and captured variables remain valid until their context is destroyed. Do not free individual values, use them afterward, move them to another context, or share one context concurrently between threads. Intermediate allocations remain in the context until destruction, so divide long-running work into independent bounded contexts.

Complete runtime C caller

Save the greeting/main Python example above as runtime-example.py and convert it in Runtime mode to runtime-example.c. In this exact example greeting has generated symbol pv_fn1; confirm the symbol in your own output because changing definitions can change it. Save this caller as runtime-caller.c beside the generated C.

#include "runtime-example.c"

int main(void)
{
    PC context = {0};
    int status = 1;
    PV function = pv_top_function(&context, pv_fn1);
    if (context.error) goto cleanup;
    PV arguments[] = {
        pv_string(&context, (const unsigned char *)"Ada", 3)
    };
    if (context.error) goto cleanup;
    PV result = pv_call(&context, function, 1, arguments);
    if (context.error) goto cleanup;
    pv_print(&context, 1, &result);
    if (!context.error) status = 0;

cleanup:
    if (context.error) {
        fprintf(stderr, "Python line %d: %s\n",
                context.error_line, context.error);
    }
    pv_destroy(&context);
    return status;
}
gcc -std=c11 runtime-caller.c -o runtime-caller -lm

Run ./runtime-caller on Linux/macOS or .\runtime-caller.exe in Windows PowerShell. It prints Hello, Ada!. This caller supplies its own main; omit PYCF_RUNTIME_MAIN and compile only runtime-caller.c. Error checks cover definition setup, string allocation, the call, and printing, and the context is destroyed on every exit path.

Build a standalone program

If the primary module defines or imports a main() callable without arguments, including one whose parameters all have defaults, an external C build can enable the supplied entry wrapper. For the example above, with a compatible 64-bit GCC toolchain:

gcc -std=c11 -DPYCF_RUNTIME_MAIN generated.c -o greeting -lm
./greeting

In Windows PowerShell, use .\greeting.exe to run the program. The command assumes a compatible GCC toolchain is already installed; PyCForge does not install one.

Integer returns from 0 to 255 become process exit statuses; other integers map to 255, and None maps to 0. A runtime failure prints its error and exits with status 1. Other return types are invalid for this wrapper.

The emitted program requires a 64-bit host with binary64 double. It includes its value routines and does not require Python, PySide6, NumPy, Numba, or Ting to run. PyCForge itself only emits C; external building and execution are your separate steps.

Memory and work limits

The default context limit is 64 MiB of allocations, one million counted iteration, hashing, lookup, comparison, materialization, and type-check steps, and 128 call levels. These are workload limits, not a wall-clock timer. PYCF_RUNTIME_BYTES and PYCF_RUNTIME_STEPS may be configured by the external C build. See Conversion and input limits for source limits and failure handling.