use super::*;
use crate::reader::Offset;
use crate::value::Parselet;
use indexmap::IndexMap;
use log;
use std::cell::RefCell;
use std::rc::Rc;
#[derive(Debug, Clone)]
pub(in crate::compiler) struct ImlParseletModel {
pub is_consuming: bool, pub locals: usize, pub signature: IndexMap<String, Option<ImlValue>>, pub variables: IndexMap<String, usize>, pub temporaries: Vec<usize>, pub begin: ImlOp, pub end: ImlOp, pub body: ImlOp, }
impl ImlParseletModel {
pub fn new(signature: Option<IndexMap<String, Option<ImlValue>>>) -> Self {
let signature = signature.unwrap_or(IndexMap::new());
let variables = signature
.keys()
.enumerate()
.map(|(index, key)| (key.to_string(), index))
.collect();
Self {
is_consuming: false,
locals: signature.len(),
signature,
variables,
temporaries: Vec::new(),
begin: ImlOp::Nop,
end: ImlOp::Nop,
body: ImlOp::Nop,
}
}
pub fn id(&self) -> usize {
self as *const ImlParseletModel as usize
}
fn allocate(&mut self) -> usize {
let addr = self.locals;
self.locals += 1;
addr
}
pub fn var(&mut self, name: &str) -> usize {
match self.variables.get(name) {
Some(addr) => *addr,
None => {
let addr = self.allocate();
self.variables.insert(name.to_string(), addr);
addr
}
}
}
pub fn temp(&mut self) -> usize {
match self.temporaries.pop() {
Some(addr) => addr,
None => self.allocate(),
}
}
pub fn untemp(&mut self, addr: usize) {
self.temporaries.push(addr)
}
}
#[allow(dead_code)]
#[derive(Debug)]
pub(in crate::compiler) struct ImlParselet {
pub model: Rc<RefCell<ImlParseletModel>>, pub generics: IndexMap<String, Option<ImlValue>>, pub origin: Option<ImlRefParselet>, pub offset: Option<Offset>, pub name: Option<String>, pub severity: u8, pub is_generated: bool, }
impl ImlParselet {
pub fn new(
model: Option<ImlParseletModel>,
generics: Option<IndexMap<String, Option<ImlValue>>>,
origin: Option<ImlRefParselet>,
offset: Option<Offset>,
name: Option<String>,
severity: u8,
is_generated: bool,
) -> Self {
Self {
model: Rc::new(RefCell::new(model.unwrap_or(ImlParseletModel::new(None)))),
generics: generics.unwrap_or(IndexMap::new()),
origin,
offset,
name,
severity,
is_generated,
}
}
pub fn id(&self) -> usize {
self as *const ImlParselet as usize
}
}
impl std::fmt::Display for ImlParselet {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
self.name.as_deref().unwrap_or("__AnonymousParselet__")
)?;
if !self.generics.is_empty() {
write!(f, "<")?;
for (i, (name, value)) in self.generics.iter().enumerate() {
if let Some(value) = value {
write!(f, "{}{}:{}", if i > 0 { ", " } else { "" }, name, value)?;
} else {
write!(f, "{}{}", if i > 0 { ", " } else { "" }, name)?;
}
}
write!(f, ">")?;
}
Ok(())
}
}
impl std::cmp::PartialEq for ImlParselet {
fn eq(&self, other: &Self) -> bool {
self.model.borrow().id() == other.model.borrow().id() && self.generics == other.generics
}
}
impl Eq for ImlParselet {}
impl std::hash::Hash for ImlParselet {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
let model = &*self.model.borrow();
(model as *const ImlParseletModel as usize).hash(state);
self.generics.iter().collect::<Vec<_>>().hash(state);
}
}
impl std::cmp::PartialOrd for ImlParselet {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
self.id().partial_cmp(&other.id())
}
}
#[derive(Clone, Eq, PartialEq)]
pub(in crate::compiler) struct ImlRefParselet {
parselet: Rc<RefCell<ImlParselet>>,
}
impl ImlRefParselet {
pub fn new(parselet: ImlParselet) -> Self {
Self {
parselet: Rc::new(RefCell::new(parselet)),
}
}
pub fn resolve(&self, name: &str) -> Option<ImlValue> {
let mut origin = Some(self.clone());
while let Some(inner) = origin {
if let Some(value) = inner.borrow().generics.get(name) {
return Some(value.clone()?);
} else {
origin = inner.borrow().origin.clone();
}
}
None
}
pub fn derive(&self, from: &ImlRefParselet) -> Result<Self, String> {
let parselet = self.parselet.borrow();
if parselet.generics.is_empty() {
return Ok(self.clone());
}
let mut generics = parselet.generics.clone();
let mut changes = false;
let mut required = Vec::new();
log::debug!(" deriving {} from {}", self, from);
for (name, value) in generics.iter_mut() {
while let Some(ImlValue::Generic { name, .. }) = value {
if name == "Self" || name == "self" {
*value = Some(ImlValue::Parselet(from.clone()));
} else {
*value = from.resolve(name);
}
changes = true;
}
if changes && matches!(value, Some(ImlValue::SelfToken | ImlValue::SelfValue)) {
*value = Some(ImlValue::Parselet(from.clone()));
}
if value.is_none() {
required.push(name.to_string());
}
}
if !required.is_empty() {
return Err(format!(
"'{}' requires assignment of generic argument '{}'",
parselet.name.as_deref().unwrap_or("__AnonymousParselet__"),
required.join(", ")
));
}
if !changes {
log::debug!(" no derivation");
return Ok(self.clone());
}
let derived = Self::new(ImlParselet {
model: parselet.model.clone(),
generics,
origin: from.borrow().origin.clone(),
offset: parselet.offset.clone(),
name: parselet.name.clone(),
severity: parselet.severity,
is_generated: parselet.is_generated,
});
log::debug!(" derived = {}", derived);
Ok(derived)
}
pub fn compile(&self, program: &mut ImlProgram, index: usize) -> Parselet {
let parselet = self.parselet.borrow();
let model = parselet.model.borrow();
log::debug!("compiling {}", parselet);
Parselet::new(
Some(format!("{}", parselet)),
None,
parselet.severity,
model
.signature
.iter()
.map(|var_value| {
(
var_value.0.clone(),
var_value
.1
.as_ref()
.and_then(|value| Some(program.register(value).unwrap_or_default())),
)
})
.collect(),
model.locals,
model.begin.compile_to_vec(program, (self, index)),
model.end.compile_to_vec(program, (self, index)),
model.body.compile_to_vec(program, (self, index)),
)
}
}
impl std::hash::Hash for ImlRefParselet {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.parselet.borrow().hash(state);
}
}
impl std::fmt::Debug for ImlRefParselet {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.parselet.borrow())
}
}
impl std::fmt::Display for ImlRefParselet {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.parselet.borrow())
}
}
impl std::ops::Deref for ImlRefParselet {
type Target = Rc<RefCell<ImlParselet>>;
fn deref(&self) -> &Self::Target {
&self.parselet
}
}
impl std::ops::DerefMut for ImlRefParselet {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.parselet
}
}
impl From<ImlRefParselet> for ImlValue {
fn from(parselet: ImlRefParselet) -> Self {
ImlValue::Parselet(parselet)
}
}