Add table length
This commit is contained in:
parent
9e9106991e
commit
73e33444c9
@ -22,6 +22,7 @@ end
|
|||||||
|
|
||||||
global sometable = {}
|
global sometable = {}
|
||||||
sometable["hello"] = { add(10)(15) }
|
sometable["hello"] = { add(10)(15) }
|
||||||
|
print(#sometable["hello"])
|
||||||
sometable["hello"].there = "my dude"
|
sometable["hello"].there = "my dude"
|
||||||
print(sometable.hello.there)
|
print(sometable.hello.there)
|
||||||
|
|
||||||
|
|||||||
@ -372,6 +372,7 @@ pub struct PrimaryExpression(Node<Expression>);
|
|||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum UnaryOperator {
|
pub enum UnaryOperator {
|
||||||
Negation,
|
Negation,
|
||||||
|
Length,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for UnaryOperator {
|
impl Parse for UnaryOperator {
|
||||||
@ -379,6 +380,7 @@ impl Parse for UnaryOperator {
|
|||||||
if let Some(token) = stream.next() {
|
if let Some(token) = stream.next() {
|
||||||
match token {
|
match token {
|
||||||
Token::Symbol('-') => Ok(UnaryOperator::Negation),
|
Token::Symbol('-') => Ok(UnaryOperator::Negation),
|
||||||
|
Token::Symbol('#') => Ok(UnaryOperator::Length),
|
||||||
_ => Err(stream.expected_err("unop")),
|
_ => Err(stream.expected_err("unop")),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -530,7 +532,6 @@ impl Parse for PrimaryExpression {
|
|||||||
Token::Symbol('[') | Token::Symbol('.') => {
|
Token::Symbol('[') | Token::Symbol('.') => {
|
||||||
let meta = Metadata::produce(&mut stream, pre.clone());
|
let meta = Metadata::produce(&mut stream, pre.clone());
|
||||||
let IndexedAccess(accesses) = stream.parse()?;
|
let IndexedAccess(accesses) = stream.parse()?;
|
||||||
dbg!(&accesses, stream.peek());
|
|
||||||
for access in accesses {
|
for access in accesses {
|
||||||
expression = Expression::IndexedAccess(
|
expression = Expression::IndexedAccess(
|
||||||
Box::new(Node {
|
Box::new(Node {
|
||||||
|
|||||||
@ -525,6 +525,7 @@ impl Expression {
|
|||||||
for reg in ®isters {
|
for reg in ®isters {
|
||||||
match op {
|
match op {
|
||||||
UnaryOperator::Negation => instructions.push(Instruction::Unm(*reg, *reg)),
|
UnaryOperator::Negation => instructions.push(Instruction::Unm(*reg, *reg)),
|
||||||
|
UnaryOperator::Length => instructions.push(Instruction::Len(*reg, *reg)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(instructions, registers)
|
(instructions, registers)
|
||||||
|
|||||||
66
src/vm.rs
66
src/vm.rs
@ -7,7 +7,7 @@ use crate::{
|
|||||||
ast::{BinaryOperator, UnaryOperator},
|
ast::{BinaryOperator, UnaryOperator},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Hash, PartialEq, Eq, Copy)]
|
#[derive(Clone, Hash, PartialEq, Eq, Copy, PartialOrd, Ord)]
|
||||||
pub struct VMFloat(u64);
|
pub struct VMFloat(u64);
|
||||||
|
|
||||||
impl VMFloat {
|
impl VMFloat {
|
||||||
@ -37,7 +37,7 @@ impl Debug for LuaFloat {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Hash, PartialEq, Eq)]
|
#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct LuaInteger(pub i64);
|
pub struct LuaInteger(pub i64);
|
||||||
|
|
||||||
impl Debug for LuaInteger {
|
impl Debug for LuaInteger {
|
||||||
@ -58,7 +58,7 @@ impl From<&LuaInteger> for LuaFloat {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Hash, PartialEq, Eq)]
|
#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct LuaBool(pub bool);
|
pub struct LuaBool(pub bool);
|
||||||
|
|
||||||
impl Debug for LuaBool {
|
impl Debug for LuaBool {
|
||||||
@ -134,6 +134,8 @@ pub enum Instruction {
|
|||||||
Add(u16, u16, u16),
|
Add(u16, u16, u16),
|
||||||
/// R(A) := -R(B)
|
/// R(A) := -R(B)
|
||||||
Unm(u16, u16),
|
Unm(u16, u16),
|
||||||
|
/// R(A) := #R(B) (length operator)
|
||||||
|
Len(u16, u16),
|
||||||
/// R(A) := R(B) == R(C)
|
/// R(A) := R(B) == R(C)
|
||||||
Equal(u16, u16, u16),
|
Equal(u16, u16, u16),
|
||||||
/// R(A) := R(B) < R(C)
|
/// R(A) := R(B) < R(C)
|
||||||
@ -190,6 +192,7 @@ impl Debug for Instruction {
|
|||||||
Instruction::Add(arg0, arg1, arg2) => write!(f, "ADD {} {} {}", arg0, arg1, arg2),
|
Instruction::Add(arg0, arg1, arg2) => write!(f, "ADD {} {} {}", arg0, arg1, arg2),
|
||||||
Instruction::LoadNil(arg0, arg1) => write!(f, "LOADNIL {} {}", arg0, arg1),
|
Instruction::LoadNil(arg0, arg1) => write!(f, "LOADNIL {} {}", arg0, arg1),
|
||||||
Instruction::Unm(arg0, arg1) => write!(f, "UNM {} {}", arg0, arg1),
|
Instruction::Unm(arg0, arg1) => write!(f, "UNM {} {}", arg0, arg1),
|
||||||
|
Instruction::Len(arg0, arg1) => write!(f, "LEN {} {}", arg0, arg1),
|
||||||
Instruction::Or(arg0, arg1, arg2) => write!(f, "OR {} {} {}", arg0, arg1, arg2),
|
Instruction::Or(arg0, arg1, arg2) => write!(f, "OR {} {} {}", arg0, arg1, arg2),
|
||||||
Instruction::And(arg0, arg1, arg2) => write!(f, "AND {} {} {}", arg0, arg1, arg2),
|
Instruction::And(arg0, arg1, arg2) => write!(f, "AND {} {} {}", arg0, arg1, arg2),
|
||||||
}
|
}
|
||||||
@ -212,6 +215,8 @@ pub enum RuntimeError {
|
|||||||
NotTable(Value),
|
NotTable(Value),
|
||||||
#[error("Value is not coercable to a float: {0:?}")]
|
#[error("Value is not coercable to a float: {0:?}")]
|
||||||
NotFloatable(Value),
|
NotFloatable(Value),
|
||||||
|
#[error("Value does not have a length: {0:?}")]
|
||||||
|
NotLengthable(Value),
|
||||||
#[error("{0}")]
|
#[error("{0}")]
|
||||||
Custom(String),
|
Custom(String),
|
||||||
}
|
}
|
||||||
@ -292,7 +297,7 @@ impl Value {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
|
#[derive(Debug, PartialEq, Eq, Hash, Clone, Ord, PartialOrd)]
|
||||||
pub enum IndexableValue {
|
pub enum IndexableValue {
|
||||||
String(String),
|
String(String),
|
||||||
Float(VMFloat),
|
Float(VMFloat),
|
||||||
@ -396,6 +401,47 @@ impl Value {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn len(&self) -> Result<Value, RuntimeError> {
|
||||||
|
match self {
|
||||||
|
Value::String(value) => Ok(Self::Integer(LuaInteger(value.len() as i64))),
|
||||||
|
Value::Table(table) => {
|
||||||
|
let table = table.borrow();
|
||||||
|
let mut int_indexes = table
|
||||||
|
.keys()
|
||||||
|
.filter(|v| match v {
|
||||||
|
IndexableValue::Integer(_) => true,
|
||||||
|
_ => false,
|
||||||
|
})
|
||||||
|
.map(|v| match v {
|
||||||
|
IndexableValue::Integer(int) => int.0,
|
||||||
|
_ => panic!(),
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
int_indexes.push(0);
|
||||||
|
int_indexes.sort();
|
||||||
|
|
||||||
|
for idx in int_indexes {
|
||||||
|
let idx_value = table.get(&IndexableValue::Integer(LuaInteger(idx)));
|
||||||
|
let idx_value_after = idx
|
||||||
|
.checked_add_unsigned(1)
|
||||||
|
.and_then(|i| table.get(&IndexableValue::Integer(LuaInteger(i))));
|
||||||
|
|
||||||
|
// Directly from https://www.lua.org/manual/5.5/manual.html#3.4.7
|
||||||
|
if (idx == 0 || idx_value.is_some()) && idx_value_after.is_none() {
|
||||||
|
return Ok(Self::Integer(LuaInteger(idx)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic!()
|
||||||
|
}
|
||||||
|
Value::Float(_) => Err(RuntimeError::NotLengthable(self.clone())),
|
||||||
|
Value::Integer(_) => Err(RuntimeError::NotLengthable(self.clone())),
|
||||||
|
Value::Boolean(_) => Err(RuntimeError::NotLengthable(self.clone())),
|
||||||
|
Value::RustFunction(_) => Err(RuntimeError::NotLengthable(self.clone())),
|
||||||
|
Value::Function(_) => Err(RuntimeError::NotLengthable(self.clone())),
|
||||||
|
Value::Nil => Err(RuntimeError::NotLengthable(self.clone())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn and(&self, other: &Value) -> Result<Value, RuntimeError> {
|
pub fn and(&self, other: &Value) -> Result<Value, RuntimeError> {
|
||||||
if self.is_truthy() {
|
if self.is_truthy() {
|
||||||
Ok(self.clone())
|
Ok(self.clone())
|
||||||
@ -986,6 +1032,18 @@ impl ClosureRunner {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Instruction::Len(res, reg) => {
|
||||||
|
self.set_stack(
|
||||||
|
*res,
|
||||||
|
StackValue::Value(
|
||||||
|
self.stack
|
||||||
|
.get(reg)
|
||||||
|
.map(|v| v.borrow().clone())
|
||||||
|
.unwrap_or(Value::Nil)
|
||||||
|
.len()?,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
Instruction::Or(res, lhs, rhs) => {
|
Instruction::Or(res, lhs, rhs) => {
|
||||||
let lhs = self
|
let lhs = self
|
||||||
.stack
|
.stack
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user