pub fn assemble<T>(source: T) -> Vec<Word>
where
    T: AsRef<str>,
{
    let tokens = get_meta_instructions(source);

    let mut label_map = HashMap::new();
    for token in tokens.iter() {
        if let MetaInstruction::Label(label) = token {
            if label_map.insert(label.clone(), 0x0000u16).is_some() {
                panic!("Label '{}' defined multiple times", label);
            }
        }
    }

    let mut instructions = Vec::new();
    let mut current_position: Word = 0x0000;

    // First pass, materialize as many instructions as possible.
    for token in tokens {
        match token {
            MetaInstruction::Instruction(instruction) => {
                let materialized = instruction.materialize(&label_map);

                // We assume the best-case situation here.
                // This is helpful because small values can be inlined
                // into the instruction.
                let len = materialized.len_estimate();
                current_position += len as Word;

                instructions.push(materialized);
            }
            MetaInstruction::Label(label) => {
                label_map.insert(label.clone(), current_position);
            }
        }
    }

    // Second pass, attempt to materialize the "flexible" instructions.
    let mut current_position: Word;
    loop {
        let mut replace_list = Vec::new();
        current_position = 0x0000;

        for (i, entry) in instructions.iter().enumerate() {
            let current_length = entry.len_estimate();
            current_position += current_length as Word;

            match entry {
                MaterializedInstruction::Static { .. } => continue,
                MaterializedInstruction::Flexible { instruction, .. } => {
                    let new_instruction = instruction.materialize(&label_map);
                    let new_length = new_instruction.len_estimate();

                    let difference = new_length as i64 - current_length as i64;
                    // assert!(difference >= 0);

                    // If the instruction changed in size, we need to adjust all following
                    // label positions.
                    if difference != 0 {
                        // Store the updated entry for later replacement in the list.
                        replace_list.push((i, new_instruction));

                        // Update the labels.
                        for (_label, label_pos) in label_map.iter_mut() {
                            if *label_pos > current_position {
                                *label_pos = (*label_pos as i64 + difference) as Word;
                            }
                        }
                    }
                }
            }
        }

        // If no instruction was replaced we arrived at a local optimum.
        if replace_list.len() == 0 {
            break;
        }

        // Update the improved instructions.
        for (idx, instruction) in replace_list {
            instructions[idx] = instruction;
        }
    }

    // Go through the instructions one last time and generate the byte stream.
    let mut bytesteam = Vec::with_capacity(current_position as usize);
    for entry in instructions {
        write_materialized_instruction_into_bytestream(&mut bytesteam, entry, &mut label_map)
    }

    bytesteam
}
/// Assembles the source code into an DCPU-16 program bytecode.
Assembles the source code into an DCPU-16 program bytecode.
Assembles the source code into an DCPU - 16 program bytecode .
pub fn assemble<T>(source: T) -> Vec<Word>
where
    T: AsRef<str>,
{
    let tokens = get_meta_instructions(source);
    let mut label_map = HashMap::new();
    for token in tokens.iter() {
        if let MetaInstruction::Label(label) = token {
            if label_map.insert(label.clone(), 0x0000u16).is_some() {
                panic!("Label '{}' defined multiple times", label);
            }
        }
    }
    let mut instructions = Vec::new();
    let mut current_position: Word = 0x0000;
    // First pass, materialize as many instructions as possible.
    for token in tokens {
        match token {
            MetaInstruction::Instruction(instruction) => {
                let materialized = instruction.materialize(&label_map);
                // We assume the best-case situation here.
                // This is helpful because small values can be inlined
                // into the instruction.
                let len = materialized.len_estimate();
                current_position += len as Word;
                instructions.push(materialized);
            }
            MetaInstruction::Label(label) => {
                label_map.insert(label.clone(), current_position);
            }
        }
    }
    // Second pass, attempt to materialize the "flexible" instructions.
    let mut current_position: Word;
    loop {
        let mut replace_list = Vec::new();
        current_position = 0x0000;
        for (i, entry) in instructions.iter().enumerate() {
            let current_length = entry.len_estimate();
            current_position += current_length as Word;
            match entry {
                MaterializedInstruction::Static { .. } => continue,
                MaterializedInstruction::Flexible { instruction, .. } => {
                    let new_instruction = instruction.materialize(&label_map);
                    let new_length = new_instruction.len_estimate();
                    let difference = new_length as i64 - current_length as i64;
                    // assert!(difference >= 0);
                    // If the instruction changed in size, we need to adjust all following
                    // label positions.
                    if difference != 0 {
                        // Store the updated entry for later replacement in the list.
                        replace_list.push((i, new_instruction));
                        // Update the labels.
                        for (_label, label_pos) in label_map.iter_mut() {
                            if *label_pos > current_position {
                                *label_pos = (*label_pos as i64 + difference) as Word;
                            }
                        }
                    }
                }
            }
        }
        // If no instruction was replaced we arrived at a local optimum.
        if replace_list.len() == 0 {
            break;
        }
        // Update the improved instructions.
        for (idx, instruction) in replace_list {
            instructions[idx] = instruction;
        }
    }
    // Go through the instructions one last time and generate the byte stream.
    let mut bytesteam = Vec::with_capacity(current_position as usize);
    for entry in instructions {
        write_materialized_instruction_into_bytestream(&mut bytesteam, entry, &mut label_map)
    }
    bytesteam
}
pub fn assemble < T > ( source : T ) -> Vec < Word > where T : AsRef < str > , { let tokens = get_meta_instructions ( source ) ; let mut label_map = HashMap :: new ( ) ; for token in tokens . iter ( ) { if let MetaInstruction :: Label ( label ) = token { if label_map . insert ( label . clone ( ) , 0x0000u16 ) . is_some ( ) { panic ! ( " " label ) ; } } } let mut instructions = Vec :: new ( ) ; let mut current_position : Word = 0x0000 ; // First pass, materialize as many instructions as possible. for token in tokens { match token { MetaInstruction :: Instruction ( instruction ) => { let materialized = instruction . materialize ( & label_map ) ; // We assume the best-case situation here. // This is helpful because small values can be inlined // into the instruction. let len = materialized . len_estimate ( ) ; current_position += len as Word ; instructions . push ( materialized ) ; } MetaInstruction :: Label ( label ) => { label_map . insert ( label . clone ( ) , current_position ) ; } } } // Second pass, attempt to materialize the "flexible" instructions. let mut current_position : Word ; loop { let mut replace_list = Vec :: new ( ) ; current_position = 0x0000 ; for ( i , entry ) in instructions . iter ( ) . enumerate ( ) { let current_length = entry . len_estimate ( ) ; current_position += current_length as Word ; match entry { MaterializedInstruction :: Static { .. } => continue , MaterializedInstruction :: Flexible { instruction , .. } => { let new_instruction = instruction . materialize ( & label_map ) ; let new_length = new_instruction . len_estimate ( ) ; let difference = new_length as i64 - current_length as i64 ; // assert!(difference >= 0); // If the instruction changed in size, we need to adjust all following // label positions. if difference != 0 { // Store the updated entry for later replacement in the list. replace_list . push ( ( i , new_instruction ) ) ; // Update the labels. for ( _label , label_pos ) in label_map . iter_mut ( ) { if * label_pos > current_position { * label_pos = ( * label_pos as i64 + difference ) as Word ; } } } } } } // If no instruction was replaced we arrived at a local optimum. if replace_list . len ( ) == 0 { break ; } // Update the improved instructions. for ( idx , instruction ) in replace_list { instructions [ idx ] = instruction ; } } // Go through the instructions one last time and generate the byte stream. let mut bytesteam = Vec :: with_capacity ( current_position as usize ) ; for entry in instructions { write_materialized_instruction_into_bytestream ( & mut bytesteam , entry , & mut label_map ) } bytesteam }
Assembles the source code into an DCPU-16 program bytecode.
Assembles the source code into an DCPU - 16 program bytecode .
source
T