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
|
||||
print("before")
|
||||
@ -65,31 +5,4 @@ while i < 10 do
|
||||
i = i + 1
|
||||
print(i)
|
||||
end
|
||||
print("after while")
|
||||
|
||||
|
||||
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
|
||||
print("after")
|
||||
@ -1,19 +1,19 @@
|
||||
use ferrite_lua::{
|
||||
compile,
|
||||
vm::{RuntimeError, VirtualMachine, value},
|
||||
vm::{self, RuntimeError, RustFunction, VirtualMachine},
|
||||
};
|
||||
|
||||
static TEST: &str = include_str!("../examples/test.lua");
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct Max;
|
||||
impl value::RustFunction for Max {
|
||||
fn execute(&self, parameters: Vec<value::Value>) -> Result<Vec<value::Value>, RuntimeError> {
|
||||
let lhs = parameters.get(0).cloned().unwrap_or(value::Value::Nil);
|
||||
let rhs = parameters.get(1).cloned().unwrap_or(value::Value::Nil);
|
||||
impl RustFunction for Max {
|
||||
fn execute(&self, parameters: Vec<vm::Value>) -> Result<Vec<vm::Value>, RuntimeError> {
|
||||
let lhs = parameters.get(0).cloned().unwrap_or(vm::Value::Nil);
|
||||
let rhs = parameters.get(1).cloned().unwrap_or(vm::Value::Nil);
|
||||
match lhs.lt(&rhs)? {
|
||||
value::Value::Boolean(value) => Ok(vec![if value.0 { rhs } else { lhs }]),
|
||||
_ => Ok(vec![value::Value::Nil]),
|
||||
vm::Value::Boolean(value) => Ok(vec![if value.0 { rhs } else { lhs }]),
|
||||
_ => Ok(vec![vm::Value::Nil]),
|
||||
}
|
||||
}
|
||||
|
||||
@ -23,8 +23,8 @@ impl value::RustFunction for Max {
|
||||
}
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct Print;
|
||||
impl value::RustFunction for Print {
|
||||
fn execute(&self, parameters: Vec<value::Value>) -> Result<Vec<value::Value>, RuntimeError> {
|
||||
impl RustFunction for Print {
|
||||
fn execute(&self, parameters: Vec<vm::Value>) -> Result<Vec<vm::Value>, RuntimeError> {
|
||||
println!("{:?}", parameters);
|
||||
Ok(Vec::new())
|
||||
}
|
||||
|
||||
38
src/ast.rs
38
src/ast.rs
@ -5,7 +5,7 @@ use crate::{
|
||||
Parse, TokenRange, TokenStream, TokenStreamError,
|
||||
lexer::{Keyword, Position, Token},
|
||||
},
|
||||
vm::value::{LuaFloat, LuaInteger},
|
||||
vm::{LuaFloat, LuaInteger},
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@ -238,7 +238,6 @@ impl Parse for Block {
|
||||
Token::Keyword(Keyword::End)
|
||||
| Token::Keyword(Keyword::ElseIf)
|
||||
| Token::Keyword(Keyword::Else)
|
||||
| Token::Keyword(Keyword::Until)
|
||||
| Token::Eof
|
||||
)
|
||||
) {
|
||||
@ -272,14 +271,11 @@ pub enum Statement {
|
||||
Node<Expression>,
|
||||
Block,
|
||||
),
|
||||
GenericFor(Vec<Node<String>>, Node<ExpressionList>, Block),
|
||||
While(Node<Expression>, Block),
|
||||
Repeat(Block, Node<Expression>),
|
||||
Break,
|
||||
Label(Node<String>),
|
||||
GoTo(Node<String>),
|
||||
Empty,
|
||||
Block(Block),
|
||||
}
|
||||
|
||||
impl Parse for Statement {
|
||||
@ -380,22 +376,6 @@ impl Parse for Statement {
|
||||
} else if stream.peek() == Some(Token::Keyword(Keyword::For)) {
|
||||
stream.next();
|
||||
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('=')?;
|
||||
let init = stream.parse()?;
|
||||
stream.expect_symbol(',')?;
|
||||
@ -422,7 +402,6 @@ impl Parse for Statement {
|
||||
step,
|
||||
block,
|
||||
))
|
||||
}
|
||||
} else if let Some(Token::Keyword(Keyword::While)) = stream.peek() {
|
||||
stream.next();
|
||||
let expr = stream.parse()?;
|
||||
@ -453,14 +432,6 @@ impl Parse for Statement {
|
||||
} else if let Some(Token::Keyword(Keyword::GoTo)) = stream.peek() {
|
||||
stream.next();
|
||||
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 {
|
||||
Err(stream.expecting_err("statement"))
|
||||
}
|
||||
@ -524,8 +495,6 @@ pub enum Expression {
|
||||
TableConstructor(Vec<(Option<Node<Expression>>, Node<Expression>)>),
|
||||
IndexedAccess(Box<Node<Expression>>, Box<Node<Expression>>),
|
||||
Ellipsis,
|
||||
/// Raw access to a register
|
||||
Register(u16),
|
||||
}
|
||||
|
||||
impl Parse for Expression {
|
||||
@ -699,11 +668,6 @@ impl Parse for PrimaryExpression {
|
||||
Expression::TableConstructor(entries)
|
||||
} else if let Ok(_) = stream.parse::<Ellipsis>() {
|
||||
Expression::Ellipsis
|
||||
} else if let Some(Token::Symbol('(')) = stream.peek() {
|
||||
stream.next();
|
||||
let expression = stream.parse()?;
|
||||
stream.expect_symbol(')')?;
|
||||
expression
|
||||
} else {
|
||||
Expression::ValueRef(stream.parse()?)
|
||||
};
|
||||
|
||||
372
src/compile.rs
372
src/compile.rs
@ -1,17 +1,11 @@
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
num::IntErrorKind,
|
||||
};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
use crate::{
|
||||
ast::{
|
||||
AccessModifier, BinaryOperator, Block, Expression, ExpressionList, IdentOrEllipsis,
|
||||
Literal, Node, Statement, UnaryOperator,
|
||||
},
|
||||
vm::{
|
||||
Constant, Instruction, Prototype,
|
||||
value::{LuaBool, LuaInteger},
|
||||
AccessModifier, BinaryOperator, Block, Expression, IdentOrEllipsis, Literal, Statement,
|
||||
UnaryOperator,
|
||||
},
|
||||
vm::{Constant, Instruction, LuaBool, LuaInteger, Prototype},
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
@ -31,27 +25,15 @@ impl State {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct Scope {
|
||||
pub locals: HashMap<String, u16>,
|
||||
pub register_counter: LocalCounter,
|
||||
pub highest_upvalue: i32,
|
||||
pub highest_upvalue: u16,
|
||||
pub upvalues: HashMap<String, u16>,
|
||||
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)]
|
||||
pub struct LocalCounter(u16, Vec<u16>);
|
||||
|
||||
@ -225,14 +207,6 @@ impl Statement {
|
||||
constants.extend(block.find_constants(scope, Vec::new()));
|
||||
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) => {
|
||||
let mut constants = HashSet::new();
|
||||
constants.extend(node.kind.find_constants(scope));
|
||||
@ -248,12 +222,6 @@ impl Statement {
|
||||
Statement::Break => HashSet::new(),
|
||||
Statement::Label(_) => 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);
|
||||
}
|
||||
|
||||
let new_ret_registers = scope.register_counter.consecutive(ret_registers.len() + 1);
|
||||
let first_ret_register = new_ret_registers.first().unwrap();
|
||||
let first_ret_register = ret_registers
|
||||
.iter()
|
||||
.cloned()
|
||||
.next()
|
||||
.unwrap_or(scope.register_counter.0);
|
||||
for (i, ret_register) in ret_registers.iter_mut().enumerate() {
|
||||
let new_reg = first_ret_register + i as u16;
|
||||
if *ret_register != new_reg {
|
||||
@ -435,7 +406,7 @@ impl Statement {
|
||||
}
|
||||
|
||||
instructions.push(PreInstr::Instr(Instruction::Return(
|
||||
*first_ret_register,
|
||||
first_ret_register,
|
||||
if vararg {
|
||||
0
|
||||
} else {
|
||||
@ -510,111 +481,6 @@ impl Statement {
|
||||
)));
|
||||
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) => {
|
||||
let (instr, expr_regs) = expr.kind.compile(state, scope, Some(1));
|
||||
let expr_instr_len = instr.len() as i32;
|
||||
@ -625,47 +491,20 @@ impl Statement {
|
||||
0,
|
||||
)));
|
||||
|
||||
let mut inner_scope = scope.clone();
|
||||
|
||||
let block_instructions = block.compile(state, &mut inner_scope);
|
||||
let block_instructions = block.compile(state, scope);
|
||||
let block_instr_len = block_instructions.len() as i32;
|
||||
|
||||
instructions.push(PreInstr::Instr(Instruction::Jmp(block_instr_len + 1)));
|
||||
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(
|
||||
-(block_instr_len + expr_instr_len + 2),
|
||||
)));
|
||||
}
|
||||
Statement::Repeat(block, expr) => todo!(),
|
||||
Statement::Break => instructions.push(PreInstr::Break),
|
||||
Statement::Label(node) => instructions.push(PreInstr::Label(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 {
|
||||
@ -758,7 +597,6 @@ impl Expression {
|
||||
constants
|
||||
}
|
||||
Expression::Ellipsis => HashSet::new(),
|
||||
Expression::Register(_) => HashSet::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -895,19 +733,14 @@ impl Expression {
|
||||
}
|
||||
}
|
||||
|
||||
inner_scope.highest_upvalue =
|
||||
scope.highest_upvalue + scope.register_counter.0 as i32;
|
||||
inner_scope.highest_upvalue = scope.highest_upvalue + scope.register_counter.0;
|
||||
inner_scope.upvalues = scope.upvalues.clone();
|
||||
|
||||
dbg!(&scope.highest_upvalue, &scope.register_counter.0);
|
||||
|
||||
for (name, reg) in &scope.locals {
|
||||
let upvalue_reg = *reg + (scope.highest_upvalue + 1) as u16;
|
||||
inner_scope.upvalues.insert(name.clone(), upvalue_reg);
|
||||
let new_reg = *reg + scope.highest_upvalue + 1;
|
||||
inner_scope.upvalues.insert(name.clone(), new_reg);
|
||||
}
|
||||
|
||||
dbg!(&inner_scope.upvalues);
|
||||
|
||||
let instructions = block.compile(state, &mut inner_scope);
|
||||
state.prototypes.push(Prototype {
|
||||
instructions: process_pre_instrs(instructions),
|
||||
@ -931,7 +764,88 @@ impl Expression {
|
||||
(instructions, vec![local])
|
||||
}
|
||||
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) => {
|
||||
let mut instructions = Vec::new();
|
||||
@ -1028,94 +942,6 @@ impl Expression {
|
||||
(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:
|
||||
//! ```rust
|
||||
//! use ferrite_lua::{compile, vm::{self, value}};
|
||||
//! use ferrite_lua::{compile, vm};
|
||||
//!
|
||||
//! #[derive(Debug, PartialEq, Eq)]
|
||||
//! pub struct Print;
|
||||
//! impl value::RustFunction for Print {
|
||||
//! fn execute(&self, parameters: Vec<value::Value>) -> Result<Vec<value::Value>, vm::RuntimeError> {
|
||||
//! impl vm::RustFunction for Print {
|
||||
//! fn execute(&self, parameters: Vec<vm::Value>) -> Result<Vec<vm::Value>, vm::RuntimeError> {
|
||||
//! println!("{:?}", parameters);
|
||||
//! Ok(Vec::new())
|
||||
//! }
|
||||
|
||||
@ -23,7 +23,6 @@ pub enum Keyword {
|
||||
Nil,
|
||||
Not,
|
||||
For,
|
||||
In,
|
||||
While,
|
||||
Repeat,
|
||||
Until,
|
||||
@ -49,7 +48,6 @@ impl Keyword {
|
||||
"nil" => Keyword::Nil,
|
||||
"not" => Keyword::Not,
|
||||
"for" => Keyword::For,
|
||||
"in" => Keyword::In,
|
||||
"do" => Keyword::Do,
|
||||
"break" => Keyword::Break,
|
||||
"goto" => Keyword::GoTo,
|
||||
@ -78,7 +76,6 @@ impl ToString for Keyword {
|
||||
Keyword::Nil => "nil",
|
||||
Keyword::Not => "not",
|
||||
Keyword::For => "for",
|
||||
Keyword::In => "in",
|
||||
Keyword::While => "while",
|
||||
Keyword::Repeat => "repeat",
|
||||
Keyword::Until => "until",
|
||||
|
||||
@ -5,10 +5,79 @@ use std::{cell::RefCell, collections::HashMap, fmt::Debug, hash::Hash, rc::Rc};
|
||||
use crate::{
|
||||
CompilationUnit,
|
||||
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)]
|
||||
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)]
|
||||
pub struct Prototype {
|
||||
pub instructions: Vec<Instruction>,
|
||||
@ -252,7 +576,7 @@ impl VirtualMachine {
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Closure {
|
||||
vm: VirtualMachine,
|
||||
pub(crate) prototype: u32,
|
||||
prototype: u32,
|
||||
environment: Rc<RefCell<Environment>>,
|
||||
upvalues: HashMap<u16, Rc<RefCell<Value>>>,
|
||||
}
|
||||
@ -263,7 +587,6 @@ impl Closure {
|
||||
for (i, param) in params.iter().enumerate() {
|
||||
stack.insert(i as u16, Rc::new(RefCell::new(param.clone())));
|
||||
}
|
||||
|
||||
ClosureRunner {
|
||||
closure: self.clone(),
|
||||
program_counter: 0,
|
||||
@ -273,7 +596,6 @@ impl Closure {
|
||||
return_registers: Vec::new(),
|
||||
top: 0,
|
||||
parameters: params,
|
||||
to_close_upvalues: 0,
|
||||
}
|
||||
}
|
||||
|
||||
@ -298,7 +620,6 @@ pub struct ClosureRunner {
|
||||
return_registers: Vec<u16>,
|
||||
top: u16,
|
||||
parameters: Vec<Value>,
|
||||
to_close_upvalues: u16,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
@ -339,17 +660,13 @@ impl ClosureRunner {
|
||||
.closure
|
||||
.upvalues
|
||||
.iter()
|
||||
.map(|(v, _)| *v as i32)
|
||||
.map(|(v, _)| *v)
|
||||
.max()
|
||||
.unwrap_or(-1);
|
||||
.unwrap_or(0);
|
||||
|
||||
let mut upvalues = self.closure.upvalues.clone();
|
||||
for (reg, value) in self
|
||||
.stack
|
||||
.iter()
|
||||
.filter(|(r, _)| **r < self.to_close_upvalues)
|
||||
{
|
||||
upvalues.insert(reg + (highest_upvalue + 1) as u16, value.clone());
|
||||
for (reg, value) in &self.stack {
|
||||
upvalues.insert(reg + highest_upvalue + 1, value.clone());
|
||||
}
|
||||
upvalues
|
||||
}
|
||||
@ -382,17 +699,19 @@ impl ClosureRunner {
|
||||
self.inner = None;
|
||||
if self.return_registers.len() == 0 {
|
||||
for (i, value) in ret_values.iter().enumerate() {
|
||||
self.set_stack(
|
||||
self.stack.insert(
|
||||
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;
|
||||
}
|
||||
for (i, reg) in self.return_registers.clone().iter().enumerate() {
|
||||
self.set_stack(
|
||||
for (i, reg) in self.return_registers.iter().enumerate() {
|
||||
self.stack.insert(
|
||||
*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 {
|
||||
@ -446,7 +765,7 @@ impl ClosureRunner {
|
||||
}
|
||||
Instruction::LoadNil(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) => {
|
||||
@ -679,18 +998,15 @@ impl ClosureRunner {
|
||||
_ => return Err(RuntimeError::TriedCallingNonFunction(value.clone())),
|
||||
}
|
||||
}
|
||||
Instruction::Close(up_until) => {
|
||||
self.to_close_upvalues = *up_until;
|
||||
}
|
||||
Instruction::Close(_) => {}
|
||||
Instruction::Closure(reg, protok) => {
|
||||
let upvalues = self.close_upvalues();
|
||||
self.set_stack(
|
||||
*reg,
|
||||
StackValue::Value(Value::Function(Closure {
|
||||
vm: self.closure.vm.clone(),
|
||||
prototype: *protok,
|
||||
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