curry.backends.cxx.bytecode module

The emitter of the ICurry interpreter of the C++ runtime.

The runtime interprets a function from a compact bytecode (cyrt/icurry.hpp): a sequence of 32-bit units that spell the statements of the ICurry body on a small machine of registers, variables, and an operand stack. This module compiles an IFunction into that form. The materializer of the C++ backend attaches the result to the info table of the function (materialize.py) when the interpreter flag interpret asks for interpretation.

The emitter follows the C++ code generator (compiler.py) statement by statement, so an interpreted function takes the steps of its compiled form:

  • An argument that the step only passes on is a register, a plain Node * read through successor_node (the rule of passthrough.py). A variable that a case scrutinizes, or that is the base of a path, is a Variable, bound by the indexer of Variable. A free variable is a register.

  • The arguments of a node are pushed on the operand stack, left to right, and MAKE pops them. A literal is a node of the runtime, made once per value (the constant table). A partial application without arguments is a node made once per function.

  • A return writes its result into the redex when it fits the block of the redex (RET_NODE), or forwards the redex to the result (RET_REF).

  • A case is one hnf call and a branch table (CASE_CONS) or a value table (CASE_LIT). Every block ends with a return, an exempt, or a case, so a branch runs to its own end and needs no join.

The names of the opcodes (OPCODES) and their numbers agree with the enum of cyrt/icurry.hpp; a unit test compares them with the runtime.

class curry.backends.cxx.bytecode.FunctionCode(name)[source]

Bases: object

The bytecode of one function: the code units, the constants, and the sizes of the frame. A constant is what the resolver gave for a symbol or a type, or a tuple that names a value the runtime makes when the code is attached (see cyrtbindings/icurry.cpp): (‘I’, value), (‘C’, codepoint), (‘F’, value), (‘S’, text), (‘P’, info, missing), (‘V’, kind, values).

disassemble()[source]

The code as lines of text, one instruction per line.

curry.backends.cxx.bytecode.compile_function(ifun, resolver)[source]

Compiles ifun into a FunctionCode. resolver answers for the symbols the body names: symbol(fullname) gives the constant that stands for the info table of a function or constructor, tag(fullname) the tag of a constructor, and datatype(fullname) the constant that stands for the type of a constructor. The constants are handed to the runtime as they are (see cyrtbindings/icurry.cpp); a test may pass names.

Raises CompileError for a body the interpreter cannot run: a built-in without a C++ implementation, or an expression of an unknown kind.

curry.backends.cxx.bytecode.disassemble(code, consts=None)[source]

Yields one line of text per instruction of code: the position, the opcode, and the operands. With consts, a constant operand is shown with its value.