Compare commits
No commits in common. "2710a43bb23fc608afdee892960a2ceed5303b0d" and "42164ef6fe46d275260a9165e6b6c83dc039ef93" have entirely different histories.
2710a43bb2
...
42164ef6fe
@ -1,63 +1,3 @@
|
|||||||
global b = 5
|
|
||||||
|
|
||||||
function add(x)
|
|
||||||
return function (y)
|
|
||||||
x = x + 1
|
|
||||||
b = b + 1
|
|
||||||
return x + y, 1, 2, b
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function min(x, y)
|
|
||||||
local m = x
|
|
||||||
if y < x then
|
|
||||||
m = y
|
|
||||||
end
|
|
||||||
return m
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
function f(x, ...)
|
|
||||||
local b = {10, ..., add(10)(15)}
|
|
||||||
return x + 5, b
|
|
||||||
end
|
|
||||||
|
|
||||||
global sometable = {}
|
|
||||||
sometable["hello"] = { 100, 150, add(10)(15) }
|
|
||||||
print(#sometable["hello"])
|
|
||||||
sometable["hello"].there = "my dude"
|
|
||||||
print(sometable.hello.there)
|
|
||||||
|
|
||||||
print(max(11.12345, 9))
|
|
||||||
print(add(10)(15))
|
|
||||||
print(add(10)(15))
|
|
||||||
print(b)
|
|
||||||
print(min(11, 9))
|
|
||||||
print(10 - 15)
|
|
||||||
print("hello there!")
|
|
||||||
print(true or 0)
|
|
||||||
|
|
||||||
global value, table = f(10, 11, 12)
|
|
||||||
|
|
||||||
print("hello")
|
|
||||||
for i=1,#table do
|
|
||||||
print(table[i])
|
|
||||||
if i > 2 then
|
|
||||||
goto test
|
|
||||||
end
|
|
||||||
end
|
|
||||||
::test::
|
|
||||||
|
|
||||||
local test = table[1]
|
|
||||||
if test == 10 then
|
|
||||||
print("first")
|
|
||||||
elseif test == 11 then
|
|
||||||
print("second")
|
|
||||||
else
|
|
||||||
print("third")
|
|
||||||
end
|
|
||||||
print("after if/elseif/else")
|
|
||||||
|
|
||||||
|
|
||||||
local i = 0
|
local i = 0
|
||||||
print("before")
|
print("before")
|
||||||
@ -65,31 +5,4 @@ while i < 10 do
|
|||||||
i = i + 1
|
i = i + 1
|
||||||
print(i)
|
print(i)
|
||||||
end
|
end
|
||||||
print("after while")
|
print("after")
|
||||||
|
|
||||||
|
|
||||||
local i = 0
|
|
||||||
print("before")
|
|
||||||
repeat
|
|
||||||
i = i + 1
|
|
||||||
print(i)
|
|
||||||
until i >= 10
|
|
||||||
print("after repeat")
|
|
||||||
|
|
||||||
|
|
||||||
function ipairs(t)
|
|
||||||
print("inside!")
|
|
||||||
local i = 0
|
|
||||||
return function (state, control)
|
|
||||||
print(state, control)
|
|
||||||
i = i + 1
|
|
||||||
if i > #table then
|
|
||||||
return nil, nil
|
|
||||||
end
|
|
||||||
return i, t[i]
|
|
||||||
end, "otus", "potus"
|
|
||||||
end
|
|
||||||
|
|
||||||
for k, v in (ipairs(table)) do
|
|
||||||
print(k, v)
|
|
||||||
end
|
|
||||||
@ -1,19 +1,19 @@
|
|||||||
use ferrite_lua::{
|
use ferrite_lua::{
|
||||||
compile,
|
compile,
|
||||||
vm::{RuntimeError, VirtualMachine, value},
|
vm::{self, RuntimeError, RustFunction, VirtualMachine},
|
||||||
};
|
};
|
||||||
|
|
||||||
static TEST: &str = include_str!("../examples/test.lua");
|
static TEST: &str = include_str!("../examples/test.lua");
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub struct Max;
|
pub struct Max;
|
||||||
impl value::RustFunction for Max {
|
impl RustFunction for Max {
|
||||||
fn execute(&self, parameters: Vec<value::Value>) -> Result<Vec<value::Value>, RuntimeError> {
|
fn execute(&self, parameters: Vec<vm::Value>) -> Result<Vec<vm::Value>, RuntimeError> {
|
||||||
let lhs = parameters.get(0).cloned().unwrap_or(value::Value::Nil);
|
let lhs = parameters.get(0).cloned().unwrap_or(vm::Value::Nil);
|
||||||
let rhs = parameters.get(1).cloned().unwrap_or(value::Value::Nil);
|
let rhs = parameters.get(1).cloned().unwrap_or(vm::Value::Nil);
|
||||||
match lhs.lt(&rhs)? {
|
match lhs.lt(&rhs)? {
|
||||||
value::Value::Boolean(value) => Ok(vec![if value.0 { rhs } else { lhs }]),
|
vm::Value::Boolean(value) => Ok(vec![if value.0 { rhs } else { lhs }]),
|
||||||
_ => Ok(vec![value::Value::Nil]),
|
_ => Ok(vec![vm::Value::Nil]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -23,8 +23,8 @@ impl value::RustFunction for Max {
|
|||||||
}
|
}
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub struct Print;
|
pub struct Print;
|
||||||
impl value::RustFunction for Print {
|
impl RustFunction for Print {
|
||||||
fn execute(&self, parameters: Vec<value::Value>) -> Result<Vec<value::Value>, RuntimeError> {
|
fn execute(&self, parameters: Vec<vm::Value>) -> Result<Vec<vm::Value>, RuntimeError> {
|
||||||
println!("{:?}", parameters);
|
println!("{:?}", parameters);
|
||||||
Ok(Vec::new())
|
Ok(Vec::new())
|
||||||
}
|
}
|
||||||
|
|||||||
38
src/ast.rs
38
src/ast.rs
@ -5,7 +5,7 @@ use crate::{
|
|||||||
Parse, TokenRange, TokenStream, TokenStreamError,
|
Parse, TokenRange, TokenStream, TokenStreamError,
|
||||||
lexer::{Keyword, Position, Token},
|
lexer::{Keyword, Position, Token},
|
||||||
},
|
},
|
||||||
vm::value::{LuaFloat, LuaInteger},
|
vm::{LuaFloat, LuaInteger},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@ -238,7 +238,6 @@ impl Parse for Block {
|
|||||||
Token::Keyword(Keyword::End)
|
Token::Keyword(Keyword::End)
|
||||||
| Token::Keyword(Keyword::ElseIf)
|
| Token::Keyword(Keyword::ElseIf)
|
||||||
| Token::Keyword(Keyword::Else)
|
| Token::Keyword(Keyword::Else)
|
||||||
| Token::Keyword(Keyword::Until)
|
|
||||||
| Token::Eof
|
| Token::Eof
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
@ -272,14 +271,11 @@ pub enum Statement {
|
|||||||
Node<Expression>,
|
Node<Expression>,
|
||||||
Block,
|
Block,
|
||||||
),
|
),
|
||||||
GenericFor(Vec<Node<String>>, Node<ExpressionList>, Block),
|
|
||||||
While(Node<Expression>, Block),
|
While(Node<Expression>, Block),
|
||||||
Repeat(Block, Node<Expression>),
|
Repeat(Block, Node<Expression>),
|
||||||
Break,
|
Break,
|
||||||
Label(Node<String>),
|
Label(Node<String>),
|
||||||
GoTo(Node<String>),
|
GoTo(Node<String>),
|
||||||
Empty,
|
|
||||||
Block(Block),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for Statement {
|
impl Parse for Statement {
|
||||||
@ -380,22 +376,6 @@ impl Parse for Statement {
|
|||||||
} else if stream.peek() == Some(Token::Keyword(Keyword::For)) {
|
} else if stream.peek() == Some(Token::Keyword(Keyword::For)) {
|
||||||
stream.next();
|
stream.next();
|
||||||
let counter_name = stream.parse()?;
|
let counter_name = stream.parse()?;
|
||||||
|
|
||||||
if let Some(Token::Symbol(',') | Token::Keyword(Keyword::In)) = stream.peek() {
|
|
||||||
let mut counters = vec![counter_name];
|
|
||||||
while let Some(Token::Symbol(',')) = stream.peek() {
|
|
||||||
stream.next();
|
|
||||||
counters.push(stream.parse()?);
|
|
||||||
}
|
|
||||||
|
|
||||||
stream.expect(Token::Keyword(Keyword::In))?;
|
|
||||||
let expr_list = stream.parse()?;
|
|
||||||
stream.expect(Token::Keyword(Keyword::Do))?;
|
|
||||||
let block = stream.parse()?;
|
|
||||||
stream.expect(Token::Keyword(Keyword::End))?;
|
|
||||||
|
|
||||||
Ok(Self::GenericFor(counters, expr_list, block))
|
|
||||||
} else {
|
|
||||||
stream.expect_symbol('=')?;
|
stream.expect_symbol('=')?;
|
||||||
let init = stream.parse()?;
|
let init = stream.parse()?;
|
||||||
stream.expect_symbol(',')?;
|
stream.expect_symbol(',')?;
|
||||||
@ -422,7 +402,6 @@ impl Parse for Statement {
|
|||||||
step,
|
step,
|
||||||
block,
|
block,
|
||||||
))
|
))
|
||||||
}
|
|
||||||
} else if let Some(Token::Keyword(Keyword::While)) = stream.peek() {
|
} else if let Some(Token::Keyword(Keyword::While)) = stream.peek() {
|
||||||
stream.next();
|
stream.next();
|
||||||
let expr = stream.parse()?;
|
let expr = stream.parse()?;
|
||||||
@ -453,14 +432,6 @@ impl Parse for Statement {
|
|||||||
} else if let Some(Token::Keyword(Keyword::GoTo)) = stream.peek() {
|
} else if let Some(Token::Keyword(Keyword::GoTo)) = stream.peek() {
|
||||||
stream.next();
|
stream.next();
|
||||||
Ok(Self::GoTo(stream.parse()?))
|
Ok(Self::GoTo(stream.parse()?))
|
||||||
} else if let Some(Token::Symbol(';')) = stream.peek() {
|
|
||||||
stream.next();
|
|
||||||
Ok(Self::Empty)
|
|
||||||
} else if let Some(Token::Keyword(Keyword::Do)) = stream.peek() {
|
|
||||||
stream.next();
|
|
||||||
let block = stream.parse()?;
|
|
||||||
stream.expect(Token::Keyword(Keyword::End))?;
|
|
||||||
Ok(Self::Block(block))
|
|
||||||
} else {
|
} else {
|
||||||
Err(stream.expecting_err("statement"))
|
Err(stream.expecting_err("statement"))
|
||||||
}
|
}
|
||||||
@ -524,8 +495,6 @@ pub enum Expression {
|
|||||||
TableConstructor(Vec<(Option<Node<Expression>>, Node<Expression>)>),
|
TableConstructor(Vec<(Option<Node<Expression>>, Node<Expression>)>),
|
||||||
IndexedAccess(Box<Node<Expression>>, Box<Node<Expression>>),
|
IndexedAccess(Box<Node<Expression>>, Box<Node<Expression>>),
|
||||||
Ellipsis,
|
Ellipsis,
|
||||||
/// Raw access to a register
|
|
||||||
Register(u16),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for Expression {
|
impl Parse for Expression {
|
||||||
@ -699,11 +668,6 @@ impl Parse for PrimaryExpression {
|
|||||||
Expression::TableConstructor(entries)
|
Expression::TableConstructor(entries)
|
||||||
} else if let Ok(_) = stream.parse::<Ellipsis>() {
|
} else if let Ok(_) = stream.parse::<Ellipsis>() {
|
||||||
Expression::Ellipsis
|
Expression::Ellipsis
|
||||||
} else if let Some(Token::Symbol('(')) = stream.peek() {
|
|
||||||
stream.next();
|
|
||||||
let expression = stream.parse()?;
|
|
||||||
stream.expect_symbol(')')?;
|
|
||||||
expression
|
|
||||||
} else {
|
} else {
|
||||||
Expression::ValueRef(stream.parse()?)
|
Expression::ValueRef(stream.parse()?)
|
||||||
};
|
};
|
||||||
|
|||||||
372
src/compile.rs
372
src/compile.rs
@ -1,17 +1,11 @@
|
|||||||
use std::{
|
use std::collections::{HashMap, HashSet};
|
||||||
collections::{HashMap, HashSet},
|
|
||||||
num::IntErrorKind,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::{
|
ast::{
|
||||||
AccessModifier, BinaryOperator, Block, Expression, ExpressionList, IdentOrEllipsis,
|
AccessModifier, BinaryOperator, Block, Expression, IdentOrEllipsis, Literal, Statement,
|
||||||
Literal, Node, Statement, UnaryOperator,
|
UnaryOperator,
|
||||||
},
|
|
||||||
vm::{
|
|
||||||
Constant, Instruction, Prototype,
|
|
||||||
value::{LuaBool, LuaInteger},
|
|
||||||
},
|
},
|
||||||
|
vm::{Constant, Instruction, LuaBool, LuaInteger, Prototype},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
@ -31,27 +25,15 @@ impl State {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct Scope {
|
pub struct Scope {
|
||||||
pub locals: HashMap<String, u16>,
|
pub locals: HashMap<String, u16>,
|
||||||
pub register_counter: LocalCounter,
|
pub register_counter: LocalCounter,
|
||||||
pub highest_upvalue: i32,
|
pub highest_upvalue: u16,
|
||||||
pub upvalues: HashMap<String, u16>,
|
pub upvalues: HashMap<String, u16>,
|
||||||
pub is_vararg: bool,
|
pub is_vararg: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Scope {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
locals: Default::default(),
|
|
||||||
register_counter: Default::default(),
|
|
||||||
highest_upvalue: -1,
|
|
||||||
upvalues: Default::default(),
|
|
||||||
is_vararg: Default::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub struct LocalCounter(u16, Vec<u16>);
|
pub struct LocalCounter(u16, Vec<u16>);
|
||||||
|
|
||||||
@ -225,14 +207,6 @@ impl Statement {
|
|||||||
constants.extend(block.find_constants(scope, Vec::new()));
|
constants.extend(block.find_constants(scope, Vec::new()));
|
||||||
constants
|
constants
|
||||||
}
|
}
|
||||||
Statement::GenericFor(_, expr_list, block) => {
|
|
||||||
let mut constants = HashSet::new();
|
|
||||||
for expr in &expr_list.kind.0 {
|
|
||||||
constants.extend(expr.kind.find_constants(scope));
|
|
||||||
}
|
|
||||||
constants.extend(block.find_constants(scope, Vec::new()));
|
|
||||||
constants
|
|
||||||
}
|
|
||||||
Statement::While(node, block) => {
|
Statement::While(node, block) => {
|
||||||
let mut constants = HashSet::new();
|
let mut constants = HashSet::new();
|
||||||
constants.extend(node.kind.find_constants(scope));
|
constants.extend(node.kind.find_constants(scope));
|
||||||
@ -248,12 +222,6 @@ impl Statement {
|
|||||||
Statement::Break => HashSet::new(),
|
Statement::Break => HashSet::new(),
|
||||||
Statement::Label(_) => HashSet::new(),
|
Statement::Label(_) => HashSet::new(),
|
||||||
Statement::GoTo(_) => HashSet::new(),
|
Statement::GoTo(_) => HashSet::new(),
|
||||||
Statement::Empty => HashSet::new(),
|
|
||||||
Statement::Block(block) => {
|
|
||||||
let mut constants = HashSet::new();
|
|
||||||
constants.extend(block.find_constants(scope, Vec::new()));
|
|
||||||
constants
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -417,8 +385,11 @@ impl Statement {
|
|||||||
ret_registers.extend(registers);
|
ret_registers.extend(registers);
|
||||||
}
|
}
|
||||||
|
|
||||||
let new_ret_registers = scope.register_counter.consecutive(ret_registers.len() + 1);
|
let first_ret_register = ret_registers
|
||||||
let first_ret_register = new_ret_registers.first().unwrap();
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.next()
|
||||||
|
.unwrap_or(scope.register_counter.0);
|
||||||
for (i, ret_register) in ret_registers.iter_mut().enumerate() {
|
for (i, ret_register) in ret_registers.iter_mut().enumerate() {
|
||||||
let new_reg = first_ret_register + i as u16;
|
let new_reg = first_ret_register + i as u16;
|
||||||
if *ret_register != new_reg {
|
if *ret_register != new_reg {
|
||||||
@ -435,7 +406,7 @@ impl Statement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
instructions.push(PreInstr::Instr(Instruction::Return(
|
instructions.push(PreInstr::Instr(Instruction::Return(
|
||||||
*first_ret_register,
|
first_ret_register,
|
||||||
if vararg {
|
if vararg {
|
||||||
0
|
0
|
||||||
} else {
|
} else {
|
||||||
@ -510,111 +481,6 @@ impl Statement {
|
|||||||
)));
|
)));
|
||||||
instructions.push(PreInstr::Instr(Instruction::Jmp(-(instr_len + 4))));
|
instructions.push(PreInstr::Instr(Instruction::Jmp(-(instr_len + 4))));
|
||||||
}
|
}
|
||||||
Statement::GenericFor(names, expr_list, block) => {
|
|
||||||
let mut expr_regs = Vec::new();
|
|
||||||
for (i, expr) in expr_list.kind.0.iter().enumerate() {
|
|
||||||
let (instr, regs) = expr.kind.compile(
|
|
||||||
state,
|
|
||||||
scope,
|
|
||||||
if i == expr_list.kind.0.len() - 1 {
|
|
||||||
Some(4 - expr_list.kind.0.len() + 1)
|
|
||||||
} else {
|
|
||||||
Some(1)
|
|
||||||
},
|
|
||||||
);
|
|
||||||
instructions.extend(instr);
|
|
||||||
expr_regs.extend(regs);
|
|
||||||
}
|
|
||||||
|
|
||||||
dbg!(&expr_regs);
|
|
||||||
|
|
||||||
let mut inner_scope = scope.clone();
|
|
||||||
|
|
||||||
let iterator_reg = *expr_regs.get(0).unwrap();
|
|
||||||
let state_reg = *expr_regs.get(1).unwrap();
|
|
||||||
let initial_value_reg = *expr_regs.get(2).unwrap();
|
|
||||||
let closing_value_reg = *expr_regs.get(3).unwrap();
|
|
||||||
inner_scope
|
|
||||||
.locals
|
|
||||||
.insert("_ITERATOR".to_owned(), iterator_reg);
|
|
||||||
inner_scope.locals.insert("_STATE".to_owned(), state_reg);
|
|
||||||
inner_scope
|
|
||||||
.locals
|
|
||||||
.insert("_INIT_VALUE".to_owned(), initial_value_reg);
|
|
||||||
inner_scope
|
|
||||||
.locals
|
|
||||||
.insert("_CLOSING_VAL".to_owned(), closing_value_reg);
|
|
||||||
|
|
||||||
let (instr, res_regs) = compile_function_call(
|
|
||||||
Node::empty(Expression::Register(iterator_reg)),
|
|
||||||
Node::empty(ExpressionList(vec![
|
|
||||||
Node::empty(Expression::Register(state_reg)),
|
|
||||||
Node::empty(Expression::Register(initial_value_reg)),
|
|
||||||
])),
|
|
||||||
state,
|
|
||||||
&mut inner_scope,
|
|
||||||
Some(names.len()),
|
|
||||||
);
|
|
||||||
instructions.extend(instr);
|
|
||||||
|
|
||||||
let mut counter_regs = Vec::new();
|
|
||||||
for (i, name) in names.iter().enumerate() {
|
|
||||||
let reg = inner_scope.register_counter.next();
|
|
||||||
counter_regs.push(reg);
|
|
||||||
inner_scope.locals.insert(name.kind.clone(), reg);
|
|
||||||
instructions.push(PreInstr::Instr(Instruction::Move(
|
|
||||||
reg,
|
|
||||||
*res_regs.get(i).unwrap(),
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
|
|
||||||
let eql_res = inner_scope.register_counter.next();
|
|
||||||
let nil_reg = inner_scope.register_counter.next();
|
|
||||||
instructions.push(PreInstr::Instr(Instruction::LoadNil(nil_reg, nil_reg)));
|
|
||||||
instructions.push(PreInstr::Instr(Instruction::Equal(
|
|
||||||
eql_res,
|
|
||||||
*counter_regs.first().unwrap(),
|
|
||||||
nil_reg,
|
|
||||||
)));
|
|
||||||
instructions.push(PreInstr::Instr(Instruction::Test(
|
|
||||||
inner_scope.register_counter.next(),
|
|
||||||
eql_res,
|
|
||||||
1,
|
|
||||||
)));
|
|
||||||
|
|
||||||
let block_instr = block.compile(state, &mut inner_scope);
|
|
||||||
let block_instr_len = block_instr.len() as i32;
|
|
||||||
|
|
||||||
let (func_instr, res_regs) = compile_function_call(
|
|
||||||
Node::empty(Expression::Register(iterator_reg)),
|
|
||||||
Node::empty(ExpressionList(vec![
|
|
||||||
Node::empty(Expression::Register(state_reg)),
|
|
||||||
Node::empty(Expression::Register(initial_value_reg)),
|
|
||||||
])),
|
|
||||||
state,
|
|
||||||
scope,
|
|
||||||
Some(names.len()),
|
|
||||||
);
|
|
||||||
let func_instr_len = func_instr.len() as i32;
|
|
||||||
|
|
||||||
instructions.push(PreInstr::Instr(Instruction::Jmp(
|
|
||||||
block_instr_len + func_instr_len + counter_regs.len() as i32 + 2,
|
|
||||||
)));
|
|
||||||
instructions.extend(block_instr);
|
|
||||||
instructions.push(PreInstr::Instr(Instruction::Move(
|
|
||||||
initial_value_reg,
|
|
||||||
*counter_regs.first().unwrap(),
|
|
||||||
)));
|
|
||||||
instructions.extend(func_instr);
|
|
||||||
|
|
||||||
for (counter_reg, res_reg) in counter_regs.iter().zip(res_regs) {
|
|
||||||
instructions.push(PreInstr::Instr(Instruction::Move(*counter_reg, res_reg)));
|
|
||||||
}
|
|
||||||
|
|
||||||
instructions.push(PreInstr::Instr(Instruction::Jmp(
|
|
||||||
-(block_instr_len + func_instr_len + counter_regs.len() as i32 + 6),
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
Statement::While(expr, block) => {
|
Statement::While(expr, block) => {
|
||||||
let (instr, expr_regs) = expr.kind.compile(state, scope, Some(1));
|
let (instr, expr_regs) = expr.kind.compile(state, scope, Some(1));
|
||||||
let expr_instr_len = instr.len() as i32;
|
let expr_instr_len = instr.len() as i32;
|
||||||
@ -625,47 +491,20 @@ impl Statement {
|
|||||||
0,
|
0,
|
||||||
)));
|
)));
|
||||||
|
|
||||||
let mut inner_scope = scope.clone();
|
let block_instructions = block.compile(state, scope);
|
||||||
|
|
||||||
let block_instructions = block.compile(state, &mut inner_scope);
|
|
||||||
let block_instr_len = block_instructions.len() as i32;
|
let block_instr_len = block_instructions.len() as i32;
|
||||||
|
|
||||||
instructions.push(PreInstr::Instr(Instruction::Jmp(block_instr_len + 1)));
|
instructions.push(PreInstr::Instr(Instruction::Jmp(block_instr_len + 1)));
|
||||||
instructions.extend(block_instructions);
|
instructions.extend(block_instructions);
|
||||||
|
|
||||||
instructions.push(PreInstr::Instr(Instruction::Jmp(
|
|
||||||
-(block_instr_len + expr_instr_len + 3),
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
Statement::Repeat(block, expr) => {
|
|
||||||
let mut inner_scope = scope.clone();
|
|
||||||
|
|
||||||
let block_instructions = block.compile(state, &mut inner_scope);
|
|
||||||
let block_instr_len = block_instructions.len() as i32;
|
|
||||||
instructions.extend(block_instructions);
|
|
||||||
|
|
||||||
let (instr, expr_regs) = expr.kind.compile(state, scope, Some(1));
|
|
||||||
let expr_instr_len = instr.len() as i32;
|
|
||||||
instructions.extend(instr);
|
|
||||||
|
|
||||||
instructions.push(PreInstr::Instr(Instruction::Test(
|
|
||||||
scope.register_counter.next(),
|
|
||||||
*expr_regs.first().unwrap(),
|
|
||||||
0,
|
|
||||||
)));
|
|
||||||
|
|
||||||
instructions.push(PreInstr::Instr(Instruction::Jmp(
|
instructions.push(PreInstr::Instr(Instruction::Jmp(
|
||||||
-(block_instr_len + expr_instr_len + 2),
|
-(block_instr_len + expr_instr_len + 2),
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
Statement::Repeat(block, expr) => todo!(),
|
||||||
Statement::Break => instructions.push(PreInstr::Break),
|
Statement::Break => instructions.push(PreInstr::Break),
|
||||||
Statement::Label(node) => instructions.push(PreInstr::Label(node.kind.clone())),
|
Statement::Label(node) => instructions.push(PreInstr::Label(node.kind.clone())),
|
||||||
Statement::GoTo(node) => instructions.push(PreInstr::GoTo(node.kind.clone())),
|
Statement::GoTo(node) => instructions.push(PreInstr::GoTo(node.kind.clone())),
|
||||||
Statement::Empty => {}
|
|
||||||
Statement::Block(block) => {
|
|
||||||
let mut inner_scope = scope.clone();
|
|
||||||
instructions.extend(block.compile(state, &mut inner_scope));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for reg in 0..scope.register_counter.0 {
|
for reg in 0..scope.register_counter.0 {
|
||||||
@ -758,7 +597,6 @@ impl Expression {
|
|||||||
constants
|
constants
|
||||||
}
|
}
|
||||||
Expression::Ellipsis => HashSet::new(),
|
Expression::Ellipsis => HashSet::new(),
|
||||||
Expression::Register(_) => HashSet::new(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -895,19 +733,14 @@ impl Expression {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inner_scope.highest_upvalue =
|
inner_scope.highest_upvalue = scope.highest_upvalue + scope.register_counter.0;
|
||||||
scope.highest_upvalue + scope.register_counter.0 as i32;
|
|
||||||
inner_scope.upvalues = scope.upvalues.clone();
|
inner_scope.upvalues = scope.upvalues.clone();
|
||||||
|
|
||||||
dbg!(&scope.highest_upvalue, &scope.register_counter.0);
|
|
||||||
|
|
||||||
for (name, reg) in &scope.locals {
|
for (name, reg) in &scope.locals {
|
||||||
let upvalue_reg = *reg + (scope.highest_upvalue + 1) as u16;
|
let new_reg = *reg + scope.highest_upvalue + 1;
|
||||||
inner_scope.upvalues.insert(name.clone(), upvalue_reg);
|
inner_scope.upvalues.insert(name.clone(), new_reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
dbg!(&inner_scope.upvalues);
|
|
||||||
|
|
||||||
let instructions = block.compile(state, &mut inner_scope);
|
let instructions = block.compile(state, &mut inner_scope);
|
||||||
state.prototypes.push(Prototype {
|
state.prototypes.push(Prototype {
|
||||||
instructions: process_pre_instrs(instructions),
|
instructions: process_pre_instrs(instructions),
|
||||||
@ -931,7 +764,88 @@ impl Expression {
|
|||||||
(instructions, vec![local])
|
(instructions, vec![local])
|
||||||
}
|
}
|
||||||
Expression::FunctionCall(expr, params) => {
|
Expression::FunctionCall(expr, params) => {
|
||||||
compile_function_call(*expr.clone(), params.clone(), state, scope, expected_values)
|
let mut instructions = Vec::new();
|
||||||
|
|
||||||
|
let (instr, registers) = expr.kind.compile(state, scope, Some(1));
|
||||||
|
instructions.extend(instr);
|
||||||
|
|
||||||
|
let old_function_reg = registers.first().unwrap();
|
||||||
|
|
||||||
|
let mut registers = scope
|
||||||
|
.register_counter
|
||||||
|
.consecutive(params.kind.0.len() + 1)
|
||||||
|
.into_iter();
|
||||||
|
|
||||||
|
let mut param_scope = scope.clone();
|
||||||
|
let mut original_param_regs = Vec::new();
|
||||||
|
let mut vararg = false;
|
||||||
|
for (i, param) in params.kind.0.iter().enumerate() {
|
||||||
|
let (instr, registers) = param.kind.compile(
|
||||||
|
state,
|
||||||
|
&mut param_scope,
|
||||||
|
if i == params.kind.0.len() - 1 {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(1)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
instructions.extend(instr);
|
||||||
|
if registers.len() > 0 {
|
||||||
|
original_param_regs.push(*registers.first().unwrap());
|
||||||
|
} else {
|
||||||
|
vararg = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let function_reg = registers.next().unwrap();
|
||||||
|
let mut param_regs = Vec::new();
|
||||||
|
for _ in &original_param_regs {
|
||||||
|
param_regs.push(registers.next().unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i, param_reg) in original_param_regs.iter().enumerate().rev() {
|
||||||
|
let new_reg = param_regs.get(i).unwrap();
|
||||||
|
if param_reg != new_reg {
|
||||||
|
instructions.push(PreInstr::Instr(Instruction::Move(*new_reg, *param_reg)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if function_reg != *old_function_reg {
|
||||||
|
instructions.push(PreInstr::Instr(Instruction::Move(
|
||||||
|
function_reg,
|
||||||
|
*old_function_reg,
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if vararg {
|
||||||
|
let last_reg = param_regs.last().unwrap_or(&function_reg) + 1;
|
||||||
|
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();
|
||||||
|
if let Some(expected_values) = expected_values {
|
||||||
|
for i in 0..expected_values {
|
||||||
|
let return_reg = i as u16 + function_reg;
|
||||||
|
if return_reg > *last_param_reg {
|
||||||
|
return_regs.push(scope.register_counter.next());
|
||||||
|
} else {
|
||||||
|
return_regs.push(return_reg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
instructions.push(PreInstr::Instr(Instruction::Call(
|
||||||
|
*&function_reg,
|
||||||
|
if vararg { 0 } else { param_regs.len() as u16 },
|
||||||
|
if return_regs.len() == 0 {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
return_regs.len() as u16 + 1
|
||||||
|
},
|
||||||
|
)));
|
||||||
|
|
||||||
|
(instructions, return_regs)
|
||||||
}
|
}
|
||||||
Expression::Literal(literal) => {
|
Expression::Literal(literal) => {
|
||||||
let mut instructions = Vec::new();
|
let mut instructions = Vec::new();
|
||||||
@ -1028,94 +942,6 @@ impl Expression {
|
|||||||
(instructions, vec![new_reg])
|
(instructions, vec![new_reg])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expression::Register(reg) => (Vec::new(), vec![*reg]),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_function_call(
|
|
||||||
expr: Node<Expression>,
|
|
||||||
params: Node<ExpressionList>,
|
|
||||||
state: &mut State,
|
|
||||||
scope: &mut Scope,
|
|
||||||
expected_values: Option<usize>,
|
|
||||||
) -> (Vec<PreInstr>, Vec<u16>) {
|
|
||||||
let mut instructions = Vec::new();
|
|
||||||
|
|
||||||
let (instr, registers) = expr.kind.compile(state, scope, Some(1));
|
|
||||||
instructions.extend(instr);
|
|
||||||
|
|
||||||
let old_function_reg = registers.first().unwrap();
|
|
||||||
|
|
||||||
let mut registers = scope
|
|
||||||
.register_counter
|
|
||||||
.consecutive(params.kind.0.len() + 1)
|
|
||||||
.into_iter();
|
|
||||||
|
|
||||||
let mut param_scope = scope.clone();
|
|
||||||
let mut original_param_regs = Vec::new();
|
|
||||||
let mut vararg = false;
|
|
||||||
for (i, param) in params.kind.0.iter().enumerate() {
|
|
||||||
let (instr, registers) = param.kind.compile(
|
|
||||||
state,
|
|
||||||
&mut param_scope,
|
|
||||||
if i == params.kind.0.len() - 1 {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(1)
|
|
||||||
},
|
|
||||||
);
|
|
||||||
instructions.extend(instr);
|
|
||||||
if registers.len() > 0 {
|
|
||||||
original_param_regs.push(*registers.first().unwrap());
|
|
||||||
} else {
|
|
||||||
vararg = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let function_reg = registers.next().unwrap();
|
|
||||||
let mut param_regs = Vec::new();
|
|
||||||
for _ in &original_param_regs {
|
|
||||||
param_regs.push(registers.next().unwrap());
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i, param_reg) in original_param_regs.iter().enumerate().rev() {
|
|
||||||
let new_reg = param_regs.get(i).unwrap();
|
|
||||||
if param_reg != new_reg {
|
|
||||||
instructions.push(PreInstr::Instr(Instruction::Move(*new_reg, *param_reg)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if function_reg != *old_function_reg {
|
|
||||||
instructions.push(PreInstr::Instr(Instruction::Move(
|
|
||||||
function_reg,
|
|
||||||
*old_function_reg,
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
|
|
||||||
if vararg {
|
|
||||||
let last_reg = param_regs.last().unwrap_or(&function_reg) + 1;
|
|
||||||
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();
|
|
||||||
if let Some(expected_values) = expected_values {
|
|
||||||
for i in 0..expected_values {
|
|
||||||
let return_reg = i as u16 + function_reg;
|
|
||||||
return_regs.push(return_reg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
instructions.push(PreInstr::Instr(Instruction::Call(
|
|
||||||
*&function_reg,
|
|
||||||
if vararg { 0 } else { param_regs.len() as u16 },
|
|
||||||
if return_regs.len() == 0 {
|
|
||||||
0
|
|
||||||
} else {
|
|
||||||
return_regs.len() as u16 + 1
|
|
||||||
},
|
|
||||||
)));
|
|
||||||
|
|
||||||
(instructions, return_regs)
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
//! Usage example:
|
//! Usage example:
|
||||||
//! ```rust
|
//! ```rust
|
||||||
//! use ferrite_lua::{compile, vm::{self, value}};
|
//! use ferrite_lua::{compile, vm};
|
||||||
//!
|
//!
|
||||||
//! #[derive(Debug, PartialEq, Eq)]
|
//! #[derive(Debug, PartialEq, Eq)]
|
||||||
//! pub struct Print;
|
//! pub struct Print;
|
||||||
//! impl value::RustFunction for Print {
|
//! impl vm::RustFunction for Print {
|
||||||
//! fn execute(&self, parameters: Vec<value::Value>) -> Result<Vec<value::Value>, vm::RuntimeError> {
|
//! fn execute(&self, parameters: Vec<vm::Value>) -> Result<Vec<vm::Value>, vm::RuntimeError> {
|
||||||
//! println!("{:?}", parameters);
|
//! println!("{:?}", parameters);
|
||||||
//! Ok(Vec::new())
|
//! Ok(Vec::new())
|
||||||
//! }
|
//! }
|
||||||
|
|||||||
@ -23,7 +23,6 @@ pub enum Keyword {
|
|||||||
Nil,
|
Nil,
|
||||||
Not,
|
Not,
|
||||||
For,
|
For,
|
||||||
In,
|
|
||||||
While,
|
While,
|
||||||
Repeat,
|
Repeat,
|
||||||
Until,
|
Until,
|
||||||
@ -49,7 +48,6 @@ impl Keyword {
|
|||||||
"nil" => Keyword::Nil,
|
"nil" => Keyword::Nil,
|
||||||
"not" => Keyword::Not,
|
"not" => Keyword::Not,
|
||||||
"for" => Keyword::For,
|
"for" => Keyword::For,
|
||||||
"in" => Keyword::In,
|
|
||||||
"do" => Keyword::Do,
|
"do" => Keyword::Do,
|
||||||
"break" => Keyword::Break,
|
"break" => Keyword::Break,
|
||||||
"goto" => Keyword::GoTo,
|
"goto" => Keyword::GoTo,
|
||||||
@ -78,7 +76,6 @@ impl ToString for Keyword {
|
|||||||
Keyword::Nil => "nil",
|
Keyword::Nil => "nil",
|
||||||
Keyword::Not => "not",
|
Keyword::Not => "not",
|
||||||
Keyword::For => "for",
|
Keyword::For => "for",
|
||||||
Keyword::In => "in",
|
|
||||||
Keyword::While => "while",
|
Keyword::While => "while",
|
||||||
Keyword::Repeat => "repeat",
|
Keyword::Repeat => "repeat",
|
||||||
Keyword::Until => "until",
|
Keyword::Until => "until",
|
||||||
|
|||||||
@ -5,10 +5,79 @@ use std::{cell::RefCell, collections::HashMap, fmt::Debug, hash::Hash, rc::Rc};
|
|||||||
use crate::{
|
use crate::{
|
||||||
CompilationUnit,
|
CompilationUnit,
|
||||||
ast::{BinaryOperator, UnaryOperator},
|
ast::{BinaryOperator, UnaryOperator},
|
||||||
vm::value::{IndexableValue, LuaBool, LuaInteger, VMFloat, Value},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod value;
|
#[derive(Clone, Hash, PartialEq, Eq, Copy, PartialOrd, Ord)]
|
||||||
|
pub struct VMFloat(u64);
|
||||||
|
|
||||||
|
impl VMFloat {
|
||||||
|
pub fn lua_number(&self) -> LuaFloat {
|
||||||
|
LuaFloat(f64::from_bits(self.0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for VMFloat {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
self.lua_number().fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct LuaFloat(pub f64);
|
||||||
|
|
||||||
|
impl LuaFloat {
|
||||||
|
pub fn vm_number(&self) -> VMFloat {
|
||||||
|
VMFloat(f64::to_bits(self.0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for LuaFloat {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
self.0.fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
pub struct LuaInteger(pub i64);
|
||||||
|
|
||||||
|
impl Debug for LuaInteger {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
self.0.fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<LuaInteger> for LuaFloat {
|
||||||
|
fn from(value: LuaInteger) -> Self {
|
||||||
|
LuaFloat(value.0 as f64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&LuaInteger> for LuaFloat {
|
||||||
|
fn from(value: &LuaInteger) -> Self {
|
||||||
|
LuaFloat(value.0 as f64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
pub struct LuaBool(pub bool);
|
||||||
|
|
||||||
|
impl Debug for LuaBool {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
self.0.fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<LuaBool> for LuaInteger {
|
||||||
|
fn from(value: LuaBool) -> Self {
|
||||||
|
LuaInteger(value.0 as i64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&LuaBool> for LuaInteger {
|
||||||
|
fn from(value: &LuaBool) -> Self {
|
||||||
|
LuaInteger(value.0 as i64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Hash, PartialEq, Eq)]
|
#[derive(Clone, Hash, PartialEq, Eq)]
|
||||||
pub enum Constant {
|
pub enum Constant {
|
||||||
@ -200,6 +269,261 @@ impl Environment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum Value {
|
||||||
|
String(String),
|
||||||
|
Float(VMFloat),
|
||||||
|
Integer(LuaInteger),
|
||||||
|
Boolean(LuaBool),
|
||||||
|
RustFunction(Rc<RefCell<dyn RustFunction>>),
|
||||||
|
Function(Closure),
|
||||||
|
Nil,
|
||||||
|
Table(Rc<RefCell<HashMap<IndexableValue, Value>>>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Value {
|
||||||
|
pub fn as_indexable(self) -> Result<IndexableValue, RuntimeError> {
|
||||||
|
match self {
|
||||||
|
Value::String(value) => Ok(IndexableValue::String(value)),
|
||||||
|
Value::Float(value) => Ok(IndexableValue::Float(value)),
|
||||||
|
Value::Integer(value) => Ok(IndexableValue::Integer(value)),
|
||||||
|
Value::Boolean(value) => Ok(IndexableValue::Bool(value)),
|
||||||
|
Value::RustFunction(value) => {
|
||||||
|
Ok(IndexableValue::RustFunction(value.borrow().as_indexable()))
|
||||||
|
}
|
||||||
|
Value::Function(closure) => Ok(IndexableValue::Function(closure.prototype)),
|
||||||
|
Value::Nil => Err(RuntimeError::InvalidTableIndex(self)),
|
||||||
|
Value::Table(_) => Err(RuntimeError::InvalidTableIndex(self)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_float(&self) -> Result<LuaFloat, RuntimeError> {
|
||||||
|
match self {
|
||||||
|
Value::Float(vmfloat) => Ok(vmfloat.lua_number()),
|
||||||
|
Value::Integer(lua_integer) => Ok(lua_integer.into()),
|
||||||
|
Value::Boolean(lua_boolean) => Ok(LuaFloat(lua_boolean.0 as u64 as f64)),
|
||||||
|
_ => Err(RuntimeError::NotFloatable(self.clone())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_integer(&self) -> Result<LuaInteger, RuntimeError> {
|
||||||
|
match self {
|
||||||
|
Value::Integer(lua_integer) => Ok(*lua_integer),
|
||||||
|
Value::Boolean(lua_boolean) => Ok(LuaInteger(lua_boolean.0 as i64)),
|
||||||
|
_ => Err(RuntimeError::NotFloatable(self.clone())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Hash, Clone, Ord, PartialOrd)]
|
||||||
|
pub enum IndexableValue {
|
||||||
|
String(String),
|
||||||
|
Float(VMFloat),
|
||||||
|
Integer(LuaInteger),
|
||||||
|
Bool(LuaBool),
|
||||||
|
RustFunction(String),
|
||||||
|
Function(u32),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Value {
|
||||||
|
pub fn add(&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::Add,
|
||||||
|
self.clone(),
|
||||||
|
other.clone(),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn eq(&self, other: &Value) -> Result<Value, RuntimeError> {
|
||||||
|
match (self, other) {
|
||||||
|
(Value::Integer(lhs), Value::Integer(rhs)) => {
|
||||||
|
Ok(Value::Boolean(LuaBool(lhs.0 == rhs.0)))
|
||||||
|
}
|
||||||
|
(Value::Float(_) | Value::Integer(_), Value::Float(_) | Value::Integer(_)) => {
|
||||||
|
let res = LuaBool(self.as_float()?.0 == other.as_float()?.0);
|
||||||
|
Ok(Value::Boolean(res))
|
||||||
|
}
|
||||||
|
_ => Err(RuntimeError::InvalidOperands(
|
||||||
|
BinaryOperator::Equal,
|
||||||
|
self.clone(),
|
||||||
|
other.clone(),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn lt(&self, other: &Value) -> Result<Value, RuntimeError> {
|
||||||
|
match (self, other) {
|
||||||
|
(Value::Integer(lhs), Value::Integer(rhs)) => {
|
||||||
|
Ok(Value::Boolean(LuaBool(lhs.0 < rhs.0)))
|
||||||
|
}
|
||||||
|
(Value::Float(_) | Value::Integer(_), Value::Float(_) | Value::Integer(_)) => {
|
||||||
|
let res = LuaBool(self.as_float()?.0 < other.as_float()?.0);
|
||||||
|
Ok(Value::Boolean(res))
|
||||||
|
}
|
||||||
|
_ => Err(RuntimeError::InvalidOperands(
|
||||||
|
BinaryOperator::LessThan,
|
||||||
|
self.clone(),
|
||||||
|
other.clone(),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn lte(&self, other: &Value) -> Result<Value, RuntimeError> {
|
||||||
|
match (self, other) {
|
||||||
|
(Value::Integer(lhs), Value::Integer(rhs)) => {
|
||||||
|
Ok(Value::Boolean(LuaBool(lhs.0 <= rhs.0)))
|
||||||
|
}
|
||||||
|
(Value::Float(_) | Value::Integer(_), Value::Float(_) | Value::Integer(_)) => {
|
||||||
|
let res = LuaBool(self.as_float()?.0 <= other.as_float()?.0);
|
||||||
|
Ok(Value::Boolean(res))
|
||||||
|
}
|
||||||
|
_ => Err(RuntimeError::InvalidOperands(
|
||||||
|
BinaryOperator::LessThanOrEqual,
|
||||||
|
self.clone(),
|
||||||
|
other.clone(),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unm(&self) -> Result<Value, RuntimeError> {
|
||||||
|
match self {
|
||||||
|
Value::Integer(lhs) => {
|
||||||
|
let res = LuaInteger(-lhs.0);
|
||||||
|
Ok(Value::Integer(res))
|
||||||
|
}
|
||||||
|
Value::Float(lhs) => {
|
||||||
|
let res = LuaFloat(-lhs.lua_number().0);
|
||||||
|
Ok(Value::Float(res.vm_number()))
|
||||||
|
}
|
||||||
|
Value::Boolean(val) => {
|
||||||
|
let res = LuaBool(!val.0);
|
||||||
|
Ok(Value::Boolean(res))
|
||||||
|
}
|
||||||
|
_ => Err(RuntimeError::InvalidOperand(
|
||||||
|
UnaryOperator::Negation,
|
||||||
|
self.clone(),
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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> {
|
||||||
|
if self.is_truthy() {
|
||||||
|
Ok(self.clone())
|
||||||
|
} else {
|
||||||
|
Ok(other.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn or(&self, other: &Value) -> Result<Value, RuntimeError> {
|
||||||
|
if self.is_truthy() {
|
||||||
|
Ok(self.clone())
|
||||||
|
} else {
|
||||||
|
Ok(other.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_truthy(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Value::String(_) => true,
|
||||||
|
Value::Float(_) => true,
|
||||||
|
Value::Integer(_) => true,
|
||||||
|
Value::Boolean(lua_bool) => lua_bool.0,
|
||||||
|
Value::RustFunction(_) => true,
|
||||||
|
Value::Function(_) => true,
|
||||||
|
Value::Nil => false,
|
||||||
|
Value::Table(_) => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for Value {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Value::Float(arg0) => f.debug_tuple("Float").field(&arg0.lua_number()).finish(),
|
||||||
|
Value::Integer(arg0) => f.debug_tuple("Integer").field(arg0).finish(),
|
||||||
|
Value::Boolean(arg0) => f.debug_tuple("Boolean").field(arg0).finish(),
|
||||||
|
Value::String(value) => f.debug_tuple("String").field(value).finish(),
|
||||||
|
Value::RustFunction(arg0) => f.debug_tuple("RustFunction").field(arg0).finish(),
|
||||||
|
Value::Function(closure) => f
|
||||||
|
.debug_tuple(&format!("Function({})", closure.prototype))
|
||||||
|
.finish(),
|
||||||
|
Value::Nil => write!(f, "Nil"),
|
||||||
|
Value::Table(hash_map) => {
|
||||||
|
let mut table = f.debug_struct("Table");
|
||||||
|
for (key, value) in hash_map.borrow().iter() {
|
||||||
|
table.field(&format!("{:?}", key), value);
|
||||||
|
}
|
||||||
|
table.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait RustFunction: Debug {
|
||||||
|
fn execute(&self, parameters: Vec<Value>) -> Result<Vec<Value>, RuntimeError>;
|
||||||
|
fn as_indexable(&self) -> String;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: RustFunction + 'static> From<T> for Value {
|
||||||
|
fn from(value: T) -> Self {
|
||||||
|
Self::RustFunction(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>,
|
||||||
@ -252,7 +576,7 @@ impl VirtualMachine {
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Closure {
|
pub struct Closure {
|
||||||
vm: VirtualMachine,
|
vm: VirtualMachine,
|
||||||
pub(crate) prototype: u32,
|
prototype: u32,
|
||||||
environment: Rc<RefCell<Environment>>,
|
environment: Rc<RefCell<Environment>>,
|
||||||
upvalues: HashMap<u16, Rc<RefCell<Value>>>,
|
upvalues: HashMap<u16, Rc<RefCell<Value>>>,
|
||||||
}
|
}
|
||||||
@ -263,7 +587,6 @@ impl Closure {
|
|||||||
for (i, param) in params.iter().enumerate() {
|
for (i, param) in params.iter().enumerate() {
|
||||||
stack.insert(i as u16, Rc::new(RefCell::new(param.clone())));
|
stack.insert(i as u16, Rc::new(RefCell::new(param.clone())));
|
||||||
}
|
}
|
||||||
|
|
||||||
ClosureRunner {
|
ClosureRunner {
|
||||||
closure: self.clone(),
|
closure: self.clone(),
|
||||||
program_counter: 0,
|
program_counter: 0,
|
||||||
@ -273,7 +596,6 @@ impl Closure {
|
|||||||
return_registers: Vec::new(),
|
return_registers: Vec::new(),
|
||||||
top: 0,
|
top: 0,
|
||||||
parameters: params,
|
parameters: params,
|
||||||
to_close_upvalues: 0,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -298,7 +620,6 @@ pub struct ClosureRunner {
|
|||||||
return_registers: Vec<u16>,
|
return_registers: Vec<u16>,
|
||||||
top: u16,
|
top: u16,
|
||||||
parameters: Vec<Value>,
|
parameters: Vec<Value>,
|
||||||
to_close_upvalues: u16,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
@ -339,17 +660,13 @@ impl ClosureRunner {
|
|||||||
.closure
|
.closure
|
||||||
.upvalues
|
.upvalues
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(v, _)| *v as i32)
|
.map(|(v, _)| *v)
|
||||||
.max()
|
.max()
|
||||||
.unwrap_or(-1);
|
.unwrap_or(0);
|
||||||
|
|
||||||
let mut upvalues = self.closure.upvalues.clone();
|
let mut upvalues = self.closure.upvalues.clone();
|
||||||
for (reg, value) in self
|
for (reg, value) in &self.stack {
|
||||||
.stack
|
upvalues.insert(reg + highest_upvalue + 1, value.clone());
|
||||||
.iter()
|
|
||||||
.filter(|(r, _)| **r < self.to_close_upvalues)
|
|
||||||
{
|
|
||||||
upvalues.insert(reg + (highest_upvalue + 1) as u16, value.clone());
|
|
||||||
}
|
}
|
||||||
upvalues
|
upvalues
|
||||||
}
|
}
|
||||||
@ -382,17 +699,19 @@ impl ClosureRunner {
|
|||||||
self.inner = None;
|
self.inner = None;
|
||||||
if self.return_registers.len() == 0 {
|
if self.return_registers.len() == 0 {
|
||||||
for (i, value) in ret_values.iter().enumerate() {
|
for (i, value) in ret_values.iter().enumerate() {
|
||||||
self.set_stack(
|
self.stack.insert(
|
||||||
self.function_register + i as u16 + 1,
|
self.function_register + i as u16 + 1,
|
||||||
StackValue::Value(value.clone()),
|
Rc::new(RefCell::new(value.clone())),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
self.top = self.function_register + ret_values.len() as u16;
|
self.top = self.function_register + ret_values.len() as u16;
|
||||||
}
|
}
|
||||||
for (i, reg) in self.return_registers.clone().iter().enumerate() {
|
for (i, reg) in self.return_registers.iter().enumerate() {
|
||||||
self.set_stack(
|
self.stack.insert(
|
||||||
*reg,
|
*reg,
|
||||||
StackValue::Value(ret_values.get(i).cloned().unwrap_or(Value::Nil)),
|
Rc::new(RefCell::new(
|
||||||
|
ret_values.get(i).cloned().unwrap_or(Value::Nil),
|
||||||
|
)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -446,7 +765,7 @@ impl ClosureRunner {
|
|||||||
}
|
}
|
||||||
Instruction::LoadNil(from_reg, to_reg) => {
|
Instruction::LoadNil(from_reg, to_reg) => {
|
||||||
for i in *from_reg..=*to_reg {
|
for i in *from_reg..=*to_reg {
|
||||||
self.set_stack(i, StackValue::Value(Value::Nil));
|
self.stack.insert(i, Rc::new(RefCell::new(Value::Nil)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Instruction::SetGlobal(reg, global) => {
|
Instruction::SetGlobal(reg, global) => {
|
||||||
@ -679,18 +998,15 @@ impl ClosureRunner {
|
|||||||
_ => return Err(RuntimeError::TriedCallingNonFunction(value.clone())),
|
_ => return Err(RuntimeError::TriedCallingNonFunction(value.clone())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Instruction::Close(up_until) => {
|
Instruction::Close(_) => {}
|
||||||
self.to_close_upvalues = *up_until;
|
|
||||||
}
|
|
||||||
Instruction::Closure(reg, protok) => {
|
Instruction::Closure(reg, protok) => {
|
||||||
let upvalues = self.close_upvalues();
|
|
||||||
self.set_stack(
|
self.set_stack(
|
||||||
*reg,
|
*reg,
|
||||||
StackValue::Value(Value::Function(Closure {
|
StackValue::Value(Value::Function(Closure {
|
||||||
vm: self.closure.vm.clone(),
|
vm: self.closure.vm.clone(),
|
||||||
prototype: *protok,
|
prototype: *protok,
|
||||||
environment: self.closure.environment.clone(),
|
environment: self.closure.environment.clone(),
|
||||||
upvalues,
|
upvalues: self.close_upvalues(),
|
||||||
})),
|
})),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
333
src/vm/value.rs
333
src/vm/value.rs
@ -1,333 +0,0 @@
|
|||||||
use std::{cell::RefCell, collections::HashMap, fmt::Debug, rc::Rc};
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
ast::{BinaryOperator, UnaryOperator},
|
|
||||||
vm::{Closure, RuntimeError},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Clone, Hash, PartialEq, Eq, Copy, PartialOrd, Ord)]
|
|
||||||
pub struct VMFloat(u64);
|
|
||||||
|
|
||||||
impl VMFloat {
|
|
||||||
pub fn lua_number(&self) -> LuaFloat {
|
|
||||||
LuaFloat(f64::from_bits(self.0))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Debug for VMFloat {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
self.lua_number().fmt(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
|
||||||
pub struct LuaFloat(pub f64);
|
|
||||||
|
|
||||||
impl LuaFloat {
|
|
||||||
pub fn vm_number(&self) -> VMFloat {
|
|
||||||
VMFloat(f64::to_bits(self.0))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Debug for LuaFloat {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
self.0.fmt(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
|
||||||
pub struct LuaInteger(pub i64);
|
|
||||||
|
|
||||||
impl Debug for LuaInteger {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
self.0.fmt(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<LuaInteger> for LuaFloat {
|
|
||||||
fn from(value: LuaInteger) -> Self {
|
|
||||||
LuaFloat(value.0 as f64)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<&LuaInteger> for LuaFloat {
|
|
||||||
fn from(value: &LuaInteger) -> Self {
|
|
||||||
LuaFloat(value.0 as f64)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
|
||||||
pub struct LuaBool(pub bool);
|
|
||||||
|
|
||||||
impl Debug for LuaBool {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
self.0.fmt(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<LuaBool> for LuaInteger {
|
|
||||||
fn from(value: LuaBool) -> Self {
|
|
||||||
LuaInteger(value.0 as i64)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<&LuaBool> for LuaInteger {
|
|
||||||
fn from(value: &LuaBool) -> Self {
|
|
||||||
LuaInteger(value.0 as i64)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait RustFunction: Debug {
|
|
||||||
fn execute(&self, parameters: Vec<Value>) -> Result<Vec<Value>, RuntimeError>;
|
|
||||||
fn as_indexable(&self) -> String;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: RustFunction + 'static> From<T> for Value {
|
|
||||||
fn from(value: T) -> Self {
|
|
||||||
Self::RustFunction(Rc::new(RefCell::new(value)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub enum Value {
|
|
||||||
String(String),
|
|
||||||
Float(VMFloat),
|
|
||||||
Integer(LuaInteger),
|
|
||||||
Boolean(LuaBool),
|
|
||||||
RustFunction(Rc<RefCell<dyn RustFunction>>),
|
|
||||||
Function(Closure),
|
|
||||||
Nil,
|
|
||||||
Table(Rc<RefCell<HashMap<IndexableValue, Value>>>),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Value {
|
|
||||||
pub fn as_indexable(self) -> Result<IndexableValue, RuntimeError> {
|
|
||||||
match self {
|
|
||||||
Value::String(value) => Ok(IndexableValue::String(value)),
|
|
||||||
Value::Float(value) => Ok(IndexableValue::Float(value)),
|
|
||||||
Value::Integer(value) => Ok(IndexableValue::Integer(value)),
|
|
||||||
Value::Boolean(value) => Ok(IndexableValue::Bool(value)),
|
|
||||||
Value::RustFunction(value) => {
|
|
||||||
Ok(IndexableValue::RustFunction(value.borrow().as_indexable()))
|
|
||||||
}
|
|
||||||
Value::Function(closure) => Ok(IndexableValue::Function(closure.prototype)),
|
|
||||||
Value::Nil => Err(RuntimeError::InvalidTableIndex(self)),
|
|
||||||
Value::Table(_) => Err(RuntimeError::InvalidTableIndex(self)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn as_float(&self) -> Result<LuaFloat, RuntimeError> {
|
|
||||||
match self {
|
|
||||||
Value::Float(vmfloat) => Ok(vmfloat.lua_number()),
|
|
||||||
Value::Integer(lua_integer) => Ok(lua_integer.into()),
|
|
||||||
Value::Boolean(lua_boolean) => Ok(LuaFloat(lua_boolean.0 as u64 as f64)),
|
|
||||||
_ => Err(RuntimeError::NotFloatable(self.clone())),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn as_integer(&self) -> Result<LuaInteger, RuntimeError> {
|
|
||||||
match self {
|
|
||||||
Value::Integer(lua_integer) => Ok(*lua_integer),
|
|
||||||
Value::Boolean(lua_boolean) => Ok(LuaInteger(lua_boolean.0 as i64)),
|
|
||||||
_ => Err(RuntimeError::NotFloatable(self.clone())),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Hash, Clone, Ord, PartialOrd)]
|
|
||||||
pub enum IndexableValue {
|
|
||||||
String(String),
|
|
||||||
Float(VMFloat),
|
|
||||||
Integer(LuaInteger),
|
|
||||||
Bool(LuaBool),
|
|
||||||
RustFunction(String),
|
|
||||||
Function(u32),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Value {
|
|
||||||
pub fn add(&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::Add,
|
|
||||||
self.clone(),
|
|
||||||
other.clone(),
|
|
||||||
)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn eq(&self, other: &Value) -> Result<Value, RuntimeError> {
|
|
||||||
match (self, other) {
|
|
||||||
(Value::Integer(lhs), Value::Integer(rhs)) => {
|
|
||||||
Ok(Value::Boolean(LuaBool(lhs.0 == rhs.0)))
|
|
||||||
}
|
|
||||||
(Value::Float(_) | Value::Integer(_), Value::Float(_) | Value::Integer(_)) => {
|
|
||||||
let res = LuaBool(self.as_float()?.0 == other.as_float()?.0);
|
|
||||||
Ok(Value::Boolean(res))
|
|
||||||
}
|
|
||||||
(Value::Nil, Value::Nil) => Ok(Value::Boolean(LuaBool(true))),
|
|
||||||
(Value::Nil, _) | (_, Value::Nil) => Ok(Value::Boolean(LuaBool(false))),
|
|
||||||
_ => Ok(Value::Boolean(LuaBool(
|
|
||||||
self.clone().as_indexable()? == other.clone().as_indexable()?,
|
|
||||||
))),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn lt(&self, other: &Value) -> Result<Value, RuntimeError> {
|
|
||||||
match (self, other) {
|
|
||||||
(Value::Integer(lhs), Value::Integer(rhs)) => {
|
|
||||||
Ok(Value::Boolean(LuaBool(lhs.0 < rhs.0)))
|
|
||||||
}
|
|
||||||
(Value::Float(_) | Value::Integer(_), Value::Float(_) | Value::Integer(_)) => {
|
|
||||||
let res = LuaBool(self.as_float()?.0 < other.as_float()?.0);
|
|
||||||
Ok(Value::Boolean(res))
|
|
||||||
}
|
|
||||||
_ => Err(RuntimeError::InvalidOperands(
|
|
||||||
BinaryOperator::LessThan,
|
|
||||||
self.clone(),
|
|
||||||
other.clone(),
|
|
||||||
)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn lte(&self, other: &Value) -> Result<Value, RuntimeError> {
|
|
||||||
match (self, other) {
|
|
||||||
(Value::Integer(lhs), Value::Integer(rhs)) => {
|
|
||||||
Ok(Value::Boolean(LuaBool(lhs.0 <= rhs.0)))
|
|
||||||
}
|
|
||||||
(Value::Float(_) | Value::Integer(_), Value::Float(_) | Value::Integer(_)) => {
|
|
||||||
let res = LuaBool(self.as_float()?.0 <= other.as_float()?.0);
|
|
||||||
Ok(Value::Boolean(res))
|
|
||||||
}
|
|
||||||
_ => Err(RuntimeError::InvalidOperands(
|
|
||||||
BinaryOperator::LessThanOrEqual,
|
|
||||||
self.clone(),
|
|
||||||
other.clone(),
|
|
||||||
)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn unm(&self) -> Result<Value, RuntimeError> {
|
|
||||||
match self {
|
|
||||||
Value::Integer(lhs) => {
|
|
||||||
let res = LuaInteger(-lhs.0);
|
|
||||||
Ok(Value::Integer(res))
|
|
||||||
}
|
|
||||||
Value::Float(lhs) => {
|
|
||||||
let res = LuaFloat(-lhs.lua_number().0);
|
|
||||||
Ok(Value::Float(res.vm_number()))
|
|
||||||
}
|
|
||||||
Value::Boolean(val) => {
|
|
||||||
let res = LuaBool(!val.0);
|
|
||||||
Ok(Value::Boolean(res))
|
|
||||||
}
|
|
||||||
_ => Err(RuntimeError::InvalidOperand(
|
|
||||||
UnaryOperator::Negation,
|
|
||||||
self.clone(),
|
|
||||||
)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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> {
|
|
||||||
if self.is_truthy() {
|
|
||||||
Ok(self.clone())
|
|
||||||
} else {
|
|
||||||
Ok(other.clone())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn or(&self, other: &Value) -> Result<Value, RuntimeError> {
|
|
||||||
if self.is_truthy() {
|
|
||||||
Ok(self.clone())
|
|
||||||
} else {
|
|
||||||
Ok(other.clone())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_truthy(&self) -> bool {
|
|
||||||
match self {
|
|
||||||
Value::String(_) => true,
|
|
||||||
Value::Float(_) => true,
|
|
||||||
Value::Integer(_) => true,
|
|
||||||
Value::Boolean(lua_bool) => lua_bool.0,
|
|
||||||
Value::RustFunction(_) => true,
|
|
||||||
Value::Function(_) => true,
|
|
||||||
Value::Nil => false,
|
|
||||||
Value::Table(_) => true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Debug for Value {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
match self {
|
|
||||||
Value::Float(arg0) => f.debug_tuple("Float").field(&arg0.lua_number()).finish(),
|
|
||||||
Value::Integer(arg0) => f.debug_tuple("Integer").field(arg0).finish(),
|
|
||||||
Value::Boolean(arg0) => f.debug_tuple("Boolean").field(arg0).finish(),
|
|
||||||
Value::String(value) => f.debug_tuple("String").field(value).finish(),
|
|
||||||
Value::RustFunction(arg0) => f.debug_tuple("RustFunction").field(arg0).finish(),
|
|
||||||
Value::Function(closure) => f
|
|
||||||
.debug_tuple(&format!("Function({})", closure.prototype))
|
|
||||||
.finish(),
|
|
||||||
Value::Nil => write!(f, "Nil"),
|
|
||||||
Value::Table(hash_map) => {
|
|
||||||
let mut table = f.debug_struct("Table");
|
|
||||||
for (key, value) in hash_map.borrow().iter() {
|
|
||||||
table.field(&format!("{:?}", key), value);
|
|
||||||
}
|
|
||||||
table.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue
Block a user