1use std::fmt;
4
5use gc_arena::Collect;
6
7pub use super::ast::FunctionKind;
8use super::{
9    analyzer,
10    codegen::{self, SyntaxError},
11    lexer,
12    opcode::OpCode,
13    parser,
14};
15
16#[derive(Debug, Clone, Collect)]
18#[collect(require_static)]
19pub struct Code {
20    pub params: Vec<String>,
22    pub variadic: Option<String>,
24    pub kind: FunctionKind,
26    pub code: Vec<OpCode>,
28
29    pub consts: Vec<ConstValue>,
31    pub local_names: Vec<String>,
33    pub global_names: Vec<String>,
35    pub upvalue_names: Vec<(String, usize, usize)>,
37
38    pub def_upvalue_count: usize,
40    pub stack_size: usize,
42}
43
44impl fmt::Display for Code {
45    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46        if let Some(v) = &self.variadic {
47            writeln!(f, "params: ({}), *{}", self.params.join(", "), v)?;
48        } else {
49            writeln!(f, "params: ({})", self.params.join(", "))?;
50        }
51        writeln!(f, "kind: {}", self.kind)?;
52        writeln!(f, "stack_size: {}", self.stack_size)?;
53        let mut code_str = String::new();
54        for (i, code) in self.code.iter().enumerate() {
55            code_str.push_str(&format!(
56                "{:>12} {}{}\n",
57                i,
58                code,
59                match code {
60                    OpCode::LoadLocal(i) | OpCode::StoreLocal(i) =>
61                        format!(" ({})", self.local_names[*i]),
62                    OpCode::LoadGlobal(i) | OpCode::StoreGlobal(i) =>
63                        format!(" ({})", self.global_names[*i]),
64                    OpCode::LoadUpvalue(i) | OpCode::StoreUpvalue(i) => {
65                        let t = &self.upvalue_names[*i];
66                        format!(" ({}, {}, {})", t.0, t.1, t.2)
67                    }
68                    OpCode::LoadConst(i) | OpCode::Import(i) | OpCode::ImportFrom(i) =>
69                        format!(" ({})", self.consts[*i]),
70                    _ => "".to_string(),
71                }
72            ));
73        }
74        write!(f, "code:\n{}", code_str)
75    }
76}
77
78impl PartialEq for Code {
79    fn eq(&self, _: &Self) -> bool {
80        false
81    }
82}
83
84impl fmt::Display for FunctionKind {
85    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
86        match self {
87            FunctionKind::Function => write!(f, "Function"),
88            FunctionKind::Closure => write!(f, "Closure"),
89            FunctionKind::Do => write!(f, "Do"),
90        }
91    }
92}
93
94#[derive(Debug, Clone, PartialEq)]
96pub enum ConstValue {
97    Null,
99    Bool(bool),
101    Int(i64),
103    Float(f64),
105    Str(String),
107    Func(Code),
109}
110
111impl fmt::Display for ConstValue {
112    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
113        match self {
114            Self::Null => write!(f, "null"),
115            Self::Bool(v) => write!(f, "{}", v),
116            Self::Int(v) => write!(f, "{}", v),
117            Self::Float(v) => write!(f, "{}", v),
118            Self::Str(v) => write!(f, "{}", v),
119            Self::Func(_) => write!(f, "<code>"),
120        }
121    }
122}
123
124impl TryFrom<&str> for Code {
125    type Error = SyntaxError;
126
127    fn try_from(value: &str) -> Result<Self, Self::Error> {
128        codegen::gen_code(analyzer::analyze(
129            parser::Parser::new(&mut lexer::tokenize(value)).parse()?,
130        ))
131    }
132}
133
134impl TryFrom<&String> for Code {
135    type Error = SyntaxError;
136
137    fn try_from(value: &String) -> Result<Self, Self::Error> {
138        codegen::gen_code(analyzer::analyze(
139            parser::Parser::new(&mut lexer::tokenize(value)).parse()?,
140        ))
141    }
142}