phoenix_lang/
chunk.rs

1use std::collections::HashMap;
2
3use serde::{Deserialize, Serialize};
4
5use crate::resolver::{Resolver, UpValue};
6use crate::scanner::{Scanner, Token};
7use crate::value::Value;
8
9// todo: fix comments
10#[derive(PartialEq, PartialOrd, Debug, Clone, Copy, Serialize, Deserialize)]
11pub enum OpCode {
12    OpReturn,
13    OpPop,
14
15    // Index of the String name for this variable name in the identifiers vec
16    OpDefineGlobal(usize),
17    // ^
18    OpGetGlobal(usize),
19    // ^
20    OpSetGlobal(usize),
21    // ^
22    OpGetSuper(usize),
23    //  module_index, string name, arity
24    OpCallGlobal(usize, usize, usize), // A combination of OpCall and OpGetGlobal
25
26    OpGetModuleVar(usize, usize),
27
28    // Index on the stack
29    OpGetLocal(usize),
30
31    OpSetLocal(usize),
32    // ^
33    /// Combines a GetProperty and a Call. Contains the exact same information. First usize is the index for the property name, second is for the arity, third is for the module index
34    OpInvoke(usize, usize, usize),
35
36    // WIP
37    OpImport(usize),
38    OpGetProperty(usize),
39    // Index of the String name for this variable name in the identifiers vec corresponding with the property name
40    OpSetProperty(usize),
41    // ^
42    // Optimization note: Is there any way to resolve properties at compile time? Phoenix allows arbitrary properties to be added at any time, so I don't believe it's possible
43    OpGetUpvalue(usize),
44    // upvalue index for a closure
45    OpSetUpvalue(usize),
46    // Wraps the top value of the stack (must be a PhoenixFunction) in a PhoenixClosure, capturing the appropriate UpValues at the same time
47    OpClosure,
48
49    // Jump ip offset
50    OpJump(usize),
51    OpJumpIfFalse(usize),
52    // Jump backwards by offset
53    OpLoop(usize),
54    // Arity, module index
55    OpCall(usize, usize),
56    // Index into the classes vec for the ClassChunk object
57    OpClass(usize),
58    // Index of the constant we want to retrieve
59    OpConstant(usize),
60
61    OpNil,
62    OpTrue,
63    OpFalse,
64
65    OpNegate,
66    OpNot,
67
68    OpAdd,
69    OpSubtract,
70    OpMultiply,
71    OpDivide,
72    OpEqual,
73    OpGreater,
74    OpLess,
75
76    OpPrint,
77    // get element of list at index
78    OpGetIndex,
79    // set element of list at index
80    OpSetIndex,
81    // create a new list with the last n elements on the stack
82    OpCreateList(usize),
83    // Push the string on the stack to the heap and replace it with a pointer to the heap
84    OpCreateString,
85    /// Creates a hashmap of the last 2n items, where the first value is the key and the second one is the value
86    OpCreateHashMap(usize),
87    /// Waits until enter is pressed before continuing
88    OpWait,
89}
90
91#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
92pub struct Instr {
93    pub op_code: OpCode,
94    pub line_num: usize,
95}
96
97#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
98pub struct Chunk {
99    pub code: Vec<Instr>,
100}
101
102impl Default for Chunk {
103    fn default() -> Self {
104        Self::new()
105    }
106}
107
108impl Chunk {
109    pub fn write_instruction(&mut self, instruction: Instr) {
110        self.code.push(instruction);
111    }
112
113    pub fn new() -> Chunk {
114        Chunk { code: Vec::new() }
115    }
116}
117
118#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
119pub enum FunctionType {
120    Function,
121    Script,
122    Method,
123    Initializer,
124}
125
126/// Compile time representation of a function, ie its code, name, resolved closure information
127#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
128pub struct FunctionChunk {
129    pub chunk: Chunk,
130    pub name: Option<String>,
131    // None for the top level script
132    pub arity: usize,
133    pub fn_type: FunctionType,
134    pub upvalues: Option<Vec<UpValue>>, // None while the function is being defined and for functions without upvalues. If the function does have upvalues, this field must be set and must be binded with an OpClosure
135}
136
137impl FunctionChunk {
138    pub fn new(name: Option<String>, arity: usize, fn_type: FunctionType) -> FunctionChunk {
139        FunctionChunk {
140            chunk: Chunk::new(),
141            name,
142            arity,
143            fn_type,
144            upvalues: None,
145        }
146    }
147
148    pub fn set_upvalues(&mut self, upvalues: Vec<UpValue>) {
149        self.upvalues = Some(upvalues);
150    }
151}
152
153/// Compile time repr of a class
154#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
155pub struct ClassChunk {
156    pub name: String,
157    pub methods: HashMap<usize, usize>,
158    pub superclass: Option<usize>,
159    pub has_init: bool,
160}
161
162impl ClassChunk {
163    pub fn new(name: String) -> ClassChunk {
164        ClassChunk {
165            name,
166            methods: HashMap::new(),
167            superclass: None,
168            has_init: false,
169        }
170    }
171}
172
173/// Compile time repr of an imported module
174#[derive(Debug, Clone)]
175pub struct CompilerModuleChunk {
176    /// The name of the module
177    pub name: String,
178    /// Whether or not this is the main module
179    pub main: bool,
180    /// The chunk of code for the module
181    pub chunk: Chunk,
182    pub scanner: Scanner,
183    pub tokens: Vec<Token>,
184    pub constants: Vec<Value>,
185    pub functions: Vec<FunctionChunk>,
186    pub classes: Vec<ClassChunk>,
187    pub(crate) current_function: usize,
188    pub current_class: Option<usize>,
189    /// Which FunctionChunk should the the compiler return to after. Acts as a stack
190    pub parent_functions: Vec<usize>,
191    /// Manages the slots for the local variables and upvalues, represented as a Vec of individual ResolverNodes
192    pub resolver: Resolver,
193    pub identifier_constants: Vec<String>,
194    // for now we ignore the init functions in modules
195    pub has_init: bool,
196}
197
198impl CompilerModuleChunk {
199    pub fn new(main: bool, name: String, file: String, code: String) -> CompilerModuleChunk {
200        CompilerModuleChunk {
201            main,
202            name,
203            chunk: Chunk::new(),
204            functions: Vec::new(),
205            constants: Vec::new(),
206            classes: Vec::new(),
207            current_function: 0,
208            current_class: None,
209            parent_functions: vec![],
210            resolver: Resolver::new(),
211            identifier_constants: vec![],
212            has_init: false,
213            scanner: Scanner::new(file, code, 0),
214            tokens: vec![],
215        }
216    }
217}
218
219/// Compile time repr of an imported module, but without the scanner, instead with the file name
220#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
221pub struct ModuleChunk {
222    /// The name of the module
223    pub name: String,
224    /// Whether or not this is the main module
225    pub main: bool,
226    /// The file name of the module
227    pub file: String,
228    pub constants: Vec<Value>,
229    pub identifiers: Vec<String>,
230    pub functions: Vec<FunctionChunk>,
231    pub classes: Vec<ClassChunk>,
232    // for now we ignore the init functions in modules
233    pub has_init: bool,
234}
235
236impl ModuleChunk {
237    pub fn new(main: bool, name: String, file: String) -> ModuleChunk {
238        ModuleChunk {
239            main,
240            name,
241            functions: Vec::new(),
242            constants: Vec::new(),
243            classes: Vec::new(),
244            has_init: false,
245            file,
246            identifiers: vec![],
247        }
248    }
249
250    pub fn from(module: CompilerModuleChunk) -> ModuleChunk {
251        ModuleChunk {
252            main: module.main,
253            name: module.name,
254            functions: module.functions,
255            constants: module.constants,
256            classes: module.classes,
257            has_init: module.has_init,
258            file: module.scanner.file,
259            identifiers: module.identifier_constants,
260        }
261    }
262}