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}