use std::{collections::HashMap, rc::Rc};
use super::{
variables::{VariableAllocation, VariablePlace},
CodeGenerator, ExpressionResult,
};
use crate::ll::{
ast::{Ast, NodeId},
bytecode::{Opcode, Opr24},
error::{LanguageError, LanguageErrorKind},
};
#[derive(Debug, Default)]
pub(super) struct StructData {
pub(crate) fields: HashMap<Rc<str>, Opr24>,
pub(crate) receiver: Option<VariablePlace>,
}
impl StructData {
pub(super) fn get_or_create_field(&mut self, name: &str) -> Result<Opr24, LanguageErrorKind> {
if !self.fields.contains_key(name) {
let index =
Opr24::try_from(self.fields.len()).map_err(|_| LanguageErrorKind::TooManyFields)?;
self.fields.insert(Rc::from(name), index);
Ok(index)
} else {
Ok(*self.fields.get(name).unwrap())
}
}
pub(super) fn get_field(&self, name: &str) -> Option<Opr24> {
self.fields.get(name).copied()
}
}
impl<'e> CodeGenerator<'e> {
pub(super) fn generate_field(
&mut self,
ast: &Ast,
node: NodeId,
) -> Result<ExpressionResult, LanguageError> {
let (name, _) = ast.node_pair(node);
let name = ast.string(name).unwrap();
let struct_data = self
.struct_data
.as_deref()
.ok_or_else(|| ast.error(node, LanguageErrorKind::FieldOutsideOfImpl))?;
let field_id = struct_data.get_field(name).ok_or_else(|| {
ast.error(node, LanguageErrorKind::FieldDoesNotExist(Rc::clone(name)))
})?;
let receiver = struct_data.receiver.unwrap();
self.generate_variable_load(receiver);
self.chunk.emit((Opcode::GetField, field_id));
Ok(ExpressionResult::Present)
}
pub(super) fn generate_struct(
&mut self,
ast: &Ast,
node: NodeId,
) -> Result<ExpressionResult, LanguageError> {
let (name, _) = ast.node_pair(node);
let name = ast.string(name).unwrap();
self.chunk.emit(Opcode::CreateType);
self.chunk.emit_string(name);
let variable = self
.create_variable(name, VariableAllocation::Allocate)
.map_err(|kind| ast.error(node, kind))?;
self.generate_variable_assign(variable);
Ok(ExpressionResult::Present)
}
}