fn gen_function(
    function: &FuncDef,
    storage_env: &mut StorageEnv,
    classes: &HashMap<String, ClassSlot>,
    level: u32,
    parent: Option<&str>,
    platform: Platform,
) -> Vec<Chunk> {
    let link_name = if let Some(parent) = parent {
        parent.to_owned() + "." + &function.name.name
    } else {
        function.name.name.clone()
    };

    let mut locals = HashMap::new();

    // Collects slot and debug info for parameters
    let mut ref_list = vec![];
    let mut params_debug = vec![];
    for (i, param) in function.params.iter().enumerate() {
        let offset;
        offset = i as i32 * 8 + 16;
        let name = &param.identifier.name;
        locals.insert(
            name.clone(),
            LocalSlot::Var(VarSlot {
                offset,
                level: level + 1,
            }),
        );
        let param_type = ValueType::from_annotation(&param.type_);
        if !param_type.is_plain() {
            ref_list.push(offset);
        }

        params_debug.push(VarDebug {
            offset,
            line: param.base().location.start.row,
            name: name.clone(),
            var_type: TypeDebug::from_annotation(&param.type_),
        })
    }

    // Collect infos for local variables and nested functions
    let mut locals_debug = vec![];
    let mut local_offset = if level == 0 { -8 } else { -16 };
    for declaration in &function.declarations {
        match declaration {
            Declaration::VarDef(v) => {
                let name = &v.var.identifier.name;
                let offset = local_offset;
                local_offset -= 8;
                locals.insert(
                    name.clone(),
                    LocalSlot::Var(VarSlot {
                        offset,
                        level: level + 1,
                    }),
                );

                locals_debug.push(VarDebug {
                    offset,
                    line: v.base().location.start.row,
                    name: name.clone(),
                    var_type: TypeDebug::from_annotation(&v.var.type_),
                })
            }
            Declaration::FuncDef(f) => {
                let name = &f.name.name;
                locals.insert(
                    name.clone(),
                    LocalSlot::Func(FuncSlot {
                        link_name: link_name.clone() + "." + name,
                        level: level + 1,
                    }),
                );
            }
            _ => (),
        }
    }

    let mut handle = storage_env.push(locals);
    let return_type = ValueType::from_annotation(&function.return_type);

    let mut code = Emitter::new(
        &link_name,
        Some(&return_type),
        Some(handle.inner()),
        Some(classes),
        ref_list,
        level,
        platform,
    );

    if level != 0 {
        // Save static link
        let static_link = code.alloc_stack(TicketType::Plain);
        // mov [rbp+{}],r10
        code.emit_with_stack(&[0x4C, 0x89, 0x95], &static_link);
        static_link.free_on_exit();
    }

    // Initialize local variables
    for declaration in &function.declarations {
        if let Declaration::VarDef(v) = declaration {
            code.emit_local_var_init(v);
        }
    }

    let mut lines = vec![LineMap {
        code_pos: 0,
        line_number: function.base().location.start.row,
    }];

    // Generate codes for all statements
    for statement in &function.statements {
        code.emit_statement(statement, &mut lines);
    }

    // Implicit `return None`
    code.emit_none_literal();
    code.end_proc();

    // Package code into a chunk
    let mut chunks = vec![code.finalize(ProcedureDebug {
        decl_line: function.statements[0].base().location.start.row,
        artificial: false,
        parent: if level == 0 {
            None
        } else {
            parent.map(str::to_owned)
        },
        lines,
        return_type: TypeDebug::from_annotation(&function.return_type),
        params: params_debug,
        locals: locals_debug,
        frame_size: 0,
    })];

    // Recursively generate codes for nested functions
    // Note: put children functions after the parent one
    // so that debug tree can be generated sequentially
    for declaration in &function.declarations {
        if let Declaration::FuncDef(f) = declaration {
            chunks.append(&mut gen_function(
                &f,
                handle.inner(),
                classes,
                level + 1,
                Some(&link_name),
                platform,
            ));
        }
    }

    chunks
}
// Generate machine code for a function
Generate machine code for a function
Generate machine code for a function
fn gen_function(
    function: &FuncDef,
    storage_env: &mut StorageEnv,
    classes: &HashMap<String, ClassSlot>,
    level: u32,
    parent: Option<&str>,
    platform: Platform,
) -> Vec<Chunk> {
    let link_name = if let Some(parent) = parent {
        parent.to_owned() + "." + &function.name.name
    } else {
        function.name.name.clone()
    };
    let mut locals = HashMap::new();
    // Collects slot and debug info for parameters
    let mut ref_list = vec![];
    let mut params_debug = vec![];
    for (i, param) in function.params.iter().enumerate() {
        let offset;
        offset = i as i32 * 8 + 16;
        let name = &param.identifier.name;
        locals.insert(
            name.clone(),
            LocalSlot::Var(VarSlot {
                offset,
                level: level + 1,
            }),
        );
        let param_type = ValueType::from_annotation(&param.type_);
        if !param_type.is_plain() {
            ref_list.push(offset);
        }
        params_debug.push(VarDebug {
            offset,
            line: param.base().location.start.row,
            name: name.clone(),
            var_type: TypeDebug::from_annotation(&param.type_),
        })
    }
    // Collect infos for local variables and nested functions
    let mut locals_debug = vec![];
    let mut local_offset = if level == 0 { -8 } else { -16 };
    for declaration in &function.declarations {
        match declaration {
            Declaration::VarDef(v) => {
                let name = &v.var.identifier.name;
                let offset = local_offset;
                local_offset -= 8;
                locals.insert(
                    name.clone(),
                    LocalSlot::Var(VarSlot {
                        offset,
                        level: level + 1,
                    }),
                );
                locals_debug.push(VarDebug {
                    offset,
                    line: v.base().location.start.row,
                    name: name.clone(),
                    var_type: TypeDebug::from_annotation(&v.var.type_),
                })
            }
            Declaration::FuncDef(f) => {
                let name = &f.name.name;
                locals.insert(
                    name.clone(),
                    LocalSlot::Func(FuncSlot {
                        link_name: link_name.clone() + "." + name,
                        level: level + 1,
                    }),
                );
            }
            _ => (),
        }
    }
    let mut handle = storage_env.push(locals);
    let return_type = ValueType::from_annotation(&function.return_type);
    let mut code = Emitter::new(
        &link_name,
        Some(&return_type),
        Some(handle.inner()),
        Some(classes),
        ref_list,
        level,
        platform,
    );
    if level != 0 {
        // Save static link
        let static_link = code.alloc_stack(TicketType::Plain);
        // mov [rbp+{}],r10
        code.emit_with_stack(&[0x4C, 0x89, 0x95], &static_link);
        static_link.free_on_exit();
    }
    // Initialize local variables
    for declaration in &function.declarations {
        if let Declaration::VarDef(v) = declaration {
            code.emit_local_var_init(v);
        }
    }
    let mut lines = vec![LineMap {
        code_pos: 0,
        line_number: function.base().location.start.row,
    }];
    // Generate codes for all statements
    for statement in &function.statements {
        code.emit_statement(statement, &mut lines);
    }
    // Implicit `return None`
    code.emit_none_literal();
    code.end_proc();
    // Package code into a chunk
    let mut chunks = vec![code.finalize(ProcedureDebug {
        decl_line: function.statements[0].base().location.start.row,
        artificial: false,
        parent: if level == 0 {
            None
        } else {
            parent.map(str::to_owned)
        },
        lines,
        return_type: TypeDebug::from_annotation(&function.return_type),
        params: params_debug,
        locals: locals_debug,
        frame_size: 0,
    })];
    // Recursively generate codes for nested functions
    // Note: put children functions after the parent one
    // so that debug tree can be generated sequentially
    for declaration in &function.declarations {
        if let Declaration::FuncDef(f) = declaration {
            chunks.append(&mut gen_function(
                &f,
                handle.inner(),
                classes,
                level + 1,
                Some(&link_name),
                platform,
            ));
        }
    }
    chunks
}
fn gen_function ( function : & FuncDef , storage_env : & mut StorageEnv , classes : & HashMap < String , ClassSlot > , level : u32 , parent : Option < & str > , platform : Platform , ) -> Vec < Chunk > { let link_name = if let Some ( parent ) = parent { parent . to_owned ( ) + " " + & function . name . name } else { function . name . name . clone ( ) } ; let mut locals = HashMap :: new ( ) ; // Collects slot and debug info for parameters let mut ref_list = vec ! [ ] ; let mut params_debug = vec ! [ ] ; for ( i , param ) in function . params . iter ( ) . enumerate ( ) { let offset ; offset = i as i32 * 8 + 16 ; let name = & param . identifier . name ; locals . insert ( name . clone ( ) , LocalSlot :: Var ( VarSlot { offset , level : level + 1 , } ) , ) ; let param_type = ValueType :: from_annotation ( & param . type_ ) ; if ! param_type . is_plain ( ) { ref_list . push ( offset ) ; } params_debug . push ( VarDebug { offset , line : param . base ( ) . location . start . row , name : name . clone ( ) , var_type : TypeDebug :: from_annotation ( & param . type_ ) , } ) } // Collect infos for local variables and nested functions let mut locals_debug = vec ! [ ] ; let mut local_offset = if level == 0 { - 8 } else { - 16 } ; for declaration in & function . declarations { match declaration { Declaration :: VarDef ( v ) => { let name = & v . var . identifier . name ; let offset = local_offset ; local_offset -= 8 ; locals . insert ( name . clone ( ) , LocalSlot :: Var ( VarSlot { offset , level : level + 1 , } ) , ) ; locals_debug . push ( VarDebug { offset , line : v . base ( ) . location . start . row , name : name . clone ( ) , var_type : TypeDebug :: from_annotation ( & v . var . type_ ) , } ) } Declaration :: FuncDef ( f ) => { let name = & f . name . name ; locals . insert ( name . clone ( ) , LocalSlot :: Func ( FuncSlot { link_name : link_name . clone ( ) + " " + name , level : level + 1 , } ) , ) ; } _ => ( ) , } } let mut handle = storage_env . push ( locals ) ; let return_type = ValueType :: from_annotation ( & function . return_type ) ; let mut code = Emitter :: new ( & link_name , Some ( & return_type ) , Some ( handle . inner ( ) ) , Some ( classes ) , ref_list , level , platform , ) ; if level != 0 { // Save static link let static_link = code . alloc_stack ( TicketType :: Plain ) ; // mov [rbp+{}],r10 code . emit_with_stack ( & [ 0x4C , 0x89 , 0x95 ] , & static_link ) ; static_link . free_on_exit ( ) ; } // Initialize local variables for declaration in & function . declarations { if let Declaration :: VarDef ( v ) = declaration { code . emit_local_var_init ( v ) ; } } let mut lines = vec ! [ LineMap { code_pos 0 line_number function base ( ) location start row } ] ; // Generate codes for all statements for statement in & function . statements { code . emit_statement ( statement , & mut lines ) ; } // Implicit `return None` code . emit_none_literal ( ) ; code . end_proc ( ) ; // Package code into a chunk let mut chunks = vec ! [ code finalize ( ProcedureDebug { decl_line function statements [ 0 ] base ( ) location start row artificial false parent if level 0 { None } else { parent map ( str to_owned ) } lines return_type TypeDebug from_annotation ( function return_type ) params params_debug locals locals_debug frame_size 0 } ) ] ; // Recursively generate codes for nested functions // Note: put children functions after the parent one // so that debug tree can be generated sequentially for declaration in & function . declarations { if let Declaration :: FuncDef ( f ) = declaration { chunks . append ( & mut gen_function ( & f , handle . inner ( ) , classes , level + 1 , Some ( & link_name ) , platform , ) ) ; } } chunks }
Generate machine code for a function
Generate machine code for a function
function
&FuncDef
storage_env
&mut StorageEnv
classes
&HashMap<String, ClassSlot>
level
u32
parent
Option<&str>
platform
Platform