pub fn generate_code_for_node(
    generator: &mut impl Generator,
    node: &Box<ASTnode>,
) -> Option<usize> {
    // Special cases
    match node.op {
        ASTop::FUNCTION => {
            generate_code_for_function(generator, node);
            return None;
        }
        ASTop::FUNCCALL => {
            return Some(generate_code_for_funccall(generator, node));
        }
        ASTop::MEMBER | ASTop::PTRMEMBER => {
            return Some(generate_code_for_struct_member_access(
                generator,
                node,
                node.op == ASTop::PTRMEMBER,
            ));
        }
        ASTop::ASSIGN => {
            return Some(generate_code_for_assignation(generator, node));
        }
        ASTop::IF => {
            generate_code_if_statement(generator, node);
            return None;
        }
        ASTop::WHILE => {
            generate_code_while_statement(generator, node);
            return None;
        }
        ASTop::FOR => {
            generate_code_for_statement(generator, node);
            return None;
        }
        ASTop::SWITCH => {
            generate_code_switch_statement(generator, node);
            return None;
        }
        _ => {}
    }

    let mut left_reg: Option<usize> = None;
    if let Some(left) = &node.left {
        left_reg = generate_code_for_node(generator, left);

        if node.op == ASTop::GLUE {
            generator.free_all_registers();
        }
    }

    let mut right_reg: Option<usize> = None;
    if let Some(right) = &node.right {
        right_reg = generate_code_for_node(generator, right);

        if node.op == ASTop::GLUE {
            generator.free_all_registers();
        }
    }

    let data_size = generator.data_type_to_size(node.data_type);

    match node.op {
        ASTop::INTLIT | ASTop::ENUM => Some(generator.load_integer(node.int_value)),
        ASTop::ADD => Some(generator.add(left_reg.unwrap(), right_reg.unwrap())),
        ASTop::MINUS => Some(generator.minus(left_reg.unwrap(), right_reg.unwrap())),
        ASTop::MULTIPLY => Some(generator.multiply(left_reg.unwrap(), right_reg.unwrap())),
        ASTop::DIVIDE => Some(generator.divide(left_reg.unwrap(), right_reg.unwrap(), data_size)),
        ASTop::IDENT => {
            let sym = node.symtable_entry.as_ref().unwrap().borrow();

            match sym.sym_type {
                // Special case since array variables are actually pointers
                SymType::ARRAY(_) => Some(generator.load_addr(&sym)),
                _ => {
                    if node.rvalue {
                        let sym = node.symtable_entry.as_ref().unwrap().borrow();
                        Some(generator.load_var(&sym))
                    } else {
                        // In cases where an IDENT is used as a left-value,
                        // the parent node will take care of what needs to be done.
                        Some(generator.load_addr(&sym))
                    }
                }
            }
        }
        ASTop::DEREF => {
            if node.rvalue {
                Some(generator.load_from_addr(left_reg.unwrap(), data_size))
            } else {
                // In cases where an IDENT is used as a left-value,
                // the parent node will take care of what needs to be done.
                left_reg
            }
        }
        ASTop::ADDR => match &node.left {
            Some(left) => match left.op {
                ASTop::IDENT => {
                    let sym = node
                        .left
                        .as_ref()
                        .unwrap()
                        .symtable_entry
                        .as_ref()
                        .unwrap()
                        .borrow();
                    Some(generator.load_addr(&sym))
                }
                ASTop::OFFSET => left_reg,
                _ => {
                    panic!("Unexpected operand in ASTop::ADDR");
                }
            },
            None => {
                panic!("Left node should not be empty for ASTop::ADDR.");
            }
        },
        ASTop::RETURN => {
            generator.return_from_func(node.label.as_ref()?, left_reg);
            None
        }
        ASTop::STRLIT => {
            // This is safe as we can count on STRLITs to have a string table ID
            Some(generator.load_strlit(node.string_table_id.unwrap()))
        }
        ASTop::OFFSET => {
            // TODO: This uses needlessly many operations, should be optimised
            let data_size = generator.data_type_to_size(node.data_type);
            let data_size_reg = generator.load_integer(data_size as i32);
            let offset_reg = generator.multiply(right_reg.unwrap(), data_size_reg);
            let addr_reg = generator.add(left_reg.unwrap(), offset_reg);
            if node.rvalue {
                Some(generator.load_from_addr(addr_reg, data_size))
            } else {
                Some(addr_reg)
            }
        }
        ASTop::UNARYMINUS => {
            let tmp_reg = generator.load_integer(-1);
            Some(generator.multiply(left_reg.unwrap(), tmp_reg))
        }
        ASTop::GT | ASTop::GTEQ | ASTop::LT | ASTop::LTEQ | ASTop::EQ | ASTop::NOTEQ => {
            let comp_type = match node.op {
                ASTop::EQ => ComparisonType::EQ,
                ASTop::NOTEQ => ComparisonType::NOTEQ,
                ASTop::GT => ComparisonType::GT,
                ASTop::GTEQ => ComparisonType::GTEQ,
                ASTop::LT => ComparisonType::LT,
                ASTop::LTEQ => ComparisonType::LTEQ,
                _ => unreachable!("No other operations are expected here."),
            };
            Some(generator.comparison(left_reg.unwrap(), right_reg.unwrap(), comp_type))
        }
        ASTop::CONTINUE => {
            generator.gen_continue();
            None
        }
        ASTop::BREAK => {
            generator.gen_break();
            None
        }
        ASTop::NOOP => None,
        ASTop::GLUE => right_reg,
        _ => {
            panic!(
                "Unknown ASTop:{} encountered during code generation",
                node.op.name()
            );
        }
    }
}
// Generates the code for the ASTnode,
// also returns the register containing the result
// of this node.
Generates the code for the ASTnode,
also returns the register containing the result
of this node.
Generates the code for the ASTnode also returns the register containing the result of this node .
pub fn generate_code_for_node(
    generator: &mut impl Generator,
    node: &Box<ASTnode>,
) -> Option<usize> {
    // Special cases
    match node.op {
        ASTop::FUNCTION => {
            generate_code_for_function(generator, node);
            return None;
        }
        ASTop::FUNCCALL => {
            return Some(generate_code_for_funccall(generator, node));
        }
        ASTop::MEMBER | ASTop::PTRMEMBER => {
            return Some(generate_code_for_struct_member_access(
                generator,
                node,
                node.op == ASTop::PTRMEMBER,
            ));
        }
        ASTop::ASSIGN => {
            return Some(generate_code_for_assignation(generator, node));
        }
        ASTop::IF => {
            generate_code_if_statement(generator, node);
            return None;
        }
        ASTop::WHILE => {
            generate_code_while_statement(generator, node);
            return None;
        }
        ASTop::FOR => {
            generate_code_for_statement(generator, node);
            return None;
        }
        ASTop::SWITCH => {
            generate_code_switch_statement(generator, node);
            return None;
        }
        _ => {}
    }
    let mut left_reg: Option<usize> = None;
    if let Some(left) = &node.left {
        left_reg = generate_code_for_node(generator, left);
        if node.op == ASTop::GLUE {
            generator.free_all_registers();
        }
    }
    let mut right_reg: Option<usize> = None;
    if let Some(right) = &node.right {
        right_reg = generate_code_for_node(generator, right);
        if node.op == ASTop::GLUE {
            generator.free_all_registers();
        }
    }
    let data_size = generator.data_type_to_size(node.data_type);
    match node.op {
        ASTop::INTLIT | ASTop::ENUM => Some(generator.load_integer(node.int_value)),
        ASTop::ADD => Some(generator.add(left_reg.unwrap(), right_reg.unwrap())),
        ASTop::MINUS => Some(generator.minus(left_reg.unwrap(), right_reg.unwrap())),
        ASTop::MULTIPLY => Some(generator.multiply(left_reg.unwrap(), right_reg.unwrap())),
        ASTop::DIVIDE => Some(generator.divide(left_reg.unwrap(), right_reg.unwrap(), data_size)),
        ASTop::IDENT => {
            let sym = node.symtable_entry.as_ref().unwrap().borrow();
            match sym.sym_type {
                // Special case since array variables are actually pointers
                SymType::ARRAY(_) => Some(generator.load_addr(&sym)),
                _ => {
                    if node.rvalue {
                        let sym = node.symtable_entry.as_ref().unwrap().borrow();
                        Some(generator.load_var(&sym))
                    } else {
                        // In cases where an IDENT is used as a left-value,
                        // the parent node will take care of what needs to be done.
                        Some(generator.load_addr(&sym))
                    }
                }
            }
        }
        ASTop::DEREF => {
            if node.rvalue {
                Some(generator.load_from_addr(left_reg.unwrap(), data_size))
            } else {
                // In cases where an IDENT is used as a left-value,
                // the parent node will take care of what needs to be done.
                left_reg
            }
        }
        ASTop::ADDR => match &node.left {
            Some(left) => match left.op {
                ASTop::IDENT => {
                    let sym = node
                        .left
                        .as_ref()
                        .unwrap()
                        .symtable_entry
                        .as_ref()
                        .unwrap()
                        .borrow();
                    Some(generator.load_addr(&sym))
                }
                ASTop::OFFSET => left_reg,
                _ => {
                    panic!("Unexpected operand in ASTop::ADDR");
                }
            },
            None => {
                panic!("Left node should not be empty for ASTop::ADDR.");
            }
        },
        ASTop::RETURN => {
            generator.return_from_func(node.label.as_ref()?, left_reg);
            None
        }
        ASTop::STRLIT => {
            // This is safe as we can count on STRLITs to have a string table ID
            Some(generator.load_strlit(node.string_table_id.unwrap()))
        }
        ASTop::OFFSET => {
            // TODO: This uses needlessly many operations, should be optimised
            let data_size = generator.data_type_to_size(node.data_type);
            let data_size_reg = generator.load_integer(data_size as i32);
            let offset_reg = generator.multiply(right_reg.unwrap(), data_size_reg);
            let addr_reg = generator.add(left_reg.unwrap(), offset_reg);
            if node.rvalue {
                Some(generator.load_from_addr(addr_reg, data_size))
            } else {
                Some(addr_reg)
            }
        }
        ASTop::UNARYMINUS => {
            let tmp_reg = generator.load_integer(-1);
            Some(generator.multiply(left_reg.unwrap(), tmp_reg))
        }
        ASTop::GT | ASTop::GTEQ | ASTop::LT | ASTop::LTEQ | ASTop::EQ | ASTop::NOTEQ => {
            let comp_type = match node.op {
                ASTop::EQ => ComparisonType::EQ,
                ASTop::NOTEQ => ComparisonType::NOTEQ,
                ASTop::GT => ComparisonType::GT,
                ASTop::GTEQ => ComparisonType::GTEQ,
                ASTop::LT => ComparisonType::LT,
                ASTop::LTEQ => ComparisonType::LTEQ,
                _ => unreachable!("No other operations are expected here."),
            };
            Some(generator.comparison(left_reg.unwrap(), right_reg.unwrap(), comp_type))
        }
        ASTop::CONTINUE => {
            generator.gen_continue();
            None
        }
        ASTop::BREAK => {
            generator.gen_break();
            None
        }
        ASTop::NOOP => None,
        ASTop::GLUE => right_reg,
        _ => {
            panic!(
                "Unknown ASTop:{} encountered during code generation",
                node.op.name()
            );
        }
    }
}
pub fn generate_code_for_node ( generator : & mut impl Generator , node : & Box < ASTnode > , ) -> Option < usize > { // Special cases match node . op { ASTop :: FUNCTION => { generate_code_for_function ( generator , node ) ; return None ; } ASTop :: FUNCCALL => { return Some ( generate_code_for_funccall ( generator , node ) ) ; } ASTop :: MEMBER | ASTop :: PTRMEMBER => { return Some ( generate_code_for_struct_member_access ( generator , node , node . op == ASTop :: PTRMEMBER , ) ) ; } ASTop :: ASSIGN => { return Some ( generate_code_for_assignation ( generator , node ) ) ; } ASTop :: IF => { generate_code_if_statement ( generator , node ) ; return None ; } ASTop :: WHILE => { generate_code_while_statement ( generator , node ) ; return None ; } ASTop :: FOR => { generate_code_for_statement ( generator , node ) ; return None ; } ASTop :: SWITCH => { generate_code_switch_statement ( generator , node ) ; return None ; } _ => { } } let mut left_reg : Option < usize > = None ; if let Some ( left ) = & node . left { left_reg = generate_code_for_node ( generator , left ) ; if node . op == ASTop :: GLUE { generator . free_all_registers ( ) ; } } let mut right_reg : Option < usize > = None ; if let Some ( right ) = & node . right { right_reg = generate_code_for_node ( generator , right ) ; if node . op == ASTop :: GLUE { generator . free_all_registers ( ) ; } } let data_size = generator . data_type_to_size ( node . data_type ) ; match node . op { ASTop :: INTLIT | ASTop :: ENUM => Some ( generator . load_integer ( node . int_value ) ) , ASTop :: ADD => Some ( generator . add ( left_reg . unwrap ( ) , right_reg . unwrap ( ) ) ) , ASTop :: MINUS => Some ( generator . minus ( left_reg . unwrap ( ) , right_reg . unwrap ( ) ) ) , ASTop :: MULTIPLY => Some ( generator . multiply ( left_reg . unwrap ( ) , right_reg . unwrap ( ) ) ) , ASTop :: DIVIDE => Some ( generator . divide ( left_reg . unwrap ( ) , right_reg . unwrap ( ) , data_size ) ) , ASTop :: IDENT => { let sym = node . symtable_entry . as_ref ( ) . unwrap ( ) . borrow ( ) ; match sym . sym_type { // Special case since array variables are actually pointers SymType :: ARRAY ( _ ) => Some ( generator . load_addr ( & sym ) ) , _ => { if node . rvalue { let sym = node . symtable_entry . as_ref ( ) . unwrap ( ) . borrow ( ) ; Some ( generator . load_var ( & sym ) ) } else { // In cases where an IDENT is used as a left-value, // the parent node will take care of what needs to be done. Some ( generator . load_addr ( & sym ) ) } } } } ASTop :: DEREF => { if node . rvalue { Some ( generator . load_from_addr ( left_reg . unwrap ( ) , data_size ) ) } else { // In cases where an IDENT is used as a left-value, // the parent node will take care of what needs to be done. left_reg } } ASTop :: ADDR => match & node . left { Some ( left ) => match left . op { ASTop :: IDENT => { let sym = node . left . as_ref ( ) . unwrap ( ) . symtable_entry . as_ref ( ) . unwrap ( ) . borrow ( ) ; Some ( generator . load_addr ( & sym ) ) } ASTop :: OFFSET => left_reg , _ => { panic ! ( " " ) ; } } , None => { panic ! ( " " ) ; } } , ASTop :: RETURN => { generator . return_from_func ( node . label . as_ref ( ) ? , left_reg ) ; None } ASTop :: STRLIT => { // This is safe as we can count on STRLITs to have a string table ID Some ( generator . load_strlit ( node . string_table_id . unwrap ( ) ) ) } ASTop :: OFFSET => { // TODO: This uses needlessly many operations, should be optimised let data_size = generator . data_type_to_size ( node . data_type ) ; let data_size_reg = generator . load_integer ( data_size as i32 ) ; let offset_reg = generator . multiply ( right_reg . unwrap ( ) , data_size_reg ) ; let addr_reg = generator . add ( left_reg . unwrap ( ) , offset_reg ) ; if node . rvalue { Some ( generator . load_from_addr ( addr_reg , data_size ) ) } else { Some ( addr_reg ) } } ASTop :: UNARYMINUS => { let tmp_reg = generator . load_integer ( - 1 ) ; Some ( generator . multiply ( left_reg . unwrap ( ) , tmp_reg ) ) } ASTop :: GT | ASTop :: GTEQ | ASTop :: LT | ASTop :: LTEQ | ASTop :: EQ | ASTop :: NOTEQ => { let comp_type = match node . op { ASTop :: EQ => ComparisonType :: EQ , ASTop :: NOTEQ => ComparisonType :: NOTEQ , ASTop :: GT => ComparisonType :: GT , ASTop :: GTEQ => ComparisonType :: GTEQ , ASTop :: LT => ComparisonType :: LT , ASTop :: LTEQ => ComparisonType :: LTEQ , _ => unreachable ! ( " " ) , } ; Some ( generator . comparison ( left_reg . unwrap ( ) , right_reg . unwrap ( ) , comp_type ) ) } ASTop :: CONTINUE => { generator . gen_continue ( ) ; None } ASTop :: BREAK => { generator . gen_break ( ) ; None } ASTop :: NOOP => None , ASTop :: GLUE => right_reg , _ => { panic ! ( " " node op name ( ) ) ; } } }
Generates the code for the ASTnode,
also returns the register containing the result
of this node.
Generates the code for the ASTnode also returns the register containing the result of this node .
generator
&mut impl Generator
node
&Box<ASTnode>