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
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::ops::Deref;
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> {
// A 'cursor' of where we are in assumed execution
@ -137,20 +141,33 @@ impl Traversal<'_> {
prototype.code.len() - 1
}
fn insert_code(&mut self, location: usize, it: Code) {
// slightly dangerous since it doesn't consider scopes
self.last_context().prototype.code[location] = it;
}
fn push_constant(&mut self, it: Value) -> Index {
// todo: constants need pieces too!!!
// 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
} else {
let index = {
let constants = &mut self.contexts.last_mut().unwrap().prototype.constants;
constants.push(it.clone());
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
}
}
@ -164,7 +181,8 @@ impl Traversal<'_> {
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;
self.contexts.last_mut().unwrap().scopes.push(Scope {
index,
@ -174,9 +192,11 @@ impl Traversal<'_> {
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();
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
@ -218,8 +238,12 @@ impl Traversal<'_> {
}
pub(crate) fn close_context(&mut self) -> Result<Prototype, LoadError> {
let mut context = self.contexts.pop().unwrap();
for jump in context.scopes.pop().unwrap().jumps { // 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!
for jump in context.scopes.pop().unwrap().jumps {
// 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)
}
@ -227,7 +251,8 @@ impl Traversal<'_> {
Traversal {
machine,
contexts: vec![Context {
scopes: vec![Scope { // Dummy scope
scopes: vec![Scope {
// Dummy scope
index: 0,
jumps: vec![],
labels: vec![],
@ -264,7 +289,7 @@ fn compile_function(
if method {
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 {
// Dummy initial scope so the rest can start from index = 0 (since there can be zero arguments!!)
index: 0,
@ -287,13 +312,13 @@ fn compile_function(
traversal.contexts.push(Context {
vararg: this
.it
.1
.vararg
.as_ref()
.map(|it| it.swap(it.clone().it.0.map(|string| string.0.clone()))),
scopes: argument_scopes,
prototype: Prototype {
args: this.it.0.len().try_into().unwrap(),
vararg: this.it.1.is_some(),
args: this.it.args.len().try_into().unwrap(),
vararg: this.it.vararg.is_some(),
prototypes: vec![],
constants: vec![],
upvalues: vec![Reference::Upvalue(0)], // _ENV
@ -302,7 +327,7 @@ fn compile_function(
},
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 prototypes = &mut traversal.last_context().prototype.prototypes; // add this to the upper function's prototypes list
let index = prototypes.len().try_into().unwrap();
@ -474,8 +499,8 @@ impl Compile for Piece<&Args> {
impl Compile for Piece<&Call> {
fn compile(&self, traversal: &mut Traversal) -> Result<(), LoadError> {
traversal.compile(&self.it.0.as_ref().inner_ref())?; // call prefix
match &self.it.1 {
traversal.compile(&self.it.prefix.as_ref().inner_ref())?; // call prefix
match &self.it.method {
Some(name) => {
traversal.push_string(name.it.0.clone(), name.unit())?;
traversal.push_code(name.swap(Code::TableGet));
@ -483,8 +508,8 @@ impl Compile for Piece<&Call> {
None => {}
}
let index = traversal.index().unwrap();
traversal.compile(&self.it.2.inner_ref())?; // arguments
traversal.push_code(self.it.0.unit().end().swap(Code::Call(index))); // Our responsibility to discard here
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(())
}
}
@ -562,20 +587,26 @@ impl Compile for Piece<&Constructor> {
traversal.push_code(self.swap(Code::TableNew));
let index_table = traversal.index().unwrap();
for field in self.it.0.iter() {
match &field.it.0 {
match &field.it.index {
Some(index) => {
traversal.compile(&index.inner_ref())?;
traversal.push_code(field.it.1.swap(Code::RegisterGet(index_table)).start());
traversal.push_code(field.it.1.swap(Code::TableSet));
traversal.push_code(
field
.it
.expression
.swap(Code::RegisterGet(index_table))
.start(),
);
traversal.push_code(field.it.expression.swap(Code::TableSet));
}
None => {
match &field.it.1.it {
match &field.it.expression.it {
Expression::VarArg(vararg) => {
traversal.compile(&field.it.1.swap(vararg))?;
traversal.push_code(field.it.1.swap(Code::VarArg(0)));
traversal.compile(&field.it.expression.swap(vararg))?;
traversal.push_code(field.it.expression.swap(Code::VarArg(0)));
}
it => {
traversal.compile(&field.it.1.swap(it))?;
traversal.compile(&field.it.expression.swap(it))?;
}
}
let index = traversal
@ -586,8 +617,14 @@ impl Compile for Piece<&Constructor> {
.last()
.unwrap()
.index;
traversal.push_code(field.it.1.swap(Code::RegisterGet(index_table)).start());
traversal.push_code(field.it.1.swap(Code::TableInsert(index)));
traversal.push_code(
field
.it
.expression
.swap(Code::RegisterGet(index_table))
.start(),
);
traversal.push_code(field.it.expression.swap(Code::TableInsert(index)));
}
}
}
@ -609,10 +646,16 @@ impl Compile for Piece<&Expression> {
}
Expression::Number(number) => {
let number = number
.0
.parse::<u64>()
.map(|it| Value::Integer(it))
.unwrap_or(Value::Number(
number
.0
.parse::<f64>()
.map_err(|it| LoadError(it.to_string(), self.unit()))?;
traversal.push_literal(Value::Number(number), self.unit());
.map_err(|it| LoadError(it.to_string(), self.unit()))?,
));
traversal.push_literal(number, self.unit());
}
Expression::String(string) => {
traversal.push_string(string.clone(), self.unit())?;
@ -675,8 +718,7 @@ fn compile_assignment(
let compile_variable_expression = |// Compile a variable normally with one value from an expression
traversal: &mut Traversal,
variable: Option<&Piece<Variable>>,
expression: &Piece<&Expression>
|
expression: &Piece<&Expression>|
-> Result<(), LoadError> {
let index = traversal.index().unwrap();
traversal.compile(expression)?;
@ -691,8 +733,8 @@ fn compile_assignment(
// If this is the last expression it CAN have multiplicity
match &expression.it {
Expression::Prefix(prefix) => {
match &**prefix {
Prefix::Call(call) => {
match **prefix {
Prefix::Call(ref call) => {
// multiple
let mut index = traversal.index().unwrap();
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
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() {
traversal.compile(&expression.swap(prefix))?;
compile_variable(variable.inner_ref(), traversal, Access::Set)?
@ -720,7 +765,8 @@ fn compile_assignment(
count += 1;
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
};
// 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();
match &statement.it {
Statement::Semicolon => {}
@ -932,7 +979,9 @@ impl Compile for Piece<&Block> {
let index = traversal.index().unwrap();
traversal.push_code(
block
.swap(Code::Discard((index as usize + names.len()).try_into().unwrap()))
.swap(Code::Discard(
(index as usize + names.len()).try_into().unwrap(),
))
.start(),
);
for name in names.iter() {
@ -992,19 +1041,107 @@ impl Compile for Piece<&Block> {
traversal.push_code(name.swap(Code::RegisterSet(index)).end());
}
Statement::Declaration(names, expressions) => {
let variables = &names
.iter()
.map(|name| {
var_scope(traversal, name.it.0.clone());
name.swap(Variable::Name(name.it.clone()))
})
.collect();
compile_assignment(traversal, variables, expressions)?;
let mut expressions_iter = expressions.iter().peekable();
let mut names_iter = names.iter().peekable();
let compile_declaration = |traversal: &mut Traversal,
expression: &Piece<Expression>,
name: &Piece<Name>|
-> Result<(), LoadError> {
traversal.compile(&expression.inner_ref())?;
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
if let Some(return_expressions) = &self.it.1 {
if let Some(return_expressions) = &self.it.return_exp {
// arguments are backwards
for return_expression in return_expressions.iter().rev() {
traversal.compile(&return_expression.inner_ref())?;

View file

@ -1,9 +1,8 @@
// PARSER
use std::fmt::Formatter;
use std::hash::{DefaultHasher, Hash, Hasher};
use std::ops::{Add, Deref, DerefMut};
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
#[derive(Clone, Copy)]
@ -335,12 +334,9 @@ impl Parse for Number {
if end == 0 {
reader.error("Could not parse number".into())
} else {
let number = reader.slice[..end].to_string();
reader.slice = &reader.slice[end..];
Ok(Piece::of(
Number(reader.slice[..end].to_string()),
reader,
end,
))
Ok(Piece::of(Number(number), reader, end))
}
}
}
@ -426,7 +422,10 @@ impl Parse for String {
// AST
#[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)]
pub(crate) struct Chunk(pub(crate) Piece<Block>);
#[derive(Debug)]
@ -494,13 +493,24 @@ pub(crate) enum Prefix {
#[derive(Debug, Clone)]
pub(crate) struct VarArg(pub(crate) Option<Name>);
#[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)]
pub(crate) struct Args(pub(crate) Vec<Piece<Expression>>);
#[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)]
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)]
pub(crate) enum FieldSep {
Comma,
@ -701,7 +711,11 @@ impl Parse for Function {
let block = reader.take::<Block>()?;
reader.white_consume("end")?;
Ok(Piece::from(
Function(pre_parameters, vararg, block),
Function {
args: pre_parameters,
vararg: vararg,
block: block,
},
&start,
&end,
))
@ -857,14 +871,23 @@ impl Parse for Field {
reader.consume_white("=")?;
let value = reader.take::<Expression>()?;
reader.consume_white("]")?;
Field(Some(index), value)
Field {
index: Some(index),
expression: value,
}
} else if let Ok(name) = reader.take::<Name>() {
reader.consume_white("=")?;
let index = name.map(|it| Expression::String(it.0));
let value = reader.take::<Expression>()?;
Field(Some(index), value)
Field {
index: Some(index),
expression: value,
}
} else {
Field(None, reader.take::<Expression>()?)
Field {
index: None,
expression: reader.take::<Expression>()?,
}
};
Ok(Piece::from(result, &start, &reader.marker()))
}
@ -940,9 +963,17 @@ impl Parse for Prefix {
} else if reader.consume_white(":").is_ok() {
let field = reader.take::<Name>()?;
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>() {
Prefix::Call(Call(current, None, args))
Prefix::Call(Call {
prefix: current,
method: None,
args: args,
})
} else {
break;
};
@ -1180,7 +1211,10 @@ impl Parse for Block {
None
};
Ok(Piece::from(
Block(statements, expressions),
Block {
statements: statements,
return_exp: expressions,
},
&start,
&reader.marker(),
))
@ -1208,7 +1242,10 @@ impl Parse for Chunk {
};
Ok(Piece::from(
Chunk(Piece::from(
Block(statements, expressions),
Block {
statements: statements,
return_exp: expressions,
},
&start,
&reader.marker(),
)),

View file

@ -34,7 +34,10 @@ pub trait Equivalent<T>: Sized {
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 {
self == other
}
@ -75,7 +78,13 @@ impl TableEntry for KeyValue {
}
}
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)]
pub struct Map<E: TableEntry + Clone> { // default representing vacancy!
pub struct Map<E: TableEntry + Clone> {
// default representing vacancy!
map: Vec<Entry<E>>,
map_bounds: std::ops::Range<usize>,
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> {
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) {
let old = std::mem::replace(&mut self.map, vec![Entry {
let old = std::mem::replace(
&mut self.map,
vec![
Entry {
entry: E::new_vacant(),
home: 0,
displacement: 0,
}; len]);
};
len
],
);
for Entry { entry, .. } in old {
if entry.is_vacant() {
self.set_table(entry)
@ -202,7 +217,11 @@ impl<E: TableEntry + Clone> Map<E> {
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 {
return;
}
@ -256,9 +275,12 @@ impl<E: TableEntry + Clone> Map<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 {
return None
return None;
}
let location = index.hashed() as usize % self.map.len();
let home = &self.map[location];
@ -377,7 +399,7 @@ impl Table {
} else {
self.table.set_table(KeyValue {
index: Value::Integer(index),
value: item
value: item,
})
}
}
@ -387,25 +409,28 @@ impl Table {
Value::Nil => Err(RunError(
"Attempt to set new index of table with key: nil".to_string(),
)),
index => Ok(self.table.set_table(KeyValue {
index,
value
})),
index => Ok(self.table.set_table(KeyValue { index, value })),
}
}
pub fn get(&mut self, index: Value) -> Result<Value, RunError> {
match index {
Value::Integer(index) => Ok(self
.array
.get(index as usize)
.get(index as usize - 1)
.unwrap_or(&Value::Nil)
.clone()),
Value::Nil => Err(RunError("Attempt to index table with key: nil".to_string())),
index => { // todo: move this into the Map
Ok(self.table.get_table(index).unwrap_or(&KeyValue {
index => {
// todo: move this into the Map
Ok(self
.table
.get_table(index)
.unwrap_or(&KeyValue {
index: 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
use crate::parser::{BinaryOp, Piece, UnaryOp, parse};
use crate::table::{Equivalent, Hashed, Hashes, Map, Table, TableEntry};
use std::any::Any;
use std::fmt::Formatter;
use std::hash::{DefaultHasher, Hash, Hasher};
use std::ops::{Deref, DerefMut};
use std::rc::Rc;
use crate::table::{Equivalent, Hashed, Hashes, Map, Table, TableEntry};
use crate::parser::{Piece, BinaryOp, UnaryOp, parse};
// Rust function to call
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 {}
@ -176,10 +174,10 @@ impl Traverse for Anything {
}
}
use crate::compiler::compile;
use crate::gc::{Allocator, Gc, Traverse};
#[cfg(feature = "vector3")]
use glam::Vec3;
use crate::gc::{Allocator, Gc, Traverse};
use crate::compiler::{Traversal, Context, Scope, compile};
#[derive(Clone, Debug, PartialEq)]
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 {
match self.0 {
Some(ref entry) => match other.0 {
@ -232,7 +231,7 @@ impl Equivalent<&str> for CachedStringEntry {
fn matches(&self, string: &&str) -> bool {
match self.0 {
Some(ref entry) => entry.0.deref() == *string,
None => false
None => false,
}
}
}
@ -265,7 +264,7 @@ impl Value {
match self {
Value::CachedString(cached) => cached.0.clone(),
Value::String(string, _hash) => string.clone(),
_ => panic!()
_ => panic!(),
}
}
}
@ -276,58 +275,61 @@ impl PartialEq for Value {
Value::Nil => match other {
Value::Nil => true,
_ => false,
}
},
Value::Bool(this) => match other {
Value::Bool(other) => this == other,
_ => false,
}
},
Value::Number(this) => match other {
Value::Number(other) => this == other,
Value::Integer(other) => *this == *other as f64,
_ => false,
}
},
Value::Integer(this) => match other {
Value::Number(other) => *this as f64 == *other, // are these conversions ok?
Value::Integer(other) => this == other,
_ => false,
}
},
Value::String(string, hash) => match other {
Value::CachedString(other) =>
Value::CachedString(other) => {
if *hash == other.1 {
other.0.deref() == string.deref()
} else {
false
}
Value::String(other_string, other_hash) =>
}
Value::String(other_string, other_hash) => {
if hash == other_hash {
string == other_string
} else {
false
}
_ => false
}
_ => false,
},
Value::CachedString(string) => match other {
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 {
string.0.deref() == other_string.deref()
} else {
false
}
_ => false
}
_ => false,
},
Value::Table(this) => match other {
Value::Table(other) => other == this,
_ => false
}
_ => false,
},
Value::Object(this) => match other {
Value::Object(other) => other == this,
_ => false
}
_ => false,
},
Value::Function(this) => match other {
Value::Function(other) => other == this,
_ => false
}
_ => false,
},
}
}
}
@ -359,7 +361,7 @@ pub struct Frame {
pub struct Machine {
global: Gc<Table>,
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
}
/*
@ -444,12 +446,11 @@ impl Machine {
if string.len() < SHORT_STRING_LEN {
let existing = self.cache.get_table(string);
match existing {
Some(ref entry) => {
Ok(Value::CachedString(entry.0.clone().unwrap()))
},
Some(ref entry) => Ok(Value::CachedString(entry.0.clone().unwrap())),
None => {
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))
}
}
@ -678,7 +679,13 @@ impl Machine {
if needle.stack.len() > 65536 {
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 {
Some(code) => code,
None => {
@ -694,9 +701,7 @@ impl Machine {
Code::Comment(number) => {
eprintln!("{}", number)
}
Code::TableNew => {
needle.push(Value::Table(self.allocator.alloc(Table::new())))
}
Code::TableNew => needle.push(Value::Table(self.allocator.alloc(Table::new()))),
Code::TableSet => {
let table = needle.pop();
let index = needle.pop();
@ -712,7 +717,7 @@ impl Machine {
match needle.pop() {
Value::Table(mut table) => {
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();
machine.global.borrow_mut().set(
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() {
println!("{}",machine.try_string(&mut needle.pop())?.unwrap_str())
print!("{} ", machine.try_string(&mut needle.pop())?.unwrap_str())
}
println!();
Ok(())
}))))
},
)))),
)?;
Ok(machine)
}