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. Functions support nested definitions and closures and decorators. Nested classes, class decorators, general module execution, and writable globals are unsupported.

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, sets, frozen sets, 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 containers 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, set, frozen set, 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.
set(iterable), frozenset(iterable)Create a mutable or immutable set of hashable values. Omit the iterable for an empty set. See Set operations.
range(stop), range(start, stop, step)Integer ranges, including a calculated nonzero step. Values are generated as needed during iteration.
isinstance, issubclass, super, objectClass relationships, cooperative method lookup, and the root class. See Class calls and inheritance for supported forms.
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. Zip accepts separate iterable arguments or an expanded collection of iterables. 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.
reversed(value)A single-use reverse iterator over a list, tuple, string, range, dictionary, or dictionary view. Dictionary entries follow reverse insertion order.
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 and their results must fit signed 64-bit values. Floating operations use finite binary64 values. Overflow and division by zero report errors through the C context.

FormBehavior
+, -, *, /Checked arithmetic; true division returns a float.
//, %, divmod(a, b)Integer or floating floor quotient and remainder, including Python's sign and signed-zero rules. Divmod returns both results.
**, pow(base, exp, mod=None)Nonnegative integer powers remain integers; negative exponents or floating operands produce floats. A nonzero integer modulus enables modular power, including negative exponents when the base is invertible. Pow accepts its named keywords.
&, |, ^, ~, <<, >>Integer bit operations with Python's negative-value semantics. Negative shift counts are errors; left shifts check overflow. Binary Boolean bit operations return Booleans.

Augmented assignments use the same numeric rules. Complex results and arbitrary-size integers are outside the numeric domain. Floating power uses the target's math library; its final rounding may vary across platforms.

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, sets, frozen sets, 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, dictionary, and set 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. Obtain a function value with pv_top_function using its generated symbol from the conversion summary. This initializes module definitions, defaults, and decorators once in the context and returns the final decorated value. 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.

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. Build through Compile C or an external toolchain; run the resulting program separately.

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.