Fixed loop instructions, local registers in other instructions, upvalues and tables. Builds and passes test.

This commit is contained in:
paladin 2026-08-29 13:33:48 +01:00
parent 110e035efd
commit 60c097518a
9 changed files with 229 additions and 151 deletions

View file

@ -346,13 +346,13 @@ fn compile_identifier(
traversal: &mut Traversal,
access: Access,
) -> Result<(), LoadError> {
let length = traversal.contexts.len();
for i in 0..length {
let contexts_len = traversal.contexts.len();
for context_index in 0..contexts_len {
// For each context
let i = length - i - 1; // From top to bottom
if i == length - 1 {
let context_index = contexts_len - context_index - 1; // From top to bottom
if context_index == contexts_len - 1 {
// If this is our context
for scope in traversal.contexts[i].scopes.iter().rev() {
for scope in traversal.contexts[context_index].scopes.iter().rev() {
// Go through the scopes
if scope.symbol.as_ref().is_some_and(|it| it.eq(&name.it)) {
// Find it
@ -366,36 +366,23 @@ fn compile_identifier(
}
} else {
// Otherwise it's another function's 'scope'(s)
let length = traversal.contexts[i].scopes.len();
for j in 0..length {
let scopes_len = traversal.contexts[context_index].scopes.len();
for scope_index in 0..scopes_len {
// For each scope in that foreign context
let j = length - j - 1; // From top to bottom
if traversal.contexts[i].scopes[j]
let scope_index = scopes_len - scope_index - 1; // From top to bottom
if traversal.contexts[context_index].scopes[scope_index]
.symbol
.as_ref()
.is_some_and(|it| it.eq(&name.it))
{
// Go through...
// todo: fix this comment it's talking about something i ended up dropping
/*
So here we know this 'traversal.contexts[i]' is the function holding the upvalue
in 'scopes[j]', if it has an upvalue already made, we use its 'prototype.closing'
index and set our initial rolling variable 'reference' to Reference::Register('index').
This is significant because this 'upvalue' MUST be made in this owning function's
prototype's closing list, but 'reference' also acts as a variable holding the upvalue
that the current function in the loop 'for k in j+1..length' produced so that the next
function context can reference it, this also means that the last 'reference' after the
loop is sort of vacuously a 'Reference::Upvalue' that is only storing our 'index'
for the eventual instruction itself.
*/
let register = traversal.contexts[i].scopes[j].index;
traversal.contexts[i].scopes[j].upvalue = true;
let register = traversal.contexts[context_index].scopes[scope_index].index;
traversal.contexts[context_index].scopes[scope_index].upvalue = true;
let mut reference = Reference::Closing(register);
// its important that a few conditions are held here e.g. length > 2, j < length + 1...
for k in j + 1..length {
for down_context_index in context_index + 1..contexts_len {
// Ok now going from every context to the one wanting the upvalue
// set reference to what we found for the next context
reference = match traversal.contexts[k]
reference = match traversal.contexts[down_context_index]
.prototype
.upvalues
.iter()
@ -404,8 +391,14 @@ fn compile_identifier(
Some(index) => Reference::Upvalue(index.try_into().unwrap()),
None => {
// we don't even have a reference to this in our upvalues so add it
let length = traversal.contexts[k].prototype.upvalues.len();
traversal.contexts[k].prototype.upvalues.push(reference);
let length = traversal.contexts[down_context_index]
.prototype
.upvalues
.len();
traversal.contexts[down_context_index]
.prototype
.upvalues
.push(reference);
Reference::Upvalue(length.try_into().unwrap()) // Reference (child) to this reference to that reference (parent) for next context
}
}
@ -499,6 +492,8 @@ impl Compile for Piece<&Args> {
impl Compile for Piece<&Call> {
fn compile(&self, traversal: &mut Traversal) -> Result<(), LoadError> {
let index = traversal.index().map(|it| it + 1).unwrap_or(0); // there will always be at least the callable
traversal.compile(&self.it.args.inner_ref())?; // arguments
traversal.compile(&self.it.prefix.as_ref().inner_ref())?; // call prefix
match &self.it.method {
Some(name) => {
@ -507,8 +502,6 @@ impl Compile for Piece<&Call> {
}
None => {}
}
let index = traversal.index().unwrap();
traversal.compile(&self.it.args.inner_ref())?; // arguments
traversal.push_code(self.it.prefix.unit().end().swap(Code::Call(index))); // Our responsibility to discard here
Ok(())
}
@ -720,7 +713,7 @@ fn compile_assignment(
variable: Option<&Piece<Variable>>,
expression: &Piece<&Expression>|
-> Result<(), LoadError> {
let index = traversal.index().unwrap();
let index = traversal.index().unwrap_or(0);
traversal.compile(expression)?;
if let Some(variable) = variable {
compile_variable(variable.inner_ref(), traversal, Access::Set)?;
@ -794,12 +787,6 @@ impl Compile for Piece<&Block> {
fn compile(&self, traversal: &mut Traversal) -> Result<(), LoadError> {
let last_scope_index = traversal.index().unwrap_or(0);
let mut depth = 0; // Counter for 'dangling' scopes produced by any declarations to be closed.
let mut var_scope = |traversal: &mut Traversal, symbol: String| -> Index {
let index = traversal.temp_scope();
traversal.last_scope().symbol = Some(symbol);
depth += 1;
index
};
// todo: for some reason, register indices are called "<thing>_index" and code indices "index_<thing>"? fix it
// todo: maybe refactor this so that there are less indents
for statement in self.it.statements.iter() {
@ -928,27 +915,16 @@ impl Compile for Piece<&Block> {
}
}
Statement::Range(var, init, limit, step, block) => {
let init_index = traversal.temp_scope(); // init
traversal.compile(&init.inner_ref())?;
traversal.push_code(init.swap(Code::RegisterSet(init_index)));
let limit_index = traversal.temp_scope(); // limit
traversal.compile(&limit.inner_ref())?;
traversal.push_code(limit.swap(Code::RegisterSet(limit_index)));
let step_index = traversal.temp_scope(); // step;
match step {
Some(expression) => traversal.compile(&expression.inner_ref())?,
None => traversal.push_literal(Value::Integer(1), limit.unit().end()),
};
let piece = match step {
Some(expression) => expression.unit().start(),
None => limit.unit().end(),
};
traversal.push_code(piece.swap(Code::RegisterSet(step_index)));
let index_loop =
traversal.push_code(block.unit().start().swap(Code::RangeBegin)) + 1;
var_scope(traversal, var.it.0.clone());
traversal.temp_scope();
traversal.last_scope().symbol = Some(var.it.0.clone());
traversal.compile(&block.inner_ref())?;
traversal.close_scope(); // temporary for v
let index_jump = traversal.push_code(block.unit().start().swap(Code::UNSURE)); // Dummy NOP
@ -957,9 +933,7 @@ impl Compile for Piece<&Block> {
Code::RangeLoop(jump_from(index_jump, index_loop)?),
); // Reinsert into above
resolve_break(traversal, index_loop, index_jump + 1)?;
traversal.close_scope();
traversal.close_scope();
traversal.close_scope(); // init, limit, step
traversal.consume_scope(3); // init, limit, step
}
Statement::Iterator(names, expressions, block) => {
let mut iterator_variables = Vec::new();
@ -1035,10 +1009,9 @@ impl Compile for Piece<&Block> {
}
}
Statement::LocalFunction(name, function) => {
var_scope(traversal, name.it.0.clone());
let index = traversal.index().unwrap();
traversal.compile(&self.swap(function))?;
traversal.push_code(name.swap(Code::RegisterSet(index)).end());
traversal.last_scope().symbol = Some(name.it.0.clone());
depth += 1;
}
Statement::Declaration(names, expressions) => {
let mut expressions_iter = expressions.iter().peekable();
@ -1068,6 +1041,7 @@ impl Compile for Piece<&Block> {
traversal.last_context().scopes.iter_mut().rev();
for name in names.iter().rev() {
scopes.next().unwrap().symbol = Some(name.it.0.clone());
depth += 1;
}
}
Expression::Prefix(ref prefix) => {
@ -1091,28 +1065,38 @@ impl Compile for Piece<&Block> {
for name in names.iter().rev() {
scopes.next().unwrap().symbol =
Some(name.it.0.clone());
depth += 1;
}
}
_ => compile_declaration(
traversal,
expression,
names_iter.next().unwrap(),
)?,
_ => {
compile_declaration(
traversal,
expression,
names_iter.next().unwrap(),
)?;
depth += 1;
}
}
}
_ => compile_declaration(
traversal,
expression,
names_iter.next().unwrap(),
)?,
_ => {
compile_declaration(
traversal,
expression,
names_iter.next().unwrap(),
)?;
depth += 1;
}
}
break;
}
(Some(expression), false) => compile_declaration(
traversal,
expression,
names_iter.next().unwrap(),
)?, // expression is not last, just use it
(Some(expression), false) => {
compile_declaration(
traversal,
expression,
names_iter.next().unwrap(),
)?;
depth += 1;
} // expression is not last, just use it
(None, ..) => {
// no more expressions
let index = traversal.index().unwrap_or(0) as usize;