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
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
//! Information about possible Cardinal instructions.

use crate::entities::{Block, Value, ValueInfo};
use crate::instbuilder::InstBuilder;

#[derive(Clone, Copy)]
pub enum Opcode {

    Add,
    Sub,
    Mul,
    Div,
    Mod,
    BitAnd,
    BitOr,
    BitXor,
    BitLeft,
    BitRight,
    BitNot,
    TestEq,
    TestNeq,
    TestGt,
    TestGtEq,
    TestLt,
    TestLtEq,
    Not,
    Or,
    And,
    Jmp,
    Set,
    Call,
    Ret,

}

/// Information about an instruction or operation.
#[derive(Clone)]
pub struct InstructionInfo {

    /// The opcode of the instruction.
    pub opcode: Opcode,

    /// The arguments provided with the instruction.
    pub arguments: Vec<Value>,

}

/// A block type for creating different kinds of blocks.
#[derive(Clone, Copy)]
pub enum BlockType {

    /// A basic IF type that uses a value as an expression.
    If(Value),

    /// A basic block with no conditions.
    Basic,

}

/// A block for instruction building.
#[derive(Clone)]
pub struct InstBlock {

    /// The type of the block.
    pub block_type: BlockType,

    /// A list of elseif statements for the block, if any.
    pub elses: Vec<InstBlock>,

    /// An else_block for If blocks.
    pub else_block: Option<Box<InstBlock>>,

    /// A list of values defined in the block.
    pub values: Vec<ValueInfo>,

    /// A list of instructions in the block.
    pub insts: Vec<InstructionInfo>,

    /// A list of imports in the block.
    pub imports: Vec<String>,

    /// A list of nested blocks in the block.
    pub blocks: Vec<InstBlock>,

}

impl InstBuilder for InstBlock {

    fn require_import(&mut self, name: String) {
        if !self.imports.contains(&name) {
            self.imports.push(name);
        }
    }

    fn create_value(&mut self, value: ValueInfo) -> Value {
        let val = Value(self.values.len() as u32);
        self.values.push(value);

        val
    }

    fn create_block(&mut self, block: InstBlock) -> Block {
        let val = Block(self.blocks.len() as u32);
        self.blocks.push(block);

        val
    }

    fn create_inst(&mut self, inst: InstructionInfo) {
        self.insts.push(inst);
    }

    fn use_block(&mut self, block: Block) -> &mut InstBlock {
        self.blocks.get_mut(block.0 as usize).unwrap()
    }

}