Fixed table indexing and construction, declarations and some instructions. Builds and passes indexing test.

This commit is contained in:
Christian Lincoln 2026-08-28 13:53:28 +01:00 committed by paladin
parent 93599ff5d7
commit 1e288b3948
5 changed files with 2984 additions and 2773 deletions

View file

@ -1,10 +1,14 @@
// COMPILER // COMPILER
use crate::parser::{
Args, Block, Call, Chunk, Constructor, Expression, Function, LoadError, Name, Piece, Prefix,
Statement, VarArg, Variable,
};
use crate::table::{Equivalent, Hashed, Hashes, Map, TableEntry};
use crate::vm::{Code, Index, Machine, Offset, Prototype, Reference, Value};
use std::cmp::PartialEq; use std::cmp::PartialEq;
use std::ops::Deref;
use std::rc::Rc; use std::rc::Rc;
use crate::parser::{Piece,Expression,Statement,Name,Block,Chunk,Variable,VarArg,Call,Args,Function,Prefix,Constructor,LoadError,Number};
use crate::vm::{Machine, Prototype, Code, Value, Index, Reference, Offset, MarsError};
use crate::table::{Equivalent,Hashes,Map,Hashed,TableEntry};
pub(crate) struct Traversal<'a> { pub(crate) struct Traversal<'a> {
// A 'cursor' of where we are in assumed execution // A 'cursor' of where we are in assumed execution
@ -21,7 +25,7 @@ pub(crate) struct Context {
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
struct ConstantEntry(Value,Index); struct ConstantEntry(Value, Index);
impl Equivalent<Self> for ConstantEntry { impl Equivalent<Self> for ConstantEntry {
fn matches(&self, other: &Self) -> bool { fn matches(&self, other: &Self) -> bool {
@ -43,10 +47,10 @@ impl Hashes for ConstantEntry {
impl TableEntry for ConstantEntry { impl TableEntry for ConstantEntry {
fn new_vacant() -> Self { fn new_vacant() -> Self {
ConstantEntry(Value::Nil,0) ConstantEntry(Value::Nil, 0)
} }
fn is_vacant(&self) -> bool { fn is_vacant(&self) -> bool {
matches!(self.0,Value::Nil) matches!(self.0, Value::Nil)
} }
} }
@ -137,20 +141,33 @@ impl Traversal<'_> {
prototype.code.len() - 1 prototype.code.len() - 1
} }
fn insert_code(&mut self, location: usize, it: Code) { fn insert_code(&mut self, location: usize, it: Code) {
// slightly dangerous since it doesn't consider scopes
self.last_context().prototype.code[location] = it; self.last_context().prototype.code[location] = it;
} }
fn push_constant(&mut self, it: Value) -> Index { fn push_constant(&mut self, it: Value) -> Index {
// todo: constants need pieces too!!! // todo: constants need pieces too!!!
// don't use constants that already exist // don't use constants that already exist
if let Some(entry) = &mut self.contexts.last_mut().unwrap().constants.get_table(it.clone()) { if let Some(entry) = &mut self
.contexts
.last_mut()
.unwrap()
.constants
.get_table(it.clone())
{
entry.1 entry.1
} else { } else {
let index = { let index = {
let constants = &mut self.contexts.last_mut().unwrap().prototype.constants; let constants = &mut self.contexts.last_mut().unwrap().prototype.constants;
constants.push(it.clone()); constants.push(it.clone());
constants.len() - 1 constants.len() - 1
}.try_into().unwrap(); }
self.contexts.last_mut().unwrap().constants.set_table(ConstantEntry(it,index)); .try_into()
.unwrap();
self.contexts
.last_mut()
.unwrap()
.constants
.set_table(ConstantEntry(it, index));
index index
} }
} }
@ -158,13 +175,14 @@ impl Traversal<'_> {
let constant = self.push_constant(it); let constant = self.push_constant(it);
self.push_code(piece.swap(Code::Constant(constant))); self.push_code(piece.swap(Code::Constant(constant)));
} }
fn push_string(&mut self, string: String, piece: Piece<()>) -> Result<(),LoadError> { fn push_string(&mut self, string: String, piece: Piece<()>) -> Result<(), LoadError> {
match self.machine.new_string(string.clone().as_str()) { match self.machine.new_string(string.clone().as_str()) {
Err(error) => Err(LoadError(error.0,piece)), Err(error) => Err(LoadError(error.0, piece)),
Ok(string) => Ok(self.push_literal(string, piece)), Ok(string) => Ok(self.push_literal(string, piece)),
} }
} }
fn new_scope(&mut self) { // Make some new scope fn new_scope(&mut self) {
// Make some new scope
let index = self.last_scope().index; let index = self.last_scope().index;
self.contexts.last_mut().unwrap().scopes.push(Scope { self.contexts.last_mut().unwrap().scopes.push(Scope {
index, index,
@ -174,9 +192,11 @@ impl Traversal<'_> {
upvalue: false, upvalue: false,
}); });
} }
fn temp_scope(&mut self) -> Index { // Make a new scope with index++ fn temp_scope(&mut self) -> Index {
// Make a new scope with index++
self.new_scope(); self.new_scope();
if self.last_context().scopes.len() > 2 { // For the dummy scope if self.last_context().scopes.len() > 2 {
// For the dummy scope
self.last_scope().index += 1; self.last_scope().index += 1;
} }
self.last_scope().index self.last_scope().index
@ -218,8 +238,12 @@ impl Traversal<'_> {
} }
pub(crate) fn close_context(&mut self) -> Result<Prototype, LoadError> { pub(crate) fn close_context(&mut self) -> Result<Prototype, LoadError> {
let mut context = self.contexts.pop().unwrap(); let mut context = self.contexts.pop().unwrap();
for jump in context.scopes.pop().unwrap().jumps { // Get back the dummy one and error any jumps for jump in context.scopes.pop().unwrap().jumps {
return Err(LoadError::from_str(format!("{:?}",jump).as_str(), &Piece::<()>::null())) // todo: we need Vec or some append in LoadError and also BlindJumps need pieces! // Get back the dummy one and error any jumps
return Err(LoadError::from_str(
format!("{:?}", jump).as_str(),
&Piece::<()>::null(),
)); // todo: we need Vec or some append in LoadError and also BlindJumps need pieces!
} }
Ok(context.prototype) Ok(context.prototype)
} }
@ -227,7 +251,8 @@ impl Traversal<'_> {
Traversal { Traversal {
machine, machine,
contexts: vec![Context { contexts: vec![Context {
scopes: vec![Scope { // Dummy scope scopes: vec![Scope {
// Dummy scope
index: 0, index: 0,
jumps: vec![], jumps: vec![],
labels: vec![], labels: vec![],
@ -264,7 +289,7 @@ fn compile_function(
if method { if method {
self_arguments.push("self".to_string()); self_arguments.push("self".to_string());
} }
self_arguments.append(&mut this.it.0.iter().map(|it| it.it.0.clone()).collect()); self_arguments.append(&mut this.it.args.iter().map(|it| it.it.0.clone()).collect());
let mut argument_scopes = vec![Scope { let mut argument_scopes = vec![Scope {
// Dummy initial scope so the rest can start from index = 0 (since there can be zero arguments!!) // Dummy initial scope so the rest can start from index = 0 (since there can be zero arguments!!)
index: 0, index: 0,
@ -287,13 +312,13 @@ fn compile_function(
traversal.contexts.push(Context { traversal.contexts.push(Context {
vararg: this vararg: this
.it .it
.1 .vararg
.as_ref() .as_ref()
.map(|it| it.swap(it.clone().it.0.map(|string| string.0.clone()))), .map(|it| it.swap(it.clone().it.0.map(|string| string.0.clone()))),
scopes: argument_scopes, scopes: argument_scopes,
prototype: Prototype { prototype: Prototype {
args: this.it.0.len().try_into().unwrap(), args: this.it.args.len().try_into().unwrap(),
vararg: this.it.1.is_some(), vararg: this.it.vararg.is_some(),
prototypes: vec![], prototypes: vec![],
constants: vec![], constants: vec![],
upvalues: vec![Reference::Upvalue(0)], // _ENV upvalues: vec![Reference::Upvalue(0)], // _ENV
@ -302,7 +327,7 @@ fn compile_function(
}, },
constants: Map::new(), constants: Map::new(),
}); });
traversal.compile(&this.it.2.inner_ref())?; // compile the block traversal.compile(&this.it.block.inner_ref())?; // compile the block
let prototype = traversal.close_context()?; let prototype = traversal.close_context()?;
let prototypes = &mut traversal.last_context().prototype.prototypes; // add this to the upper function's prototypes list let prototypes = &mut traversal.last_context().prototype.prototypes; // add this to the upper function's prototypes list
let index = prototypes.len().try_into().unwrap(); let index = prototypes.len().try_into().unwrap();
@ -399,7 +424,7 @@ fn compile_identifier(
} }
} }
// break 'search avoids this use of the _G table // break 'search avoids this use of the _G table
traversal.push_string(name.it.clone(),name.unit())?; traversal.push_string(name.it.clone(), name.unit())?;
traversal.push_code(name.swap(Code::UpvalueGet(0))); traversal.push_code(name.swap(Code::UpvalueGet(0)));
traversal.push_code(name.swap(match access { traversal.push_code(name.swap(match access {
Access::Set => Code::TableSet, Access::Set => Code::TableSet,
@ -474,17 +499,17 @@ impl Compile for Piece<&Args> {
impl Compile for Piece<&Call> { impl Compile for Piece<&Call> {
fn compile(&self, traversal: &mut Traversal) -> Result<(), LoadError> { fn compile(&self, traversal: &mut Traversal) -> Result<(), LoadError> {
traversal.compile(&self.it.0.as_ref().inner_ref())?; // call prefix traversal.compile(&self.it.prefix.as_ref().inner_ref())?; // call prefix
match &self.it.1 { match &self.it.method {
Some(name) => { Some(name) => {
traversal.push_string(name.it.0.clone(),name.unit())?; traversal.push_string(name.it.0.clone(), name.unit())?;
traversal.push_code(name.swap(Code::TableGet)); traversal.push_code(name.swap(Code::TableGet));
} }
None => {} None => {}
} }
let index = traversal.index().unwrap(); let index = traversal.index().unwrap();
traversal.compile(&self.it.2.inner_ref())?; // arguments traversal.compile(&self.it.args.inner_ref())?; // arguments
traversal.push_code(self.it.0.unit().end().swap(Code::Call(index))); // Our responsibility to discard here traversal.push_code(self.it.prefix.unit().end().swap(Code::Call(index))); // Our responsibility to discard here
Ok(()) Ok(())
} }
} }
@ -562,20 +587,26 @@ impl Compile for Piece<&Constructor> {
traversal.push_code(self.swap(Code::TableNew)); traversal.push_code(self.swap(Code::TableNew));
let index_table = traversal.index().unwrap(); let index_table = traversal.index().unwrap();
for field in self.it.0.iter() { for field in self.it.0.iter() {
match &field.it.0 { match &field.it.index {
Some(index) => { Some(index) => {
traversal.compile(&index.inner_ref())?; traversal.compile(&index.inner_ref())?;
traversal.push_code(field.it.1.swap(Code::RegisterGet(index_table)).start()); traversal.push_code(
traversal.push_code(field.it.1.swap(Code::TableSet)); field
.it
.expression
.swap(Code::RegisterGet(index_table))
.start(),
);
traversal.push_code(field.it.expression.swap(Code::TableSet));
} }
None => { None => {
match &field.it.1.it { match &field.it.expression.it {
Expression::VarArg(vararg) => { Expression::VarArg(vararg) => {
traversal.compile(&field.it.1.swap(vararg))?; traversal.compile(&field.it.expression.swap(vararg))?;
traversal.push_code(field.it.1.swap(Code::VarArg(0))); traversal.push_code(field.it.expression.swap(Code::VarArg(0)));
} }
it => { it => {
traversal.compile(&field.it.1.swap(it))?; traversal.compile(&field.it.expression.swap(it))?;
} }
} }
let index = traversal let index = traversal
@ -586,8 +617,14 @@ impl Compile for Piece<&Constructor> {
.last() .last()
.unwrap() .unwrap()
.index; .index;
traversal.push_code(field.it.1.swap(Code::RegisterGet(index_table)).start()); traversal.push_code(
traversal.push_code(field.it.1.swap(Code::TableInsert(index))); field
.it
.expression
.swap(Code::RegisterGet(index_table))
.start(),
);
traversal.push_code(field.it.expression.swap(Code::TableInsert(index)));
} }
} }
} }
@ -609,13 +646,19 @@ impl Compile for Piece<&Expression> {
} }
Expression::Number(number) => { Expression::Number(number) => {
let number = number let number = number
.0
.parse::<u64>()
.map(|it| Value::Integer(it))
.unwrap_or(Value::Number(
number
.0 .0
.parse::<f64>() .parse::<f64>()
.map_err(|it| LoadError(it.to_string(), self.unit()))?; .map_err(|it| LoadError(it.to_string(), self.unit()))?,
traversal.push_literal(Value::Number(number), self.unit()); ));
traversal.push_literal(number, self.unit());
} }
Expression::String(string) => { Expression::String(string) => {
traversal.push_string(string.clone(),self.unit())?; traversal.push_string(string.clone(), self.unit())?;
} }
Expression::VarArg(vararg) => { Expression::VarArg(vararg) => {
traversal.compile(&self.swap(vararg))?; traversal.compile(&self.swap(vararg))?;
@ -649,7 +692,7 @@ fn jump_from(here: usize, there: usize) -> Result<Offset, LoadError> {
} }
fn resolve_break(traversal: &mut Traversal, begin: usize, end: usize) -> Result<(), LoadError> { fn resolve_break(traversal: &mut Traversal, begin: usize, end: usize) -> Result<(), LoadError> {
for jump in std::mem::replace(&mut traversal.last_scope().jumps,Vec::new()) { for jump in std::mem::replace(&mut traversal.last_scope().jumps, Vec::new()) {
// ? // ?
match jump { match jump {
BlindJump::Continue(index) => { BlindJump::Continue(index) => {
@ -672,11 +715,10 @@ fn compile_assignment(
let mut variables_iter = variables.iter().peekable(); let mut variables_iter = variables.iter().peekable();
let mut expressions_iter = expressions.iter().peekable(); let mut expressions_iter = expressions.iter().peekable();
while let Some(expression) = expressions_iter.next() { while let Some(expression) = expressions_iter.next() {
let compile_variable_expression = | // Compile a variable normally with one value from an expression let compile_variable_expression = |// Compile a variable normally with one value from an expression
traversal: &mut Traversal, traversal: &mut Traversal,
variable: Option<&Piece<Variable>>, variable: Option<&Piece<Variable>>,
expression: &Piece<&Expression> expression: &Piece<&Expression>|
|
-> Result<(), LoadError> { -> Result<(), LoadError> {
let index = traversal.index().unwrap(); let index = traversal.index().unwrap();
traversal.compile(expression)?; traversal.compile(expression)?;
@ -691,8 +733,8 @@ fn compile_assignment(
// If this is the last expression it CAN have multiplicity // If this is the last expression it CAN have multiplicity
match &expression.it { match &expression.it {
Expression::Prefix(prefix) => { Expression::Prefix(prefix) => {
match &**prefix { match **prefix {
Prefix::Call(call) => { Prefix::Call(ref call) => {
// multiple // multiple
let mut index = traversal.index().unwrap(); let mut index = traversal.index().unwrap();
traversal.compile(&expression.swap(call))?; traversal.compile(&expression.swap(call))?;
@ -701,9 +743,12 @@ fn compile_assignment(
index += 1; // The index we would need to pad nil to or restrict to index += 1; // The index we would need to pad nil to or restrict to
compile_variable(variable.inner_ref(), traversal, Access::Set)?; // Pops each return value off the stack compile_variable(variable.inner_ref(), traversal, Access::Set)?; // Pops each return value off the stack
} }
traversal.insert_code(index_discard, Code::Discard(index.try_into().unwrap())); traversal.insert_code(
index_discard,
Code::Discard(index.try_into().unwrap()),
);
} }
prefix => { ref prefix => {
if let Some(variable) = variables_iter.next() { if let Some(variable) = variables_iter.next() {
traversal.compile(&expression.swap(prefix))?; traversal.compile(&expression.swap(prefix))?;
compile_variable(variable.inner_ref(), traversal, Access::Set)? compile_variable(variable.inner_ref(), traversal, Access::Set)?
@ -720,7 +765,8 @@ fn compile_assignment(
count += 1; count += 1;
compile_variable(variable.inner_ref(), traversal, Access::Set)?; compile_variable(variable.inner_ref(), traversal, Access::Set)?;
} }
traversal.insert_code(index_vararg, Code::VarArg(count.try_into().unwrap())); traversal
.insert_code(index_vararg, Code::VarArg(count.try_into().unwrap()));
} }
} }
_ => { _ => {
@ -755,7 +801,8 @@ impl Compile for Piece<&Block> {
index index
}; };
// todo: for some reason, register indices are called "<thing>_index" and code indices "index_<thing>"? fix it // todo: for some reason, register indices are called "<thing>_index" and code indices "index_<thing>"? fix it
for statement in self.it.0.iter() { // todo: maybe refactor this so that there are less indents
for statement in self.it.statements.iter() {
let piece = statement.unit(); let piece = statement.unit();
match &statement.it { match &statement.it {
Statement::Semicolon => {} Statement::Semicolon => {}
@ -932,7 +979,9 @@ impl Compile for Piece<&Block> {
let index = traversal.index().unwrap(); let index = traversal.index().unwrap();
traversal.push_code( traversal.push_code(
block block
.swap(Code::Discard((index as usize + names.len()).try_into().unwrap())) .swap(Code::Discard(
(index as usize + names.len()).try_into().unwrap(),
))
.start(), .start(),
); );
for name in names.iter() { for name in names.iter() {
@ -976,10 +1025,10 @@ impl Compile for Piece<&Block> {
while let Some(name) = names.next() { while let Some(name) = names.next() {
if !names.peek().is_some() { if !names.peek().is_some() {
compile_function(&self.swap(function), traversal, is_method)?; compile_function(&self.swap(function), traversal, is_method)?;
traversal.push_string(name.it.0.clone(),name.unit())?; traversal.push_string(name.it.0.clone(), name.unit())?;
traversal.push_code(name.unit().end().swap(Code::TableSet)); traversal.push_code(name.unit().end().swap(Code::TableSet));
} else { } else {
traversal.push_string(name.it.0.clone(),name.unit())?; traversal.push_string(name.it.0.clone(), name.unit())?;
traversal.push_code(name.unit().end().swap(Code::TableGet)); traversal.push_code(name.unit().end().swap(Code::TableGet));
} }
} }
@ -992,19 +1041,107 @@ impl Compile for Piece<&Block> {
traversal.push_code(name.swap(Code::RegisterSet(index)).end()); traversal.push_code(name.swap(Code::RegisterSet(index)).end());
} }
Statement::Declaration(names, expressions) => { Statement::Declaration(names, expressions) => {
let variables = &names let mut expressions_iter = expressions.iter().peekable();
.iter() let mut names_iter = names.iter().peekable();
.map(|name| { let compile_declaration = |traversal: &mut Traversal,
var_scope(traversal, name.it.0.clone()); expression: &Piece<Expression>,
name.swap(Variable::Name(name.it.clone())) name: &Piece<Name>|
}) -> Result<(), LoadError> {
.collect(); traversal.compile(&expression.inner_ref())?;
compile_assignment(traversal, variables, expressions)?; traversal.last_scope().symbol = Some(name.it.0.clone());
Ok(())
};
while names_iter.peek().is_some() {
match (expressions_iter.next(), expressions_iter.peek().is_none()) {
(Some(expression), true) => {
// expression is last, has multiplicity
match expression.it {
Expression::VarArg(ref vararg) => {
let names: Vec<&Piece<Name>> = names_iter.collect();
traversal.compile(&expression.swap(vararg))?; // for error checking only
traversal.push_code(
expression.swap(Code::VarArg(
names.len().try_into().unwrap(),
)),
);
let mut scopes =
traversal.last_context().scopes.iter_mut().rev();
for name in names.iter().rev() {
scopes.next().unwrap().symbol = Some(name.it.0.clone());
}
}
Expression::Prefix(ref prefix) => {
match prefix.deref() {
Prefix::Call(call) => {
let names: Vec<&Piece<Name>> = names_iter.collect();
traversal.compile(&expression.swap(call))?;
let index = (traversal.index().unwrap_or(0)
as usize
+ names.len())
.try_into()
.unwrap();
traversal.push_code(
expression.swap(Code::Discard(index)).end(),
); // discard and extend to names
let mut scopes = traversal
.last_context()
.scopes
.iter_mut()
.rev();
for name in names.iter().rev() {
scopes.next().unwrap().symbol =
Some(name.it.0.clone());
}
}
_ => compile_declaration(
traversal,
expression,
names_iter.next().unwrap(),
)?,
}
}
_ => compile_declaration(
traversal,
expression,
names_iter.next().unwrap(),
)?,
}
break;
}
(Some(expression), false) => compile_declaration(
traversal,
expression,
names_iter.next().unwrap(),
)?, // expression is not last, just use it
(None, ..) => {
// no more expressions
let index = traversal.index().unwrap_or(0) as usize;
traversal.push_code(
names_iter
.next()
.unwrap()
.swap(Code::Discard(
(index + names_iter.count()).try_into().unwrap(),
))
.end(),
);
break;
}
}
}
let index = traversal.index().unwrap_or(0);
// clear up the remaining expressions and discard if they existed
if expressions_iter.peek().is_some() {
while let Some(expression) = expressions_iter.next() {
traversal.compile(&expression.inner_ref())?
}
traversal.push_code(Piece::<()>::null().swap(Code::Discard(index)));
}
} }
} }
} }
// Any 'dangling' scopes that weren't closed (declarations) will be at the end of this block // Any 'dangling' scopes that weren't closed (declarations) will be at the end of this block
if let Some(return_expressions) = &self.it.1 { if let Some(return_expressions) = &self.it.return_exp {
// arguments are backwards // arguments are backwards
for return_expression in return_expressions.iter().rev() { for return_expression in return_expressions.iter().rev() {
traversal.compile(&return_expression.inner_ref())?; traversal.compile(&return_expression.inner_ref())?;
@ -1024,7 +1161,7 @@ impl Compile for Chunk {
} }
} }
pub(crate) fn compile(chunk: &Chunk, machine: &mut Machine) -> Result<Prototype,LoadError> { pub(crate) fn compile(chunk: &Chunk, machine: &mut Machine) -> Result<Prototype, LoadError> {
let mut traversal = Traversal::new(machine); let mut traversal = Traversal::new(machine);
traversal.compile(chunk)?; traversal.compile(chunk)?;
traversal.close_context() traversal.close_context()

View file

@ -1,9 +1,8 @@
// PARSER // PARSER
use std::fmt::Formatter;
use std::hash::{DefaultHasher, Hash, Hasher};
use std::ops::{Add, Deref, DerefMut};
use crate::vm::{Index, RunError}; use crate::vm::{Index, RunError};
use std::fmt::Formatter;
use std::ops::Add;
// TODO: Vec<Piece<T>> is good but sometimes we either need at least one or none, current fix is just to check if there is one and if not skip it, this takes extra performance // TODO: Vec<Piece<T>> is good but sometimes we either need at least one or none, current fix is just to check if there is one and if not skip it, this takes extra performance
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
@ -47,7 +46,7 @@ impl LoadError {
roll roll
} }
fn from_runtime(piece: Piece<()>, error: RunError) -> LoadError { fn from_runtime(piece: Piece<()>, error: RunError) -> LoadError {
LoadError(error.0,piece) LoadError(error.0, piece)
} }
} }
@ -335,12 +334,9 @@ impl Parse for Number {
if end == 0 { if end == 0 {
reader.error("Could not parse number".into()) reader.error("Could not parse number".into())
} else { } else {
let number = reader.slice[..end].to_string();
reader.slice = &reader.slice[end..]; reader.slice = &reader.slice[end..];
Ok(Piece::of( Ok(Piece::of(Number(number), reader, end))
Number(reader.slice[..end].to_string()),
reader,
end,
))
} }
} }
} }
@ -426,7 +422,10 @@ impl Parse for String {
// AST // AST
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct Block(pub(crate) Vec<Piece<Statement>>, pub(crate) Option<Vec<Piece<Expression>>>); // pub(crate) struct Block {
pub(crate) statements: Vec<Piece<Statement>>,
pub(crate) return_exp: Option<Vec<Piece<Expression>>>,
} //
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct Chunk(pub(crate) Piece<Block>); pub(crate) struct Chunk(pub(crate) Piece<Block>);
#[derive(Debug)] #[derive(Debug)]
@ -494,13 +493,24 @@ pub(crate) enum Prefix {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub(crate) struct VarArg(pub(crate) Option<Name>); pub(crate) struct VarArg(pub(crate) Option<Name>);
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct Call(pub(crate) Box<Piece<Prefix>>, pub(crate) Option<Piece<Name>>, pub(crate) Piece<Args>); pub(crate) struct Call {
pub(crate) prefix: Box<Piece<Prefix>>,
pub(crate) method: Option<Piece<Name>>,
pub(crate) args: Piece<Args>,
}
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct Args(pub(crate) Vec<Piece<Expression>>); pub(crate) struct Args(pub(crate) Vec<Piece<Expression>>);
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct Function(pub(crate) Vec<Piece<Name>>, pub(crate) Option<Piece<VarArg>>, pub(crate) Piece<Block>); pub(crate) struct Function {
pub(crate) args: Vec<Piece<Name>>,
pub(crate) vararg: Option<Piece<VarArg>>,
pub(crate) block: Piece<Block>,
}
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct Field(pub(crate) Option<Piece<Expression>>, pub(crate) Piece<Expression>); pub(crate) struct Field {
pub(crate) index: Option<Piece<Expression>>,
pub(crate) expression: Piece<Expression>,
}
#[derive(Debug)] #[derive(Debug)]
pub(crate) enum FieldSep { pub(crate) enum FieldSep {
Comma, Comma,
@ -701,7 +711,11 @@ impl Parse for Function {
let block = reader.take::<Block>()?; let block = reader.take::<Block>()?;
reader.white_consume("end")?; reader.white_consume("end")?;
Ok(Piece::from( Ok(Piece::from(
Function(pre_parameters, vararg, block), Function {
args: pre_parameters,
vararg: vararg,
block: block,
},
&start, &start,
&end, &end,
)) ))
@ -857,14 +871,23 @@ impl Parse for Field {
reader.consume_white("=")?; reader.consume_white("=")?;
let value = reader.take::<Expression>()?; let value = reader.take::<Expression>()?;
reader.consume_white("]")?; reader.consume_white("]")?;
Field(Some(index), value) Field {
index: Some(index),
expression: value,
}
} else if let Ok(name) = reader.take::<Name>() { } else if let Ok(name) = reader.take::<Name>() {
reader.consume_white("=")?; reader.consume_white("=")?;
let index = name.map(|it| Expression::String(it.0)); let index = name.map(|it| Expression::String(it.0));
let value = reader.take::<Expression>()?; let value = reader.take::<Expression>()?;
Field(Some(index), value) Field {
index: Some(index),
expression: value,
}
} else { } else {
Field(None, reader.take::<Expression>()?) Field {
index: None,
expression: reader.take::<Expression>()?,
}
}; };
Ok(Piece::from(result, &start, &reader.marker())) Ok(Piece::from(result, &start, &reader.marker()))
} }
@ -940,9 +963,17 @@ impl Parse for Prefix {
} else if reader.consume_white(":").is_ok() { } else if reader.consume_white(":").is_ok() {
let field = reader.take::<Name>()?; let field = reader.take::<Name>()?;
let args = reader.take::<Args>()?; let args = reader.take::<Args>()?;
Prefix::Call(Call(current, Some(field), args)) Prefix::Call(Call {
prefix: current,
method: Some(field),
args: args,
})
} else if let Ok(args) = reader.take::<Args>() { } else if let Ok(args) = reader.take::<Args>() {
Prefix::Call(Call(current, None, args)) Prefix::Call(Call {
prefix: current,
method: None,
args: args,
})
} else { } else {
break; break;
}; };
@ -1180,7 +1211,10 @@ impl Parse for Block {
None None
}; };
Ok(Piece::from( Ok(Piece::from(
Block(statements, expressions), Block {
statements: statements,
return_exp: expressions,
},
&start, &start,
&reader.marker(), &reader.marker(),
)) ))
@ -1208,7 +1242,10 @@ impl Parse for Chunk {
}; };
Ok(Piece::from( Ok(Piece::from(
Chunk(Piece::from( Chunk(Piece::from(
Block(statements, expressions), Block {
statements: statements,
return_exp: expressions,
},
&start, &start,
&reader.marker(), &reader.marker(),
)), )),

View file

@ -25,16 +25,19 @@ Notes:
type Displacement = u8; type Displacement = u8;
#[cfg(feature="bighash")] #[cfg(feature = "bighash")]
pub type Hashed = u64; pub type Hashed = u64;
#[cfg(not(feature="bighash"))] #[cfg(not(feature = "bighash"))]
pub type Hashed = u32; pub type Hashed = u32;
pub trait Equivalent<T>: Sized { pub trait Equivalent<T>: Sized {
fn matches(&self, other: &T) -> bool; fn matches(&self, other: &T) -> bool;
} }
impl<T> Equivalent<T> for T where T: PartialEq { impl<T> Equivalent<T> for T
where
T: PartialEq,
{
fn matches(&self, other: &T) -> bool { fn matches(&self, other: &T) -> bool {
self == other self == other
} }
@ -75,7 +78,13 @@ impl TableEntry for KeyValue {
} }
} }
fn is_vacant(&self) -> bool { fn is_vacant(&self) -> bool {
matches!(self,KeyValue { index: Value::Nil, .. }) matches!(
self,
KeyValue {
index: Value::Nil,
..
}
)
} }
} }
@ -87,7 +96,8 @@ struct Entry<E> {
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Map<E: TableEntry + Clone> { // default representing vacancy! pub struct Map<E: TableEntry + Clone> {
// default representing vacancy!
map: Vec<Entry<E>>, map: Vec<Entry<E>>,
map_bounds: std::ops::Range<usize>, map_bounds: std::ops::Range<usize>,
map_count: usize, // number of elements in table map_count: usize, // number of elements in table
@ -95,14 +105,19 @@ pub struct Map<E: TableEntry + Clone> { // default representing vacancy!
impl<E: TableEntry + Clone> Map<E> { impl<E: TableEntry + Clone> Map<E> {
pub(crate) fn string_cache() { // todo: this isn't a clean way, maybe make a generic Map and use a specific one for the cache and the rest of the language pub(crate) fn string_cache() { // todo: this isn't a clean way, maybe make a generic Map and use a specific one for the cache and the rest of the language
} }
fn exchange_table(&mut self, len: usize) { fn exchange_table(&mut self, len: usize) {
let old = std::mem::replace(&mut self.map, vec![Entry { let old = std::mem::replace(
&mut self.map,
vec![
Entry {
entry: E::new_vacant(), entry: E::new_vacant(),
home: 0, home: 0,
displacement: 0, displacement: 0,
}; len]); };
len
],
);
for Entry { entry, .. } in old { for Entry { entry, .. } in old {
if entry.is_vacant() { if entry.is_vacant() {
self.set_table(entry) self.set_table(entry)
@ -202,7 +217,11 @@ impl<E: TableEntry + Clone> Map<E> {
self.set_table(entry); self.set_table(entry);
} }
} }
pub(crate) fn rem_table<K>(&mut self, index: K) where E: Equivalent<K>, K: Hashes { pub(crate) fn rem_table<K>(&mut self, index: K)
where
E: Equivalent<K>,
K: Hashes,
{
if self.map.len() == 0 { if self.map.len() == 0 {
return; return;
} }
@ -256,9 +275,12 @@ impl<E: TableEntry + Clone> Map<E> {
} }
} }
pub(crate) fn get_table<K>(&mut self, index: K) -> Option<&E> pub(crate) fn get_table<K>(&mut self, index: K) -> Option<&E>
where E: Equivalent<K>, K: Hashes { where
E: Equivalent<K>,
K: Hashes,
{
if self.map.len() == 0 { if self.map.len() == 0 {
return None return None;
} }
let location = index.hashed() as usize % self.map.len(); let location = index.hashed() as usize % self.map.len();
let home = &self.map[location]; let home = &self.map[location];
@ -377,7 +399,7 @@ impl Table {
} else { } else {
self.table.set_table(KeyValue { self.table.set_table(KeyValue {
index: Value::Integer(index), index: Value::Integer(index),
value: item value: item,
}) })
} }
} }
@ -387,25 +409,28 @@ impl Table {
Value::Nil => Err(RunError( Value::Nil => Err(RunError(
"Attempt to set new index of table with key: nil".to_string(), "Attempt to set new index of table with key: nil".to_string(),
)), )),
index => Ok(self.table.set_table(KeyValue { index => Ok(self.table.set_table(KeyValue { index, value })),
index,
value
})),
} }
} }
pub fn get(&mut self, index: Value) -> Result<Value, RunError> { pub fn get(&mut self, index: Value) -> Result<Value, RunError> {
match index { match index {
Value::Integer(index) => Ok(self Value::Integer(index) => Ok(self
.array .array
.get(index as usize) .get(index as usize - 1)
.unwrap_or(&Value::Nil) .unwrap_or(&Value::Nil)
.clone()), .clone()),
Value::Nil => Err(RunError("Attempt to index table with key: nil".to_string())), Value::Nil => Err(RunError("Attempt to index table with key: nil".to_string())),
index => { // todo: move this into the Map index => {
Ok(self.table.get_table(index).unwrap_or(&KeyValue { // todo: move this into the Map
Ok(self
.table
.get_table(index)
.unwrap_or(&KeyValue {
index: Value::Nil, index: Value::Nil,
value: Value::Nil, value: Value::Nil,
}).value.clone()) })
.value
.clone())
} }
} }
} }

View file

@ -1 +1,2 @@
local table = {} local table = { "hello", "friend" }
print(table[1], table[2])

View file

@ -1,12 +1,12 @@
// MACHINE // MACHINE
use crate::parser::{BinaryOp, Piece, UnaryOp, parse};
use crate::table::{Equivalent, Hashed, Hashes, Map, Table, TableEntry};
use std::any::Any; use std::any::Any;
use std::fmt::Formatter; use std::fmt::Formatter;
use std::hash::{DefaultHasher, Hash, Hasher}; use std::hash::{DefaultHasher, Hash, Hasher};
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use std::rc::Rc; use std::rc::Rc;
use crate::table::{Equivalent, Hashed, Hashes, Map, Table, TableEntry};
use crate::parser::{Piece, BinaryOp, UnaryOp, parse};
// Rust function to call // Rust function to call
pub struct Native(fn(&mut Machine, &mut Needle, usize) -> Result<(), RunError>); // A native function in Rust pub struct Native(fn(&mut Machine, &mut Needle, usize) -> Result<(), RunError>); // A native function in Rust
@ -156,9 +156,7 @@ pub trait Object: std::fmt::Debug {
} }
} }
impl Value { impl Value {}
}
pub trait Userdata: Traverse + std::fmt::Debug + Any + Object {} pub trait Userdata: Traverse + std::fmt::Debug + Any + Object {}
@ -176,10 +174,10 @@ impl Traverse for Anything {
} }
} }
use crate::compiler::compile;
use crate::gc::{Allocator, Gc, Traverse};
#[cfg(feature = "vector3")] #[cfg(feature = "vector3")]
use glam::Vec3; use glam::Vec3;
use crate::gc::{Allocator, Gc, Traverse};
use crate::compiler::{Traversal, Context, Scope, compile};
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
struct Phrase { struct Phrase {
@ -207,7 +205,8 @@ impl Hashes for CachedStringEntry {
} }
} }
impl Equivalent<Self> for CachedStringEntry { // redundant? impl Equivalent<Self> for CachedStringEntry {
// redundant?
fn matches(&self, other: &Self) -> bool { fn matches(&self, other: &Self) -> bool {
match self.0 { match self.0 {
Some(ref entry) => match other.0 { Some(ref entry) => match other.0 {
@ -232,7 +231,7 @@ impl Equivalent<&str> for CachedStringEntry {
fn matches(&self, string: &&str) -> bool { fn matches(&self, string: &&str) -> bool {
match self.0 { match self.0 {
Some(ref entry) => entry.0.deref() == *string, Some(ref entry) => entry.0.deref() == *string,
None => false None => false,
} }
} }
} }
@ -264,8 +263,8 @@ impl Value {
fn unwrap_str(&mut self) -> Rc<str> { fn unwrap_str(&mut self) -> Rc<str> {
match self { match self {
Value::CachedString(cached) => cached.0.clone(), Value::CachedString(cached) => cached.0.clone(),
Value::String(string,_hash) => string.clone(), Value::String(string, _hash) => string.clone(),
_ => panic!() _ => panic!(),
} }
} }
} }
@ -276,58 +275,61 @@ impl PartialEq for Value {
Value::Nil => match other { Value::Nil => match other {
Value::Nil => true, Value::Nil => true,
_ => false, _ => false,
} },
Value::Bool(this) => match other { Value::Bool(this) => match other {
Value::Bool(other) => this == other, Value::Bool(other) => this == other,
_ => false, _ => false,
} },
Value::Number(this) => match other { Value::Number(this) => match other {
Value::Number(other) => this == other, Value::Number(other) => this == other,
Value::Integer(other) => *this == *other as f64, Value::Integer(other) => *this == *other as f64,
_ => false, _ => false,
} },
Value::Integer(this) => match other { Value::Integer(this) => match other {
Value::Number(other) => *this as f64 == *other, // are these conversions ok? Value::Number(other) => *this as f64 == *other, // are these conversions ok?
Value::Integer(other) => this == other, Value::Integer(other) => this == other,
_ => false, _ => false,
} },
Value::String(string, hash) => match other { Value::String(string, hash) => match other {
Value::CachedString(other) => Value::CachedString(other) => {
if *hash == other.1 { if *hash == other.1 {
other.0.deref() == string.deref() other.0.deref() == string.deref()
} else { } else {
false false
} }
Value::String(other_string, other_hash) => }
Value::String(other_string, other_hash) => {
if hash == other_hash { if hash == other_hash {
string == other_string string == other_string
} else { } else {
false false
} }
_ => false
} }
_ => false,
},
Value::CachedString(string) => match other { Value::CachedString(string) => match other {
Value::CachedString(other) => other.0 == string.0, // pointer equality Value::CachedString(other) => other.0 == string.0, // pointer equality
Value::String(other_string, other_hash) => Value::String(other_string, other_hash) => {
if string.1 == *other_hash { if string.1 == *other_hash {
string.0.deref() == other_string.deref() string.0.deref() == other_string.deref()
} else { } else {
false false
} }
_ => false
} }
_ => false,
},
Value::Table(this) => match other { Value::Table(this) => match other {
Value::Table(other) => other == this, Value::Table(other) => other == this,
_ => false _ => false,
} },
Value::Object(this) => match other { Value::Object(this) => match other {
Value::Object(other) => other == this, Value::Object(other) => other == this,
_ => false _ => false,
} },
Value::Function(this) => match other { Value::Function(this) => match other {
Value::Function(other) => other == this, Value::Function(other) => other == this,
_ => false _ => false,
} },
} }
} }
} }
@ -359,7 +361,7 @@ pub struct Frame {
pub struct Machine { pub struct Machine {
global: Gc<Table>, global: Gc<Table>,
allocator: Allocator, allocator: Allocator,
cache: Map<CachedStringEntry> // todo: better to use a generic version of Map cache: Map<CachedStringEntry>, // todo: better to use a generic version of Map
} }
/* /*
@ -440,16 +442,15 @@ impl Code {
} }
impl Machine { impl Machine {
pub(crate) fn new_string(&mut self, string: &str) -> Result<Value,RunError> { pub(crate) fn new_string(&mut self, string: &str) -> Result<Value, RunError> {
if string.len() < SHORT_STRING_LEN { if string.len() < SHORT_STRING_LEN {
let existing = self.cache.get_table(string); let existing = self.cache.get_table(string);
match existing { match existing {
Some(ref entry) => { Some(ref entry) => Ok(Value::CachedString(entry.0.clone().unwrap())),
Ok(Value::CachedString(entry.0.clone().unwrap()))
},
None => { None => {
let cached = CachedString(Rc::from(string),string.hashed()); let cached = CachedString(Rc::from(string), string.hashed());
self.cache.set_table(CachedStringEntry(Some(cached.clone()))); self.cache
.set_table(CachedStringEntry(Some(cached.clone())));
Ok(Value::CachedString(cached)) Ok(Value::CachedString(cached))
} }
} }
@ -504,7 +505,7 @@ impl Machine {
Value::Bool(bool) => Err(RunError(format!("Cannot index {:?}", bool))), Value::Bool(bool) => Err(RunError(format!("Cannot index {:?}", bool))),
Value::Integer(_integer) => Err(RunError("Integer index unimplemented".to_string())), Value::Integer(_integer) => Err(RunError("Integer index unimplemented".to_string())),
Value::Number(_number) => Err(RunError("Number index unimplemented".to_string())), Value::Number(_number) => Err(RunError("Number index unimplemented".to_string())),
Value::String(.. ) | Value::CachedString(.. ) => { Value::String(..) | Value::CachedString(..) => {
Err(RunError("String index unimplemented".to_string())) Err(RunError("String index unimplemented".to_string()))
} }
#[cfg(feature = "vector3")] #[cfg(feature = "vector3")]
@ -527,7 +528,7 @@ impl Machine {
Value::Bool(bool) => Err(RunError(format!("Cannot index {:?}", bool))), Value::Bool(bool) => Err(RunError(format!("Cannot index {:?}", bool))),
Value::Integer(_integer) => Err(RunError("Integer index unimplemented".to_string())), Value::Integer(_integer) => Err(RunError("Integer index unimplemented".to_string())),
Value::Number(_number) => Err(RunError("Number index unimplemented".to_string())), Value::Number(_number) => Err(RunError("Number index unimplemented".to_string())),
Value::String(..) | Value::CachedString(.. ) => { Value::String(..) | Value::CachedString(..) => {
Err(RunError("String index unimplemented".to_string())) Err(RunError("String index unimplemented".to_string()))
} }
#[cfg(feature = "vector3")] #[cfg(feature = "vector3")]
@ -678,7 +679,13 @@ impl Machine {
if needle.stack.len() > 65536 { if needle.stack.len() > 65536 {
return Err(RunError("Soft stack limit of 65536 reached".to_string())); return Err(RunError("Soft stack limit of 65536 reached".to_string()));
} }
let code = frame.closure.borrow_mut().prototype.code.get(frame.counter).cloned(); let code = frame
.closure
.borrow_mut()
.prototype
.code
.get(frame.counter)
.cloned();
let code = match code { let code = match code {
Some(code) => code, Some(code) => code,
None => { None => {
@ -694,9 +701,7 @@ impl Machine {
Code::Comment(number) => { Code::Comment(number) => {
eprintln!("{}", number) eprintln!("{}", number)
} }
Code::TableNew => { Code::TableNew => needle.push(Value::Table(self.allocator.alloc(Table::new()))),
needle.push(Value::Table(self.allocator.alloc(Table::new())))
}
Code::TableSet => { Code::TableSet => {
let table = needle.pop(); let table = needle.pop();
let index = needle.pop(); let index = needle.pop();
@ -712,7 +717,7 @@ impl Machine {
match needle.pop() { match needle.pop() {
Value::Table(mut table) => { Value::Table(mut table) => {
for i in frame.offset + index as usize..needle.stack.len() { for i in frame.offset + index as usize..needle.stack.len() {
table.borrow_mut().append(needle.stack[i].value.clone()) table.borrow_mut().append(needle.pop())
} }
} }
_ => { _ => {
@ -986,12 +991,18 @@ impl Machine {
let string = machine.new_string("print").unwrap(); let string = machine.new_string("print").unwrap();
machine.global.borrow_mut().set( machine.global.borrow_mut().set(
string, string,
Value::Function(Callable::Rust(Rc::from(Native(|machine: &mut Machine, needle: &mut Needle, index: usize| -> Result<(), RunError> { Value::Function(Callable::Rust(Rc::from(Native(
|machine: &mut Machine,
needle: &mut Needle,
index: usize|
-> Result<(), RunError> {
for i in index..needle.stack.len() { for i in index..needle.stack.len() {
println!("{}",machine.try_string(&mut needle.pop())?.unwrap_str()) print!("{} ", machine.try_string(&mut needle.pop())?.unwrap_str())
} }
println!();
Ok(()) Ok(())
})))) },
)))),
)?; )?;
Ok(machine) Ok(machine)
} }