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
//! The Code that runs in LVM.

use std::fmt::Display;

pub use crate::ast::FunctionKind;
use crate::opcode::OpCode;

/// A Code, generated by codegen and executed in LVM.
#[derive(Debug, Clone)]
pub struct Code {
    /// Name of parameters.
    pub params: Vec<String>,
    /// Name of variadic parameter.
    pub variadic: Option<String>,
    /// Funciton kind.
    pub kind: FunctionKind,
    /// Bytecode, a list of OpCodes.
    pub code: Vec<OpCode>,

    /// List of constants used in the bytecode.
    pub consts: Vec<ConstlValue>,
    /// List of local names.
    pub local_names: Vec<String>,
    /// List of global names.
    pub global_names: Vec<String>,
    /// List of Upvalue information.
    pub upvalue_names: Vec<(String, usize, usize)>,

    /// The count of upvalues defined in the funciton.
    pub def_upvalue_count: usize,
    /// The required virtual machine stack space.
    pub stack_size: usize,
}

impl Display for Code {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        if let Some(v) = &self.variadic {
            writeln!(f, "params: ({}), *{}", self.params.join(", "), v)?;
        } else {
            writeln!(f, "params: ({})", self.params.join(", "))?;
        }
        writeln!(f, "kind: {}", self.kind)?;
        writeln!(f, "stack_size: {}", self.stack_size)?;
        let mut code_str = String::new();
        for (i, code) in self.code.iter().enumerate() {
            code_str.push_str(&format!(
                "{:>12} {}{}\n",
                i,
                code,
                match code {
                    OpCode::LoadLocal(i) | OpCode::StoreLocal(i) =>
                        format!(" ({})", self.local_names[*i]),
                    OpCode::LoadGlobal(i) | OpCode::StoreGlobal(i) =>
                        format!(" ({})", self.global_names[*i]),
                    OpCode::LoadUpvalue(i) | OpCode::StoreUpvalue(i) => {
                        let t = &self.upvalue_names[*i];
                        format!(" ({}, {}, {})", t.0, t.1, t.2)
                    }
                    OpCode::LoadConst(i) | OpCode::Import(i) | OpCode::ImportFrom(i) =>
                        format!(" ({})", self.consts[*i]),
                    _ => "".to_string(),
                }
            ));
        }
        write!(f, "code:\n{}", code_str)
    }
}

impl PartialEq for Code {
    fn eq(&self, _: &Self) -> bool {
        false
    }
}

impl Display for FunctionKind {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            FunctionKind::Funciton => write!(f, "Funciton"),
            FunctionKind::Closure => write!(f, "Closure"),
            FunctionKind::Do => write!(f, "Do"),
        }
    }
}

/// The const value.
#[derive(Debug, Clone, PartialEq)]
pub enum ConstlValue {
    /// "null"
    Null,
    /// "true", "false"
    Bool(bool),
    /// "12", "0o100", "0b110"
    Int(i64),
    /// "12.34", "0b100.100"
    Float(f64),
    /// ""abc"", ""abc"
    Str(String),
    /// A function.
    Func(Code),
}

impl Display for ConstlValue {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::Null => write!(f, "null"),
            Self::Bool(v) => write!(f, "{}", v),
            Self::Int(v) => write!(f, "{}", v),
            Self::Float(v) => write!(f, "{}", v),
            Self::Str(v) => write!(f, "{}", v),
            Self::Func(_) => write!(f, "<code>"),
        }
    }
}