Compare commits
9 Commits
56943d612a
...
8fe3ffc8e0
| Author | SHA1 | Date | |
|---|---|---|---|
| 8fe3ffc8e0 | |||
| fb12568e33 | |||
| 68da93541d | |||
| ed5c9d8b8f | |||
| 260963f7cd | |||
| 131c01c8f0 | |||
| b3492032e4 | |||
| ee4b5435a4 | |||
| f12f3b629b |
@ -93,3 +93,5 @@ end
|
|||||||
for k, v in (ipairs(table)) do
|
for k, v in (ipairs(table)) do
|
||||||
print(k, v)
|
print(k, v)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
print("hello " .. "there")
|
||||||
@ -39,8 +39,8 @@ fn main() {
|
|||||||
|
|
||||||
let mut vm = VirtualMachine::default();
|
let mut vm = VirtualMachine::default();
|
||||||
|
|
||||||
vm.set_global("max".into(), Max.into());
|
vm.set_global("max".into(), Max.into()).unwrap();
|
||||||
vm.set_global("print".into(), Print.into());
|
vm.set_global("print".into(), Print.into()).unwrap();
|
||||||
|
|
||||||
dbg!(&compilation_unit);
|
dbg!(&compilation_unit);
|
||||||
|
|
||||||
|
|||||||
82
src/ast.rs
82
src/ast.rs
@ -480,6 +480,11 @@ impl Parse for IndexedAccess {
|
|||||||
fn parse(mut stream: TokenStream) -> Result<Self, TokenStreamError> {
|
fn parse(mut stream: TokenStream) -> Result<Self, TokenStreamError> {
|
||||||
let mut expressions = Vec::new();
|
let mut expressions = Vec::new();
|
||||||
while let Some(Token::Symbol('[') | Token::Symbol('.')) = stream.peek() {
|
while let Some(Token::Symbol('[') | Token::Symbol('.')) = stream.peek() {
|
||||||
|
if let (Some(Token::Symbol('.')), Some(Token::Symbol('.'))) =
|
||||||
|
(stream.peek(), stream.peek2())
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
match stream.next().unwrap() {
|
match stream.next().unwrap() {
|
||||||
Token::Symbol('[') => {
|
Token::Symbol('[') => {
|
||||||
let expression = stream.parse()?;
|
let expression = stream.parse()?;
|
||||||
@ -558,8 +563,10 @@ pub struct PrimaryExpression(Node<Expression>);
|
|||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum UnaryOperator {
|
pub enum UnaryOperator {
|
||||||
|
Not,
|
||||||
Negation,
|
Negation,
|
||||||
Length,
|
Length,
|
||||||
|
BitNot,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for UnaryOperator {
|
impl Parse for UnaryOperator {
|
||||||
@ -568,6 +575,8 @@ impl Parse for UnaryOperator {
|
|||||||
match token {
|
match token {
|
||||||
Token::Symbol('-') => Ok(UnaryOperator::Negation),
|
Token::Symbol('-') => Ok(UnaryOperator::Negation),
|
||||||
Token::Symbol('#') => Ok(UnaryOperator::Length),
|
Token::Symbol('#') => Ok(UnaryOperator::Length),
|
||||||
|
Token::Keyword(Keyword::Not) => Ok(UnaryOperator::Not),
|
||||||
|
Token::Symbol('~') => Ok(UnaryOperator::BitNot),
|
||||||
_ => Err(stream.expected_err("unop")),
|
_ => Err(stream.expected_err("unop")),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -580,13 +589,28 @@ impl Parse for UnaryOperator {
|
|||||||
pub enum BinaryOperator {
|
pub enum BinaryOperator {
|
||||||
And,
|
And,
|
||||||
Or,
|
Or,
|
||||||
|
Concat,
|
||||||
|
|
||||||
LessThan,
|
LessThan,
|
||||||
LessThanOrEqual,
|
LessThanOrEqual,
|
||||||
GreaterThan,
|
GreaterThan,
|
||||||
GreaterThanOrEqual,
|
GreaterThanOrEqual,
|
||||||
Equal,
|
Equal,
|
||||||
|
NotEqual,
|
||||||
|
|
||||||
Add,
|
Add,
|
||||||
Sub,
|
Sub,
|
||||||
|
Mult,
|
||||||
|
Div,
|
||||||
|
IDiv,
|
||||||
|
Mod,
|
||||||
|
Exp,
|
||||||
|
|
||||||
|
BitAnd,
|
||||||
|
BitOr,
|
||||||
|
BitXOr,
|
||||||
|
BitSRight,
|
||||||
|
BitSLeft,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BinaryOperator {
|
impl BinaryOperator {
|
||||||
@ -594,13 +618,32 @@ impl BinaryOperator {
|
|||||||
match self {
|
match self {
|
||||||
BinaryOperator::Or => 0,
|
BinaryOperator::Or => 0,
|
||||||
BinaryOperator::And => 1,
|
BinaryOperator::And => 1,
|
||||||
|
|
||||||
BinaryOperator::LessThan => 10,
|
BinaryOperator::LessThan => 10,
|
||||||
BinaryOperator::LessThanOrEqual => 10,
|
BinaryOperator::LessThanOrEqual => 10,
|
||||||
BinaryOperator::GreaterThan => 10,
|
BinaryOperator::GreaterThan => 10,
|
||||||
BinaryOperator::GreaterThanOrEqual => 10,
|
BinaryOperator::GreaterThanOrEqual => 10,
|
||||||
BinaryOperator::Equal => 10,
|
BinaryOperator::Equal => 10,
|
||||||
BinaryOperator::Add => 20,
|
BinaryOperator::NotEqual => 10,
|
||||||
BinaryOperator::Sub => 20,
|
|
||||||
|
BinaryOperator::BitOr => 20,
|
||||||
|
BinaryOperator::BitXOr => 21,
|
||||||
|
BinaryOperator::BitAnd => 22,
|
||||||
|
|
||||||
|
BinaryOperator::BitSLeft => 25,
|
||||||
|
BinaryOperator::BitSRight => 25,
|
||||||
|
|
||||||
|
BinaryOperator::Concat => 30,
|
||||||
|
|
||||||
|
BinaryOperator::Add => 40,
|
||||||
|
BinaryOperator::Sub => 40,
|
||||||
|
|
||||||
|
BinaryOperator::Mult => 50,
|
||||||
|
BinaryOperator::Div => 50,
|
||||||
|
BinaryOperator::IDiv => 50,
|
||||||
|
BinaryOperator::Mod => 50,
|
||||||
|
|
||||||
|
BinaryOperator::Exp => 60,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -626,10 +669,42 @@ impl Parse for BinaryOperator {
|
|||||||
stream.next();
|
stream.next();
|
||||||
Ok(BinaryOperator::Equal)
|
Ok(BinaryOperator::Equal)
|
||||||
}
|
}
|
||||||
|
(Token::Symbol('~'), Some(Token::Symbol('='))) => {
|
||||||
|
stream.next();
|
||||||
|
Ok(BinaryOperator::NotEqual)
|
||||||
|
}
|
||||||
|
(Token::Symbol('.'), Some(Token::Symbol('.'))) => {
|
||||||
|
stream.next();
|
||||||
|
Ok(BinaryOperator::Concat)
|
||||||
|
}
|
||||||
|
|
||||||
|
(Token::Symbol('>'), Some(Token::Symbol('>'))) => {
|
||||||
|
stream.next();
|
||||||
|
Ok(BinaryOperator::BitSRight)
|
||||||
|
}
|
||||||
|
(Token::Symbol('<'), Some(Token::Symbol('<'))) => {
|
||||||
|
stream.next();
|
||||||
|
Ok(BinaryOperator::BitSLeft)
|
||||||
|
}
|
||||||
|
|
||||||
|
(Token::Symbol('/'), Some(Token::Symbol('/'))) => {
|
||||||
|
stream.next();
|
||||||
|
Ok(BinaryOperator::IDiv)
|
||||||
|
}
|
||||||
|
|
||||||
(Token::Symbol('<'), _) => Ok(BinaryOperator::LessThan),
|
(Token::Symbol('<'), _) => Ok(BinaryOperator::LessThan),
|
||||||
(Token::Symbol('>'), _) => Ok(BinaryOperator::GreaterThan),
|
(Token::Symbol('>'), _) => Ok(BinaryOperator::GreaterThan),
|
||||||
|
|
||||||
(Token::Symbol('+'), _) => Ok(BinaryOperator::Add),
|
(Token::Symbol('+'), _) => Ok(BinaryOperator::Add),
|
||||||
(Token::Symbol('-'), _) => Ok(BinaryOperator::Sub),
|
(Token::Symbol('-'), _) => Ok(BinaryOperator::Sub),
|
||||||
|
(Token::Symbol('*'), _) => Ok(BinaryOperator::Mult),
|
||||||
|
(Token::Symbol('/'), _) => Ok(BinaryOperator::Div),
|
||||||
|
(Token::Symbol('%'), _) => Ok(BinaryOperator::Mod),
|
||||||
|
(Token::Symbol('^'), _) => Ok(BinaryOperator::Exp),
|
||||||
|
|
||||||
|
(Token::Symbol('&'), _) => Ok(BinaryOperator::BitAnd),
|
||||||
|
(Token::Symbol('|'), _) => Ok(BinaryOperator::BitOr),
|
||||||
|
(Token::Symbol('~'), _) => Ok(BinaryOperator::BitXOr),
|
||||||
_ => Err(stream.expected_err("binop")),
|
_ => Err(stream.expected_err("binop")),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -724,6 +799,9 @@ impl Parse for PrimaryExpression {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
Token::Symbol('[') | Token::Symbol('.') => {
|
Token::Symbol('[') | Token::Symbol('.') => {
|
||||||
|
if stream.peek2() == Some(Token::Symbol('.')) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
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()?;
|
||||||
for access in accesses {
|
for access in accesses {
|
||||||
|
|||||||
@ -1,7 +1,4 @@
|
|||||||
use std::{
|
use std::collections::{HashMap, HashSet};
|
||||||
collections::{HashMap, HashSet},
|
|
||||||
num::IntErrorKind,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::{
|
ast::{
|
||||||
@ -861,6 +858,91 @@ impl Expression {
|
|||||||
*rhs.get(0).unwrap(),
|
*rhs.get(0).unwrap(),
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
BinaryOperator::Concat => {
|
||||||
|
instructions.push(PreInstr::Instr(Instruction::Concat(
|
||||||
|
reg,
|
||||||
|
*lhs.get(0).unwrap(),
|
||||||
|
*rhs.get(0).unwrap(),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
BinaryOperator::NotEqual => {
|
||||||
|
instructions.push(PreInstr::Instr(Instruction::Equal(
|
||||||
|
reg,
|
||||||
|
*lhs.get(0).unwrap(),
|
||||||
|
*rhs.get(0).unwrap(),
|
||||||
|
)));
|
||||||
|
instructions.push(PreInstr::Instr(Instruction::Not(reg, reg)));
|
||||||
|
}
|
||||||
|
BinaryOperator::Mult => {
|
||||||
|
instructions.push(PreInstr::Instr(Instruction::Mult(
|
||||||
|
reg,
|
||||||
|
*lhs.get(0).unwrap(),
|
||||||
|
*rhs.get(0).unwrap(),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
BinaryOperator::Div => {
|
||||||
|
instructions.push(PreInstr::Instr(Instruction::Div(
|
||||||
|
reg,
|
||||||
|
*lhs.get(0).unwrap(),
|
||||||
|
*rhs.get(0).unwrap(),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
BinaryOperator::IDiv => {
|
||||||
|
instructions.push(PreInstr::Instr(Instruction::IDiv(
|
||||||
|
reg,
|
||||||
|
*lhs.get(0).unwrap(),
|
||||||
|
*rhs.get(0).unwrap(),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
BinaryOperator::Mod => {
|
||||||
|
instructions.push(PreInstr::Instr(Instruction::Mod(
|
||||||
|
reg,
|
||||||
|
*lhs.get(0).unwrap(),
|
||||||
|
*rhs.get(0).unwrap(),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
BinaryOperator::Exp => {
|
||||||
|
instructions.push(PreInstr::Instr(Instruction::Exp(
|
||||||
|
reg,
|
||||||
|
*lhs.get(0).unwrap(),
|
||||||
|
*rhs.get(0).unwrap(),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
BinaryOperator::BitAnd => {
|
||||||
|
instructions.push(PreInstr::Instr(Instruction::BitAnd(
|
||||||
|
reg,
|
||||||
|
*lhs.get(0).unwrap(),
|
||||||
|
*rhs.get(0).unwrap(),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
BinaryOperator::BitOr => {
|
||||||
|
instructions.push(PreInstr::Instr(Instruction::BitOr(
|
||||||
|
reg,
|
||||||
|
*lhs.get(0).unwrap(),
|
||||||
|
*rhs.get(0).unwrap(),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
BinaryOperator::BitXOr => {
|
||||||
|
instructions.push(PreInstr::Instr(Instruction::BitXOr(
|
||||||
|
reg,
|
||||||
|
*lhs.get(0).unwrap(),
|
||||||
|
*rhs.get(0).unwrap(),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
BinaryOperator::BitSRight => {
|
||||||
|
instructions.push(PreInstr::Instr(Instruction::BitSRight(
|
||||||
|
reg,
|
||||||
|
*lhs.get(0).unwrap(),
|
||||||
|
*rhs.get(0).unwrap(),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
BinaryOperator::BitSLeft => {
|
||||||
|
instructions.push(PreInstr::Instr(Instruction::BitSLeft(
|
||||||
|
reg,
|
||||||
|
*lhs.get(0).unwrap(),
|
||||||
|
*rhs.get(0).unwrap(),
|
||||||
|
)));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
(instructions, vec![reg])
|
(instructions, vec![reg])
|
||||||
}
|
}
|
||||||
@ -876,6 +958,12 @@ impl Expression {
|
|||||||
UnaryOperator::Length => {
|
UnaryOperator::Length => {
|
||||||
instructions.push(PreInstr::Instr(Instruction::Len(*reg, *reg)))
|
instructions.push(PreInstr::Instr(Instruction::Len(*reg, *reg)))
|
||||||
}
|
}
|
||||||
|
UnaryOperator::Not => {
|
||||||
|
instructions.push(PreInstr::Instr(Instruction::Not(*reg, *reg)))
|
||||||
|
}
|
||||||
|
UnaryOperator::BitNot => {
|
||||||
|
instructions.push(PreInstr::Instr(Instruction::BitNot(*reg, *reg)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(instructions, registers)
|
(instructions, registers)
|
||||||
@ -1097,8 +1185,6 @@ fn compile_function_call(
|
|||||||
instructions.push(PreInstr::Instr(Instruction::MoveRetValues(last_reg)));
|
instructions.push(PreInstr::Instr(Instruction::MoveRetValues(last_reg)));
|
||||||
}
|
}
|
||||||
|
|
||||||
let last_param_reg = param_regs.last().unwrap_or(&function_reg);
|
|
||||||
|
|
||||||
let mut return_regs = Vec::new();
|
let mut return_regs = Vec::new();
|
||||||
if let Some(expected_values) = expected_values {
|
if let Some(expected_values) = expected_values {
|
||||||
for i in 0..expected_values {
|
for i in 0..expected_values {
|
||||||
|
|||||||
@ -18,7 +18,7 @@
|
|||||||
//! let compilation_unit = compile("print(\"hello\")", None).unwrap();
|
//! let compilation_unit = compile("print(\"hello\")", None).unwrap();
|
||||||
//!
|
//!
|
||||||
//! let mut vm = vm::VirtualMachine::default();
|
//! let mut vm = vm::VirtualMachine::default();
|
||||||
//! vm.set_global("print".into(), Print.into());
|
//! vm.set_global("print".into(), Print.into()).unwrap();
|
||||||
//!
|
//!
|
||||||
//! let mut runner = compilation_unit.with_virtual_machine(&mut vm).execute();
|
//! let mut runner = compilation_unit.with_virtual_machine(&mut vm).execute();
|
||||||
//!
|
//!
|
||||||
|
|||||||
@ -286,7 +286,7 @@ pub fn tokenize<T: Into<String>>(to_tokenize: T) -> Result<Vec<FullToken>, Error
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// "words"
|
// "words"
|
||||||
c if c.is_alphabetic() => {
|
c if c.is_alphabetic() || *c == '_' => {
|
||||||
let mut value = character.to_string();
|
let mut value = character.to_string();
|
||||||
while let Some(c) = cursor.first() {
|
while let Some(c) = cursor.first() {
|
||||||
if !(c.is_ascii_alphanumeric() || c == '_') {
|
if !(c.is_ascii_alphanumeric() || c == '_') {
|
||||||
|
|||||||
319
src/vm/mod.rs
319
src/vm/mod.rs
@ -1,11 +1,11 @@
|
|||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
use std::{cell::RefCell, collections::HashMap, fmt::Debug, rc::Rc};
|
use std::{cell::RefCell, collections::HashMap, fmt::Debug, i64, rc::Rc};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
CompilationUnit,
|
CompilationUnit,
|
||||||
ast::{BinaryOperator, UnaryOperator},
|
ast::{BinaryOperator, UnaryOperator},
|
||||||
vm::value::{Constant, IndexableValue, LuaInteger, Value},
|
vm::value::{Constant, IndexableValue, LuaInteger, Table, Value},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod value;
|
pub mod value;
|
||||||
@ -16,6 +16,7 @@ pub enum Instruction {
|
|||||||
Move(u16, u16),
|
Move(u16, u16),
|
||||||
/// R(A) ... R(A + func_register - top) := previous function return values
|
/// R(A) ... R(A + func_register - top) := previous function return values
|
||||||
MoveRetValues(u16),
|
MoveRetValues(u16),
|
||||||
|
|
||||||
/// R(A) := K(Bx)
|
/// R(A) := K(Bx)
|
||||||
LoadK(u16, u32),
|
LoadK(u16, u32),
|
||||||
/// R(A), ..., R(B) := nil
|
/// R(A), ..., R(B) := nil
|
||||||
@ -34,24 +35,58 @@ pub enum Instruction {
|
|||||||
SetList(u16, u32),
|
SetList(u16, u32),
|
||||||
/// R(A) := R(B)[R(C)]
|
/// R(A) := R(B)[R(C)]
|
||||||
GetTable(u16, u16, u16),
|
GetTable(u16, u16, u16),
|
||||||
|
|
||||||
/// R(A) := {}
|
/// R(A) := {}
|
||||||
NewTable(u16),
|
NewTable(u16),
|
||||||
|
|
||||||
|
/// R(A) := R(B) .. R(C)
|
||||||
|
Concat(u16, u16, u16),
|
||||||
|
|
||||||
/// R(A) := R(B) + R(C)
|
/// R(A) := R(B) + R(C)
|
||||||
Add(u16, u16, u16),
|
Add(u16, u16, u16),
|
||||||
|
/// R(A) := R(B) * R(C)
|
||||||
|
Mult(u16, u16, u16),
|
||||||
|
/// R(A) := R(B) / R(C)
|
||||||
|
Div(u16, u16, u16),
|
||||||
|
/// R(A) := R(B) // R(C)
|
||||||
|
IDiv(u16, u16, u16),
|
||||||
|
/// R(A) := R(B) % R(C)
|
||||||
|
Mod(u16, u16, u16),
|
||||||
|
/// R(A) := R(B) ^ R(C)
|
||||||
|
Exp(u16, u16, u16),
|
||||||
|
|
||||||
|
/// R(A) := R(B) & R(C)
|
||||||
|
BitAnd(u16, u16, u16),
|
||||||
|
/// R(A) := R(B) | R(C)
|
||||||
|
BitOr(u16, u16, u16),
|
||||||
|
/// R(A) := R(B) ~ R(C)
|
||||||
|
BitXOr(u16, u16, u16),
|
||||||
|
/// R(A) := R(B) >> R(C)
|
||||||
|
BitSRight(u16, u16, u16),
|
||||||
|
/// R(A) := R(B) << R(C)
|
||||||
|
BitSLeft(u16, u16, u16),
|
||||||
|
|
||||||
/// R(A) := -R(B)
|
/// R(A) := -R(B)
|
||||||
Unm(u16, u16),
|
Unm(u16, u16),
|
||||||
/// R(A) := #R(B) (length operator)
|
/// R(A) := #R(B) (length operator)
|
||||||
Len(u16, u16),
|
Len(u16, u16),
|
||||||
|
/// R(A) := not R(B)
|
||||||
|
Not(u16, u16),
|
||||||
|
/// R(A) := ~R(B)
|
||||||
|
BitNot(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)
|
||||||
LessThan(u16, u16, u16),
|
LessThan(u16, u16, u16),
|
||||||
/// R(A) := R(B) <= R(C)
|
/// R(A) := R(B) <= R(C)
|
||||||
LessThanOrEqual(u16, u16, u16),
|
LessThanOrEqual(u16, u16, u16),
|
||||||
|
|
||||||
/// R(A) := R(B) or R(C)
|
/// R(A) := R(B) or R(C)
|
||||||
Or(u16, u16, u16),
|
Or(u16, u16, u16),
|
||||||
/// R(A) := R(B) and R(C)
|
/// R(A) := R(B) and R(C)
|
||||||
And(u16, u16, u16),
|
And(u16, u16, u16),
|
||||||
|
|
||||||
/// PC += sAx
|
/// PC += sAx
|
||||||
Jmp(i32),
|
Jmp(i32),
|
||||||
/// PC = Ax
|
/// PC = Ax
|
||||||
@ -69,10 +104,12 @@ pub enum Instruction {
|
|||||||
Call(u16, u16, u16),
|
Call(u16, u16, u16),
|
||||||
/// return R(A), ... , R(B)
|
/// return R(A), ... , R(B)
|
||||||
Return(u16, u16),
|
Return(u16, u16),
|
||||||
|
|
||||||
/// close stack variables up to R(A)
|
/// close stack variables up to R(A)
|
||||||
Close(u16),
|
Close(u16),
|
||||||
/// R(A) := closure(KPROTO[Bx], R(A), ..., R(A+n))
|
/// R(A) := closure(KPROTO[Bx], R(A), ..., R(A+n))
|
||||||
Closure(u16, u32),
|
Closure(u16, u32),
|
||||||
|
|
||||||
/// R(A), ... , R(A+B-2) := varargs
|
/// R(A), ... , R(A+B-2) := varargs
|
||||||
Vararg(u16, u16),
|
Vararg(u16, u16),
|
||||||
}
|
}
|
||||||
@ -105,15 +142,35 @@ impl Debug for Instruction {
|
|||||||
Instruction::Close(arg0) => write!(f, "CLOSE {}", arg0),
|
Instruction::Close(arg0) => write!(f, "CLOSE {}", arg0),
|
||||||
Instruction::Closure(arg0, arg1) => write!(f, "CLOSURE {} {}", arg0, arg1),
|
Instruction::Closure(arg0, arg1) => write!(f, "CLOSURE {} {}", arg0, arg1),
|
||||||
Instruction::Return(arg0, arg1) => write!(f, "RETURN {} {}", arg0, arg1),
|
Instruction::Return(arg0, arg1) => write!(f, "RETURN {} {}", arg0, arg1),
|
||||||
|
|
||||||
|
Instruction::Concat(arg0, arg1, arg2) => write!(f, "CONCAT {} {} {}", arg0, arg1, arg2),
|
||||||
|
|
||||||
Instruction::Equal(arg0, arg1, arg2) => write!(f, "EQ {} {} {}", arg0, arg1, arg2),
|
Instruction::Equal(arg0, arg1, arg2) => write!(f, "EQ {} {} {}", arg0, arg1, arg2),
|
||||||
Instruction::LessThan(arg0, arg1, arg2) => write!(f, "LT {} {} {}", arg0, arg1, arg2),
|
Instruction::LessThan(arg0, arg1, arg2) => write!(f, "LT {} {} {}", arg0, arg1, arg2),
|
||||||
Instruction::LessThanOrEqual(arg0, arg1, arg2) => {
|
Instruction::LessThanOrEqual(arg0, arg1, arg2) => {
|
||||||
write!(f, "LE {} {} {}", arg0, arg1, arg2)
|
write!(f, "LE {} {} {}", arg0, arg1, arg2)
|
||||||
}
|
}
|
||||||
|
|
||||||
Instruction::Add(arg0, arg1, arg2) => write!(f, "ADD {} {} {}", arg0, arg1, arg2),
|
Instruction::Add(arg0, arg1, arg2) => write!(f, "ADD {} {} {}", arg0, arg1, arg2),
|
||||||
|
Instruction::Mult(arg0, arg1, arg2) => write!(f, "MUL {} {} {}", arg0, arg1, arg2),
|
||||||
|
Instruction::Div(arg0, arg1, arg2) => write!(f, "DIV {} {} {}", arg0, arg1, arg2),
|
||||||
|
Instruction::IDiv(arg0, arg1, arg2) => write!(f, "IDIV {} {} {}", arg0, arg1, arg2),
|
||||||
|
Instruction::Mod(arg0, arg1, arg2) => write!(f, "MOD {} {} {}", arg0, arg1, arg2),
|
||||||
|
Instruction::Exp(arg0, arg1, arg2) => write!(f, "EXP {} {} {}", arg0, arg1, arg2),
|
||||||
|
|
||||||
|
Instruction::BitAnd(arg0, arg1, arg2) => write!(f, "BAND {} {} {}", arg0, arg1, arg2),
|
||||||
|
Instruction::BitOr(arg0, arg1, arg2) => write!(f, "BOR {} {} {}", arg0, arg1, arg2),
|
||||||
|
Instruction::BitXOr(arg0, arg1, arg2) => write!(f, "BXOR {} {} {}", arg0, arg1, arg2),
|
||||||
|
Instruction::BitSRight(arg0, arg1, arg2) => write!(f, "BSR {} {} {}", arg0, arg1, arg2),
|
||||||
|
Instruction::BitSLeft(arg0, arg1, arg2) => write!(f, "BSL {} {} {}", 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::Len(arg0, arg1) => write!(f, "LEN {} {}", arg0, arg1),
|
||||||
|
Instruction::Not(arg0, arg1) => write!(f, "NOT {} {}", arg0, arg1),
|
||||||
|
Instruction::BitNot(arg0, arg1) => write!(f, "BNOT {} {}", 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),
|
||||||
Instruction::Vararg(arg0, arg1) => write!(f, "VARARG {} {}", arg0, arg1),
|
Instruction::Vararg(arg0, arg1) => write!(f, "VARARG {} {}", arg0, arg1),
|
||||||
@ -137,42 +194,14 @@ 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 is not coercable to bits: {0:?}")]
|
||||||
|
NotBittable(Value),
|
||||||
#[error("Value does not have a length: {0:?}")]
|
#[error("Value does not have a length: {0:?}")]
|
||||||
NotLengthable(Value),
|
NotLengthable(Value),
|
||||||
#[error("{0}")]
|
#[error("{0}")]
|
||||||
Custom(String),
|
Custom(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default)]
|
|
||||||
pub(crate) struct Environment {
|
|
||||||
pub globals: HashMap<Constant, Rc<RefCell<Value>>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Environment {
|
|
||||||
fn get_global(&mut self, key: &Constant) -> Option<StackValue> {
|
|
||||||
let value = self.globals.get_mut(key)?;
|
|
||||||
Some(match &*value.borrow() {
|
|
||||||
_ => StackValue::Value(value.borrow().clone()),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_global(&mut self, key: Constant, value: StackValue) {
|
|
||||||
if let Some(existing) = self.globals.get_mut(&key) {
|
|
||||||
match value {
|
|
||||||
StackValue::Value(value) => {
|
|
||||||
*existing.borrow_mut() = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
match value {
|
|
||||||
StackValue::Value(value) => {
|
|
||||||
self.globals.insert(key, Rc::new(RefCell::new(value)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone, Default)]
|
||||||
pub struct Prototype {
|
pub struct Prototype {
|
||||||
pub instructions: Vec<Instruction>,
|
pub instructions: Vec<Instruction>,
|
||||||
@ -181,7 +210,7 @@ pub struct Prototype {
|
|||||||
|
|
||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone, Default)]
|
||||||
pub struct VirtualMachine {
|
pub struct VirtualMachine {
|
||||||
pub(super) environment: Rc<RefCell<Environment>>,
|
pub(super) environment: Table,
|
||||||
pub(super) constants: Vec<Constant>,
|
pub(super) constants: Vec<Constant>,
|
||||||
pub(super) prototypes: HashMap<u32, Prototype>,
|
pub(super) prototypes: HashMap<u32, Prototype>,
|
||||||
pub(super) proto_counter: u32,
|
pub(super) proto_counter: u32,
|
||||||
@ -206,16 +235,17 @@ impl VirtualMachine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_global(&mut self, key: Constant, value: Value) {
|
pub fn set_global(&mut self, key: Value, value: Value) -> Result<(), RuntimeError> {
|
||||||
self.environment
|
self.environment
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.set_global(key, StackValue::Value(value));
|
.insert(key.as_indexable()?, value);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_globals(&self) -> HashMap<Constant, Value> {
|
pub fn get_globals(&self) -> HashMap<IndexableValue, Value> {
|
||||||
let mut values = HashMap::new();
|
let mut values = HashMap::new();
|
||||||
for (key, value) in &self.environment.borrow().globals {
|
for (key, value) in self.environment.borrow().iter() {
|
||||||
values.insert(key.clone(), value.borrow().clone());
|
values.insert(key.clone(), value.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
values
|
values
|
||||||
@ -226,7 +256,7 @@ impl VirtualMachine {
|
|||||||
pub struct Closure {
|
pub struct Closure {
|
||||||
vm: VirtualMachine,
|
vm: VirtualMachine,
|
||||||
pub(crate) prototype: u32,
|
pub(crate) prototype: u32,
|
||||||
environment: Rc<RefCell<Environment>>,
|
environment: Table,
|
||||||
upvalues: HashMap<u16, Rc<RefCell<Value>>>,
|
upvalues: HashMap<u16, Rc<RefCell<Value>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -424,25 +454,43 @@ impl ClosureRunner {
|
|||||||
}
|
}
|
||||||
Instruction::SetGlobal(reg, global) => {
|
Instruction::SetGlobal(reg, global) => {
|
||||||
let value = self.get_stack(*reg);
|
let value = self.get_stack(*reg);
|
||||||
self.closure
|
self.closure.environment.borrow_mut().insert(
|
||||||
.environment
|
constants
|
||||||
.borrow_mut()
|
.get(*global as usize)
|
||||||
.set_global(constants.get(*global as usize).unwrap().clone(), value);
|
.unwrap()
|
||||||
|
.clone()
|
||||||
|
.as_value()
|
||||||
|
.as_indexable()?,
|
||||||
|
match value {
|
||||||
|
StackValue::Value(value) => value,
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Instruction::GetGlobal(reg, global) => {
|
Instruction::GetGlobal(reg, global) => {
|
||||||
let glob = self
|
let constant = constants.get(*global as usize).unwrap().clone();
|
||||||
.closure
|
|
||||||
.environment
|
if let Constant::String(name) = &constant
|
||||||
.borrow_mut()
|
&& name.clone() == "_ENV".to_owned()
|
||||||
.get_global(constants.get(*global as usize).unwrap());
|
{
|
||||||
|
self.set_stack(
|
||||||
|
*reg,
|
||||||
|
StackValue::Value(Value::Table(self.closure.environment.clone())),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
let environment = self.closure.environment.borrow_mut().clone();
|
||||||
|
let glob = environment
|
||||||
|
.get(&constant.as_value().as_indexable()?)
|
||||||
|
.cloned();
|
||||||
|
|
||||||
if let Some(global) = glob {
|
if let Some(global) = glob {
|
||||||
self.set_stack(*reg, global);
|
self.set_stack(*reg, StackValue::Value(global));
|
||||||
} else {
|
} else {
|
||||||
return Err(RuntimeError::GlobalNotFound(
|
return Err(RuntimeError::GlobalNotFound(
|
||||||
constants.get(*global as usize).cloned(),
|
constants.get(*global as usize).cloned(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
Instruction::GetUpVal(reg, upvalreg) => {
|
Instruction::GetUpVal(reg, upvalreg) => {
|
||||||
let upvalue = self.closure.get_upvalue(*upvalreg);
|
let upvalue = self.closure.get_upvalue(*upvalreg);
|
||||||
self.set_stack(*reg, upvalue);
|
self.set_stack(*reg, upvalue);
|
||||||
@ -689,6 +737,21 @@ impl ClosureRunner {
|
|||||||
}
|
}
|
||||||
return Ok(Some(ret_values));
|
return Ok(Some(ret_values));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Instruction::Concat(res, lhs, rhs) => {
|
||||||
|
let lhs = self
|
||||||
|
.stack
|
||||||
|
.get(lhs)
|
||||||
|
.map(|v| v.borrow().clone())
|
||||||
|
.unwrap_or(Value::Nil);
|
||||||
|
let rhs = self
|
||||||
|
.stack
|
||||||
|
.get(rhs)
|
||||||
|
.map(|v| v.borrow().clone())
|
||||||
|
.unwrap_or(Value::Nil);
|
||||||
|
self.set_stack(*res, StackValue::Value(lhs.concat(&rhs)?));
|
||||||
|
}
|
||||||
|
|
||||||
Instruction::Add(res, lhs, rhs) => {
|
Instruction::Add(res, lhs, rhs) => {
|
||||||
let lhs = self
|
let lhs = self
|
||||||
.stack
|
.stack
|
||||||
@ -702,6 +765,138 @@ impl ClosureRunner {
|
|||||||
.unwrap_or(Value::Nil);
|
.unwrap_or(Value::Nil);
|
||||||
self.set_stack(*res, StackValue::Value(lhs.add(&rhs)?));
|
self.set_stack(*res, StackValue::Value(lhs.add(&rhs)?));
|
||||||
}
|
}
|
||||||
|
Instruction::Mult(res, lhs, rhs) => {
|
||||||
|
let lhs = self
|
||||||
|
.stack
|
||||||
|
.get(lhs)
|
||||||
|
.map(|v| v.borrow().clone())
|
||||||
|
.unwrap_or(Value::Nil);
|
||||||
|
let rhs = self
|
||||||
|
.stack
|
||||||
|
.get(rhs)
|
||||||
|
.map(|v| v.borrow().clone())
|
||||||
|
.unwrap_or(Value::Nil);
|
||||||
|
self.set_stack(*res, StackValue::Value(lhs.mult(&rhs)?));
|
||||||
|
}
|
||||||
|
Instruction::Div(res, lhs, rhs) => {
|
||||||
|
let lhs = self
|
||||||
|
.stack
|
||||||
|
.get(lhs)
|
||||||
|
.map(|v| v.borrow().clone())
|
||||||
|
.unwrap_or(Value::Nil);
|
||||||
|
let rhs = self
|
||||||
|
.stack
|
||||||
|
.get(rhs)
|
||||||
|
.map(|v| v.borrow().clone())
|
||||||
|
.unwrap_or(Value::Nil);
|
||||||
|
self.set_stack(*res, StackValue::Value(lhs.div(&rhs)?));
|
||||||
|
}
|
||||||
|
Instruction::IDiv(res, lhs, rhs) => {
|
||||||
|
let lhs = self
|
||||||
|
.stack
|
||||||
|
.get(lhs)
|
||||||
|
.map(|v| v.borrow().clone())
|
||||||
|
.unwrap_or(Value::Nil);
|
||||||
|
let rhs = self
|
||||||
|
.stack
|
||||||
|
.get(rhs)
|
||||||
|
.map(|v| v.borrow().clone())
|
||||||
|
.unwrap_or(Value::Nil);
|
||||||
|
self.set_stack(*res, StackValue::Value(lhs.idiv(&rhs)?));
|
||||||
|
}
|
||||||
|
Instruction::Mod(res, lhs, rhs) => {
|
||||||
|
let lhs = self
|
||||||
|
.stack
|
||||||
|
.get(lhs)
|
||||||
|
.map(|v| v.borrow().clone())
|
||||||
|
.unwrap_or(Value::Nil);
|
||||||
|
let rhs = self
|
||||||
|
.stack
|
||||||
|
.get(rhs)
|
||||||
|
.map(|v| v.borrow().clone())
|
||||||
|
.unwrap_or(Value::Nil);
|
||||||
|
self.set_stack(*res, StackValue::Value(lhs.r#mod(&rhs)?));
|
||||||
|
}
|
||||||
|
Instruction::Exp(res, lhs, rhs) => {
|
||||||
|
let lhs = self
|
||||||
|
.stack
|
||||||
|
.get(lhs)
|
||||||
|
.map(|v| v.borrow().clone())
|
||||||
|
.unwrap_or(Value::Nil);
|
||||||
|
let rhs = self
|
||||||
|
.stack
|
||||||
|
.get(rhs)
|
||||||
|
.map(|v| v.borrow().clone())
|
||||||
|
.unwrap_or(Value::Nil);
|
||||||
|
self.set_stack(*res, StackValue::Value(lhs.exp(&rhs)?));
|
||||||
|
}
|
||||||
|
|
||||||
|
Instruction::BitAnd(res, lhs, rhs) => {
|
||||||
|
let lhs = self
|
||||||
|
.stack
|
||||||
|
.get(lhs)
|
||||||
|
.map(|v| v.borrow().clone())
|
||||||
|
.unwrap_or(Value::Nil);
|
||||||
|
let rhs = self
|
||||||
|
.stack
|
||||||
|
.get(rhs)
|
||||||
|
.map(|v| v.borrow().clone())
|
||||||
|
.unwrap_or(Value::Nil);
|
||||||
|
self.set_stack(*res, StackValue::Value(lhs.band(&rhs)?));
|
||||||
|
}
|
||||||
|
Instruction::BitOr(res, lhs, rhs) => {
|
||||||
|
let lhs = self
|
||||||
|
.stack
|
||||||
|
.get(lhs)
|
||||||
|
.map(|v| v.borrow().clone())
|
||||||
|
.unwrap_or(Value::Nil);
|
||||||
|
let rhs = self
|
||||||
|
.stack
|
||||||
|
.get(rhs)
|
||||||
|
.map(|v| v.borrow().clone())
|
||||||
|
.unwrap_or(Value::Nil);
|
||||||
|
self.set_stack(*res, StackValue::Value(lhs.bor(&rhs)?));
|
||||||
|
}
|
||||||
|
Instruction::BitXOr(res, lhs, rhs) => {
|
||||||
|
let lhs = self
|
||||||
|
.stack
|
||||||
|
.get(lhs)
|
||||||
|
.map(|v| v.borrow().clone())
|
||||||
|
.unwrap_or(Value::Nil);
|
||||||
|
let rhs = self
|
||||||
|
.stack
|
||||||
|
.get(rhs)
|
||||||
|
.map(|v| v.borrow().clone())
|
||||||
|
.unwrap_or(Value::Nil);
|
||||||
|
self.set_stack(*res, StackValue::Value(lhs.bxor(&rhs)?));
|
||||||
|
}
|
||||||
|
Instruction::BitSRight(res, lhs, rhs) => {
|
||||||
|
let lhs = self
|
||||||
|
.stack
|
||||||
|
.get(lhs)
|
||||||
|
.map(|v| v.borrow().clone())
|
||||||
|
.unwrap_or(Value::Nil);
|
||||||
|
let rhs = self
|
||||||
|
.stack
|
||||||
|
.get(rhs)
|
||||||
|
.map(|v| v.borrow().clone())
|
||||||
|
.unwrap_or(Value::Nil);
|
||||||
|
self.set_stack(*res, StackValue::Value(lhs.bsright(&rhs)?));
|
||||||
|
}
|
||||||
|
Instruction::BitSLeft(res, lhs, rhs) => {
|
||||||
|
let lhs = self
|
||||||
|
.stack
|
||||||
|
.get(lhs)
|
||||||
|
.map(|v| v.borrow().clone())
|
||||||
|
.unwrap_or(Value::Nil);
|
||||||
|
let rhs = self
|
||||||
|
.stack
|
||||||
|
.get(rhs)
|
||||||
|
.map(|v| v.borrow().clone())
|
||||||
|
.unwrap_or(Value::Nil);
|
||||||
|
self.set_stack(*res, StackValue::Value(lhs.bsleft(&rhs)?));
|
||||||
|
}
|
||||||
|
|
||||||
Instruction::Equal(res, lhs, rhs) => {
|
Instruction::Equal(res, lhs, rhs) => {
|
||||||
let lhs = self
|
let lhs = self
|
||||||
.stack
|
.stack
|
||||||
@ -741,6 +936,7 @@ impl ClosureRunner {
|
|||||||
.unwrap_or(Value::Nil);
|
.unwrap_or(Value::Nil);
|
||||||
self.set_stack(*res, StackValue::Value(lhs.lte(&rhs)?));
|
self.set_stack(*res, StackValue::Value(lhs.lte(&rhs)?));
|
||||||
}
|
}
|
||||||
|
|
||||||
Instruction::Unm(res, reg) => {
|
Instruction::Unm(res, reg) => {
|
||||||
self.set_stack(
|
self.set_stack(
|
||||||
*res,
|
*res,
|
||||||
@ -765,6 +961,31 @@ impl ClosureRunner {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Instruction::Not(res, reg) => {
|
||||||
|
self.set_stack(
|
||||||
|
*res,
|
||||||
|
StackValue::Value(
|
||||||
|
self.stack
|
||||||
|
.get(reg)
|
||||||
|
.map(|v| v.borrow().clone())
|
||||||
|
.unwrap_or(Value::Nil)
|
||||||
|
.not()?,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Instruction::BitNot(res, reg) => {
|
||||||
|
self.set_stack(
|
||||||
|
*res,
|
||||||
|
StackValue::Value(
|
||||||
|
self.stack
|
||||||
|
.get(reg)
|
||||||
|
.map(|v| v.borrow().clone())
|
||||||
|
.unwrap_or(Value::Nil)
|
||||||
|
.bxor(&Value::Integer(LuaInteger(u64::MAX as i64)))?,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
Instruction::Or(res, lhs, rhs) => {
|
Instruction::Or(res, lhs, rhs) => {
|
||||||
let lhs = self
|
let lhs = self
|
||||||
.stack
|
.stack
|
||||||
|
|||||||
297
src/vm/value.rs
297
src/vm/value.rs
@ -1,4 +1,9 @@
|
|||||||
use std::{cell::RefCell, collections::HashMap, fmt::Debug, rc::Rc};
|
use std::{
|
||||||
|
cell::RefCell,
|
||||||
|
collections::HashMap,
|
||||||
|
fmt::{Debug, Display},
|
||||||
|
rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::{BinaryOperator, UnaryOperator},
|
ast::{BinaryOperator, UnaryOperator},
|
||||||
@ -31,7 +36,7 @@ impl LuaFloat {
|
|||||||
|
|
||||||
impl Debug for LuaFloat {
|
impl Debug for LuaFloat {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
self.0.fmt(f)
|
Debug::fmt(&self.0, f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,7 +45,7 @@ pub struct LuaInteger(pub i64);
|
|||||||
|
|
||||||
impl Debug for LuaInteger {
|
impl Debug for LuaInteger {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
self.0.fmt(f)
|
Debug::fmt(&self.0, f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,7 +66,7 @@ pub struct LuaBool(pub bool);
|
|||||||
|
|
||||||
impl Debug for LuaBool {
|
impl Debug for LuaBool {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
self.0.fmt(f)
|
Debug::fmt(&self.0, f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,9 +101,15 @@ pub enum Constant {
|
|||||||
Nil,
|
Nil,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&str> for Constant {
|
impl Constant {
|
||||||
fn from(value: &str) -> Self {
|
pub fn as_value(self) -> Value {
|
||||||
Constant::String(value.to_owned())
|
match self {
|
||||||
|
Constant::String(value) => Value::String(value),
|
||||||
|
Constant::Float(vmfloat) => Value::Float(vmfloat),
|
||||||
|
Constant::Integer(lua_integer) => Value::Integer(lua_integer),
|
||||||
|
Constant::Bool(lua_bool) => Value::Boolean(lua_bool),
|
||||||
|
Constant::Nil => Value::Nil,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,6 +125,8 @@ impl Debug for Constant {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type Table = Rc<RefCell<HashMap<IndexableValue, Value>>>;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum Value {
|
pub enum Value {
|
||||||
String(String),
|
String(String),
|
||||||
@ -123,7 +136,7 @@ pub enum Value {
|
|||||||
RustFunction(Rc<RefCell<dyn RustFunction>>),
|
RustFunction(Rc<RefCell<dyn RustFunction>>),
|
||||||
Function(Closure),
|
Function(Closure),
|
||||||
Nil,
|
Nil,
|
||||||
Table(Rc<RefCell<HashMap<IndexableValue, Value>>>),
|
Table(Table),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Value {
|
impl Value {
|
||||||
@ -158,19 +171,63 @@ impl Value {
|
|||||||
_ => Err(RuntimeError::NotFloatable(self.clone())),
|
_ => Err(RuntimeError::NotFloatable(self.clone())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn as_bits(&self) -> Result<LuaInteger, RuntimeError> {
|
||||||
|
match self {
|
||||||
|
Value::Float(vmfloat) => Ok(LuaInteger(vmfloat.lua_number().0 as i64)),
|
||||||
|
Value::Integer(lua_integer) => Ok(LuaInteger(lua_integer.0 as i64)),
|
||||||
|
Value::Boolean(lua_bool) => Ok(LuaInteger(lua_bool.0 as i64)),
|
||||||
|
Value::Nil => Ok(LuaInteger(0)),
|
||||||
|
_ => Err(RuntimeError::NotFloatable(self.clone())),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Hash, Clone, Ord, PartialOrd)]
|
impl From<&str> for Value {
|
||||||
pub enum IndexableValue {
|
fn from(value: &str) -> Self {
|
||||||
String(String),
|
Value::String(value.to_owned())
|
||||||
Float(VMFloat),
|
}
|
||||||
Integer(LuaInteger),
|
}
|
||||||
Bool(LuaBool),
|
|
||||||
RustFunction(String),
|
impl Display for Value {
|
||||||
Function(u32),
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Value::String(value) => Display::fmt(value, f),
|
||||||
|
Value::Float(vmfloat) => Display::fmt(&vmfloat.lua_number().0, f),
|
||||||
|
Value::Integer(lua_integer) => Display::fmt(&lua_integer.0, f),
|
||||||
|
Value::Boolean(lua_bool) => Display::fmt(&lua_bool.0, f),
|
||||||
|
Value::RustFunction(ref_cell) => {
|
||||||
|
write!(f, "<RustFunction({})>", ref_cell.borrow().as_indexable())
|
||||||
|
}
|
||||||
|
Value::Function(closure) => write!(f, "<function({})>", closure.prototype),
|
||||||
|
Value::Nil => write!(f, "nil"),
|
||||||
|
Value::Table(_) => write!(f, "<table>"),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Value {
|
impl Value {
|
||||||
|
pub fn concat(&self, other: &Value) -> Result<Value, RuntimeError> {
|
||||||
|
match (self, other) {
|
||||||
|
(
|
||||||
|
Value::String(_) | Value::Integer(_) | Value::Boolean(_),
|
||||||
|
Value::String(_) | Value::Integer(_) | Value::Boolean(_),
|
||||||
|
) => Ok(Value::String(format!("{}{}", self, other))),
|
||||||
|
(
|
||||||
|
Value::Float(_) | Value::Integer(_) | Value::Boolean(_),
|
||||||
|
Value::Float(_) | Value::Integer(_) | Value::Boolean(_),
|
||||||
|
) => {
|
||||||
|
let res = LuaFloat(self.as_float()?.0 * other.as_float()?.0);
|
||||||
|
Ok(Value::Float(res.vm_number()))
|
||||||
|
}
|
||||||
|
_ => Err(RuntimeError::InvalidOperands(
|
||||||
|
BinaryOperator::Concat,
|
||||||
|
self.clone(),
|
||||||
|
other.clone(),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn add(&self, other: &Value) -> Result<Value, RuntimeError> {
|
pub fn add(&self, other: &Value) -> Result<Value, RuntimeError> {
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(Value::Integer(_) | Value::Boolean(_), Value::Integer(_) | Value::Boolean(_)) => {
|
(Value::Integer(_) | Value::Boolean(_), Value::Integer(_) | Value::Boolean(_)) => {
|
||||||
@ -192,6 +249,196 @@ impl Value {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn mult(&self, other: &Value) -> Result<Value, RuntimeError> {
|
||||||
|
match (self, other) {
|
||||||
|
(Value::Integer(_) | Value::Boolean(_), Value::Integer(_) | Value::Boolean(_)) => {
|
||||||
|
let res = LuaInteger(self.as_integer()?.0 * other.as_integer()?.0);
|
||||||
|
Ok(Value::Integer(res))
|
||||||
|
}
|
||||||
|
(
|
||||||
|
Value::Float(_) | Value::Integer(_) | Value::Boolean(_),
|
||||||
|
Value::Float(_) | Value::Integer(_) | Value::Boolean(_),
|
||||||
|
) => {
|
||||||
|
let res = LuaFloat(self.as_float()?.0 * other.as_float()?.0);
|
||||||
|
Ok(Value::Float(res.vm_number()))
|
||||||
|
}
|
||||||
|
_ => Err(RuntimeError::InvalidOperands(
|
||||||
|
BinaryOperator::Mult,
|
||||||
|
self.clone(),
|
||||||
|
other.clone(),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn div(&self, other: &Value) -> Result<Value, RuntimeError> {
|
||||||
|
match (self, other) {
|
||||||
|
(Value::Integer(_) | Value::Boolean(_), Value::Integer(_) | Value::Boolean(_)) => {
|
||||||
|
let res = LuaFloat(self.as_integer()?.0 as f64 / other.as_integer()?.0 as f64);
|
||||||
|
Ok(Value::Float(res.vm_number()))
|
||||||
|
}
|
||||||
|
(
|
||||||
|
Value::Float(_) | Value::Integer(_) | Value::Boolean(_),
|
||||||
|
Value::Float(_) | Value::Integer(_) | Value::Boolean(_),
|
||||||
|
) => {
|
||||||
|
let res = LuaFloat(self.as_float()?.0 / other.as_float()?.0);
|
||||||
|
Ok(Value::Float(res.vm_number()))
|
||||||
|
}
|
||||||
|
_ => Err(RuntimeError::InvalidOperands(
|
||||||
|
BinaryOperator::Div,
|
||||||
|
self.clone(),
|
||||||
|
other.clone(),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn idiv(&self, other: &Value) -> Result<Value, RuntimeError> {
|
||||||
|
match (self, other) {
|
||||||
|
(Value::Integer(_) | Value::Boolean(_), Value::Integer(_) | Value::Boolean(_)) => {
|
||||||
|
let res = LuaInteger(self.as_integer()?.0 / other.as_integer()?.0);
|
||||||
|
Ok(Value::Integer(res))
|
||||||
|
}
|
||||||
|
(
|
||||||
|
Value::Float(_) | Value::Integer(_) | Value::Boolean(_),
|
||||||
|
Value::Float(_) | Value::Integer(_) | Value::Boolean(_),
|
||||||
|
) => {
|
||||||
|
let res = LuaInteger((self.as_float()?.0 / other.as_float()?.0).floor() as i64);
|
||||||
|
Ok(Value::Integer(res))
|
||||||
|
}
|
||||||
|
_ => Err(RuntimeError::InvalidOperands(
|
||||||
|
BinaryOperator::IDiv,
|
||||||
|
self.clone(),
|
||||||
|
other.clone(),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn r#mod(&self, other: &Value) -> Result<Value, RuntimeError> {
|
||||||
|
match (self, other) {
|
||||||
|
(Value::Integer(_) | Value::Boolean(_), Value::Integer(_) | Value::Boolean(_)) => {
|
||||||
|
let res = LuaInteger(self.as_integer()?.0 % other.as_integer()?.0);
|
||||||
|
Ok(Value::Integer(res))
|
||||||
|
}
|
||||||
|
(
|
||||||
|
Value::Float(_) | Value::Integer(_) | Value::Boolean(_),
|
||||||
|
Value::Float(_) | Value::Integer(_) | Value::Boolean(_),
|
||||||
|
) => {
|
||||||
|
let res = LuaFloat(self.as_float()?.0 % other.as_float()?.0);
|
||||||
|
Ok(Value::Float(res.vm_number()))
|
||||||
|
}
|
||||||
|
_ => Err(RuntimeError::InvalidOperands(
|
||||||
|
BinaryOperator::Mod,
|
||||||
|
self.clone(),
|
||||||
|
other.clone(),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn exp(&self, other: &Value) -> Result<Value, RuntimeError> {
|
||||||
|
match (self, other) {
|
||||||
|
(Value::Integer(_) | Value::Boolean(_), Value::Integer(_) | Value::Boolean(_)) => {
|
||||||
|
let res = LuaInteger(self.as_integer()?.0.pow(other.as_integer()?.0 as u32));
|
||||||
|
Ok(Value::Integer(res))
|
||||||
|
}
|
||||||
|
(
|
||||||
|
Value::Float(_) | Value::Integer(_) | Value::Boolean(_),
|
||||||
|
Value::Float(_) | Value::Integer(_) | Value::Boolean(_),
|
||||||
|
) => {
|
||||||
|
let res = LuaFloat(self.as_float()?.0.powf(other.as_float()?.0));
|
||||||
|
Ok(Value::Float(res.vm_number()))
|
||||||
|
}
|
||||||
|
_ => Err(RuntimeError::InvalidOperands(
|
||||||
|
BinaryOperator::Exp,
|
||||||
|
self.clone(),
|
||||||
|
other.clone(),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn band(&self, other: &Value) -> Result<Value, RuntimeError> {
|
||||||
|
match (self, other) {
|
||||||
|
(
|
||||||
|
Value::Float(_) | Value::Integer(_) | Value::Boolean(_) | Value::Nil,
|
||||||
|
Value::Float(_) | Value::Integer(_) | Value::Boolean(_) | Value::Nil,
|
||||||
|
) => {
|
||||||
|
let res = LuaInteger(self.as_bits()?.0 & other.as_bits()?.0);
|
||||||
|
Ok(Value::Integer(res))
|
||||||
|
}
|
||||||
|
_ => Err(RuntimeError::InvalidOperands(
|
||||||
|
BinaryOperator::BitAnd,
|
||||||
|
self.clone(),
|
||||||
|
other.clone(),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bor(&self, other: &Value) -> Result<Value, RuntimeError> {
|
||||||
|
match (self, other) {
|
||||||
|
(
|
||||||
|
Value::Float(_) | Value::Integer(_) | Value::Boolean(_) | Value::Nil,
|
||||||
|
Value::Float(_) | Value::Integer(_) | Value::Boolean(_) | Value::Nil,
|
||||||
|
) => {
|
||||||
|
let res = LuaInteger(self.as_bits()?.0 | other.as_bits()?.0);
|
||||||
|
Ok(Value::Integer(res))
|
||||||
|
}
|
||||||
|
_ => Err(RuntimeError::InvalidOperands(
|
||||||
|
BinaryOperator::BitOr,
|
||||||
|
self.clone(),
|
||||||
|
other.clone(),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bxor(&self, other: &Value) -> Result<Value, RuntimeError> {
|
||||||
|
match (self, other) {
|
||||||
|
(
|
||||||
|
Value::Float(_) | Value::Integer(_) | Value::Boolean(_) | Value::Nil,
|
||||||
|
Value::Float(_) | Value::Integer(_) | Value::Boolean(_) | Value::Nil,
|
||||||
|
) => {
|
||||||
|
let res = LuaInteger(self.as_bits()?.0 ^ other.as_bits()?.0);
|
||||||
|
Ok(Value::Integer(res))
|
||||||
|
}
|
||||||
|
_ => Err(RuntimeError::InvalidOperands(
|
||||||
|
BinaryOperator::BitXOr,
|
||||||
|
self.clone(),
|
||||||
|
other.clone(),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bsleft(&self, other: &Value) -> Result<Value, RuntimeError> {
|
||||||
|
match (self, other) {
|
||||||
|
(
|
||||||
|
Value::Float(_) | Value::Integer(_) | Value::Boolean(_) | Value::Nil,
|
||||||
|
Value::Float(_) | Value::Integer(_) | Value::Boolean(_) | Value::Nil,
|
||||||
|
) => {
|
||||||
|
let res = LuaInteger(self.as_bits()?.0 << other.as_bits()?.0);
|
||||||
|
Ok(Value::Integer(res))
|
||||||
|
}
|
||||||
|
_ => Err(RuntimeError::InvalidOperands(
|
||||||
|
BinaryOperator::BitSLeft,
|
||||||
|
self.clone(),
|
||||||
|
other.clone(),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bsright(&self, other: &Value) -> Result<Value, RuntimeError> {
|
||||||
|
match (self, other) {
|
||||||
|
(
|
||||||
|
Value::Float(_) | Value::Integer(_) | Value::Boolean(_) | Value::Nil,
|
||||||
|
Value::Float(_) | Value::Integer(_) | Value::Boolean(_) | Value::Nil,
|
||||||
|
) => {
|
||||||
|
let res = LuaInteger(self.as_bits()?.0 >> other.as_bits()?.0);
|
||||||
|
Ok(Value::Integer(res))
|
||||||
|
}
|
||||||
|
_ => Err(RuntimeError::InvalidOperands(
|
||||||
|
BinaryOperator::BitSRight,
|
||||||
|
self.clone(),
|
||||||
|
other.clone(),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn eq(&self, other: &Value) -> Result<Value, RuntimeError> {
|
pub fn eq(&self, other: &Value) -> Result<Value, RuntimeError> {
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(Value::Integer(lhs), Value::Integer(rhs)) => {
|
(Value::Integer(lhs), Value::Integer(rhs)) => {
|
||||||
@ -321,6 +568,14 @@ impl Value {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn not(&self) -> Result<Value, RuntimeError> {
|
||||||
|
if self.is_truthy() {
|
||||||
|
Ok(Value::Boolean(LuaBool(false)))
|
||||||
|
} else {
|
||||||
|
Ok(Value::Boolean(LuaBool(true)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_truthy(&self) -> bool {
|
pub fn is_truthy(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Value::String(_) => true,
|
Value::String(_) => true,
|
||||||
@ -357,3 +612,13 @@ impl Debug for Value {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Hash, Clone, Ord, PartialOrd)]
|
||||||
|
pub enum IndexableValue {
|
||||||
|
String(String),
|
||||||
|
Float(VMFloat),
|
||||||
|
Integer(LuaInteger),
|
||||||
|
Bool(LuaBool),
|
||||||
|
RustFunction(String),
|
||||||
|
Function(u32),
|
||||||
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user