use super::Parser;
use super::Result;
use super::SyntaxError;
use super::UpvalueDesc;
use super::find_last_local;
impl Parser<'_> {
pub(super) fn find_upvalue(&self, name: &str) -> Option<u8> {
self.upvalues
.iter()
.position(|(n, _)| n == name)
.map(|i| i as u8)
}
pub(super) fn resolve_upvalue(&mut self, name: &str) -> Result<Option<u8>> {
self.resolve_upvalue_recursive(name, self.outer_locals.len())
}
fn resolve_upvalue_recursive(&mut self, name: &str, depth: usize) -> Result<Option<u8>> {
if depth == 0 {
return Ok(None);
}
let parent_idx = depth - 1;
let parent_locals = &self.outer_locals[parent_idx];
if let Some(local_idx) = find_last_local(parent_locals, name) {
let idx = self.add_upvalue(name, UpvalueDesc::Local(local_idx as u8))?;
return Ok(Some(idx));
}
let parent_upvalues = &self.outer_upvalues[parent_idx];
if let Some(upvalue_idx) = parent_upvalues.iter().position(|(n, _)| n == name) {
let idx = self.add_upvalue(name, UpvalueDesc::Upvalue(upvalue_idx as u8))?;
return Ok(Some(idx));
}
if parent_idx > 0 {
if let Some(parent_upvalue_idx) = self.create_parent_upvalue(name, parent_idx)? {
let idx = self.add_upvalue(name, UpvalueDesc::Upvalue(parent_upvalue_idx))?;
return Ok(Some(idx));
}
}
Ok(None)
}
fn create_parent_upvalue(&mut self, name: &str, parent_idx: usize) -> Result<Option<u8>> {
if parent_idx > 0 {
let grandparent_idx = parent_idx - 1;
let grandparent_locals = &self.outer_locals[grandparent_idx];
if let Some(local_idx) = find_last_local(grandparent_locals, name) {
let upvalue_idx = self.checked_parent_upvalue_index(parent_idx)?;
self.outer_upvalues[parent_idx]
.push((name.to_string(), UpvalueDesc::Local(local_idx as u8)));
return Ok(Some(upvalue_idx));
}
let grandparent_upvalues = &self.outer_upvalues[grandparent_idx];
if let Some(gp_upvalue_idx) = grandparent_upvalues.iter().position(|(n, _)| n == name) {
let upvalue_idx = self.checked_parent_upvalue_index(parent_idx)?;
self.outer_upvalues[parent_idx]
.push((name.to_string(), UpvalueDesc::Upvalue(gp_upvalue_idx as u8)));
return Ok(Some(upvalue_idx));
}
if grandparent_idx > 0
&& let Some(gp_upvalue_idx) = self.create_parent_upvalue(name, grandparent_idx)?
{
let upvalue_idx = self.checked_parent_upvalue_index(parent_idx)?;
self.outer_upvalues[parent_idx]
.push((name.to_string(), UpvalueDesc::Upvalue(gp_upvalue_idx)));
return Ok(Some(upvalue_idx));
}
}
Ok(None)
}
fn add_upvalue(&mut self, name: &str, desc: UpvalueDesc) -> Result<u8> {
if self.upvalues.len() >= u8::MAX as usize {
return Err(self.error(SyntaxError::TooManyUpvalues));
}
let idx = self.upvalues.len() as u8;
self.upvalues.push((name.to_string(), desc));
Ok(idx)
}
fn checked_parent_upvalue_index(&self, parent_idx: usize) -> Result<u8> {
let len = self.outer_upvalues[parent_idx].len();
if len >= u8::MAX as usize {
Err(self.error(SyntaxError::TooManyUpvalues))
} else {
Ok(len as u8)
}
}
}