1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
mod byte_code;
mod byte_expr;
mod first_pass;
mod second_pass;
mod third_pass;

use std::fmt;

use crate::program::CompilableFn;

pub use byte_code::{
    Arg, FieldAccess, Instruction, InstructionPointerType, JumpTarget,
    Location, RelJumpTarget,
};

pub use byte_expr::fn_id as to_fn_id;

use crate::analysis::Traverser;

#[derive(Debug, Clone)]
pub struct ByteCodeFunction {
    instructions: Vec<Instruction>,
    validated_flag: bool,
}

impl ByteCodeFunction {
    pub fn new_not_validated(
        instructions: Vec<Instruction>,
    ) -> ByteCodeFunction {
        ByteCodeFunction {
            instructions: instructions,
            validated_flag: false,
        }
    }

    pub fn new_pre_validated(
        instructions: Vec<Instruction>,
    ) -> ByteCodeFunction {
        ByteCodeFunction {
            instructions: instructions,
            validated_flag: true,
        }
    }

    pub fn validate(mut self) -> ByteCodeFunction {
        self.validated_flag = true;
        self
    }

    pub fn is_validated(&self) -> bool {
        self.validated_flag
    }

    pub fn instructions(&self) -> &[Instruction] {
        &self.instructions
    }
}

impl fmt::Display for ByteCodeFunction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        for instr in self.instructions.iter() {
            writeln!(f, "{}", instr)?;
        }

        Ok(())
    }
}

/// Takes a CFG and transforms it into valid and executable bytecode
pub fn compile_to_byte_code(function: &CompilableFn) -> ByteCodeFunction {
    let cfg = function.cfg();
    let cfg = cfg.borrow();
    let typing_context = function.typing_context();

    // Goes through the CFG and collects the main function body, loops, and branches
    //   into organized groups of instructions with metadata
    let mut first_pass = first_pass::FirstPass::new(typing_context);
    {
        let traverser = Traverser::new(&*cfg, &mut first_pass);

        traverser.traverse().unwrap();
    }

    // Takes the data from the first pass and combines all branches and loops together
    //   into a single chunk of instructions
    // This pass leaves break/continue meta instructions to be resolved later
    let second_pass: second_pass::SecondPass = first_pass.into();

    // Takes the data from the second pass and resolves break/continue statements
    //   to jump to the correct index
    let third_pass = third_pass::ThirdPass::new(second_pass.pass());

    ByteCodeFunction::new_pre_validated(third_pass.pass())
}