def assemble(code):
    """
    Assemble the given iterable of mnemonics, operands, and lables.

    A convienience over constructing individual Instruction and Operand
    objects, the output of this function can be directly piped to
    :class:`~jawa.attributes.code.CodeAttribute.assemble()` to produce
    executable bytecode.

    As a simple example, lets produce an infinite loop:

        >>> from jawa.assemble import assemble, Label
        >>> print(list(assemble((
        ...     Label('start'),
        ...     ('goto', Label('start'))
        ... ))))
        [Instruction(mnemonic='goto', opcode=167, operands=[
            Operand(op_type=40, value=0)], pos=0)]

    For a more complex example, see examples/hello_world.py.
    """
    final = []

    # We need to make three passes, because we cannot know the offset for
    # jump labels until after we've figured out the PC for each instructions,
    # which is complicated by the variable-width instructions set and
    # alignment padding.
    for line in code:
        if isinstance(line, Label):
            final.append(line)
            continue

        mnemonic, operands = line[0], line[1:]
        operand_fmts = opcode_table[mnemonic]['operands']

        # We need to coerce each opcodes operands into their
        # final `Operand` form.
        final_operands = []
        for i, operand in enumerate(operands):
            if isinstance(operand, Operand):
                # Already in Operand form.
                final_operands.append(operand)
            elif isinstance(operand, Constant):
                # Convert constants into CONSTANT_INDEX'es
                final_operands.append(Operand(
                    OperandTypes.CONSTANT_INDEX,
                    operand.index
                ))
            elif isinstance(operand, dict):
                # lookupswitch's operand is a dict as
                # a special usability case.
                final_operands.append(operand)
            elif isinstance(operand, Label):
                final_operands.append(operand)
            else:
                # For anything else, lookup that opcode's operand
                # type from its definition.
                final_operands.append(Operand(
                    operand_fmts[i][1],
                    operand
                ))

        # Build the final, immutable `Instruction`.
        final.append(Instruction.create(mnemonic, final_operands))

    label_pcs = {}

    # The second pass, find the absolute PC for each label.
    current_pc = 0
    for ins in final:
        if isinstance(ins, Label):
            label_pcs[ins.name] = current_pc
            continue

        # size_on_disk must know the current pc because of alignment on
        # tableswitch and lookupswitch.
        current_pc += ins.size_on_disk(current_pc)

    # The third pass, now that we know where each label is we can figure
    # out the offset for each jump.
    current_pc = 0

    for ins in final:
        if isinstance(ins, Label):
            continue

        for i, operand in enumerate(ins.operands):
            if isinstance(operand, dict):
                # lookupswitch is a special case
                for k, v in operand.items():
                    if isinstance(v, Label):
                        operand[k] = Operand(40, label_pcs[v.name] - current_pc)
            elif isinstance(operand, Label):
                ins.operands[i] = Operand(
                    40,
                    label_pcs[operand.name] - current_pc
                )

        current_pc += ins.size_on_disk(current_pc)

        yield ins
def assemble ( code ) : final = [ ] for line in code : if isinstance ( line , Label ) : final . append ( line ) continue mnemonic , operands = line [ 0 ] , line [ 1 : ] operand_fmts = opcode_table [ mnemonic ] [ 'operands' ] final_operands = [ ] for i , operand in enumerate ( operands ) : if isinstance ( operand , Operand ) : final_operands . append ( operand ) elif isinstance ( operand , Constant ) : final_operands . append ( Operand ( OperandTypes . CONSTANT_INDEX , operand . index ) ) elif isinstance ( operand , dict ) : final_operands . append ( operand ) elif isinstance ( operand , Label ) : final_operands . append ( operand ) else : final_operands . append ( Operand ( operand_fmts [ i ] [ 1 ] , operand ) ) final . append ( Instruction . create ( mnemonic , final_operands ) ) label_pcs = { } current_pc = 0 for ins in final : if isinstance ( ins , Label ) : label_pcs [ ins . name ] = current_pc continue current_pc += ins . size_on_disk ( current_pc ) current_pc = 0 for ins in final : if isinstance ( ins , Label ) : continue for i , operand in enumerate ( ins . operands ) : if isinstance ( operand , dict ) : for k , v in operand . items ( ) : if isinstance ( v , Label ) : operand [ k ] = Operand ( 40 , label_pcs [ v . name ] - current_pc ) elif isinstance ( operand , Label ) : ins . operands [ i ] = Operand ( 40 , label_pcs [ operand . name ] - current_pc ) current_pc += ins . size_on_disk ( current_pc ) yield ins
Assemble the given iterable of mnemonics, operands, and lables.

    A convienience over constructing individual Instruction and Operand
    objects, the output of this function can be directly piped to
    :class:`~jawa.attributes.code.CodeAttribute.assemble()` to produce
    executable bytecode.

    As a simple example, lets produce an infinite loop:

        >>> from jawa.assemble import assemble, Label
        >>> print(list(assemble((
        ...     Label('start'),
        ...     ('goto', Label('start'))
        ... ))))
        [Instruction(mnemonic='goto', opcode=167, operands=[
            Operand(op_type=40, value=0)], pos=0)]

    For a more complex example, see examples/hello_world.py.