Compare commits
10 Commits
c37e95e445
...
2afe480be1
| Author | SHA1 | Date | |
|---|---|---|---|
| 2afe480be1 | |||
| 0fda2c6d4b | |||
| 80dfd74ee5 | |||
| f55f9be345 | |||
| 8c0220c0c2 | |||
| e30ecd865a | |||
| 0fcd00864b | |||
| e259bae865 | |||
| f6548019e3 | |||
| 1e2feb9c3c |
@ -20,10 +20,11 @@ global sometable = {}
|
|||||||
sometable["hello"] = {}
|
sometable["hello"] = {}
|
||||||
sometable["hello"].there = "my dude"
|
sometable["hello"].there = "my dude"
|
||||||
|
|
||||||
print(max(11, 9))
|
print(max(11.12345, 9))
|
||||||
print(add(10)(15))
|
print(add(10)(15))
|
||||||
print(add(10)(15))
|
print(add(10)(15))
|
||||||
print(b)
|
print(b)
|
||||||
print(min(11, 9))
|
print(min(11, 9))
|
||||||
print(10 - 15)
|
print(10 - 15)
|
||||||
print("hello there!")
|
print("hello there!")
|
||||||
|
print(true or 0)
|
||||||
65
examples/test.rs
Normal file
65
examples/test.rs
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
use ferrite_lua::{
|
||||||
|
compile,
|
||||||
|
vm::{self, RuntimeError, RustFunction, VirtualMachine},
|
||||||
|
};
|
||||||
|
|
||||||
|
static TEST: &str = include_str!("../examples/test.lua");
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
pub struct Max;
|
||||||
|
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)? {
|
||||||
|
vm::Value::Boolean(value) => Ok(vec![if value.0 { rhs } else { lhs }]),
|
||||||
|
_ => Ok(vec![vm::Value::Nil]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_indexable(&self) -> String {
|
||||||
|
"std::max".to_owned()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
pub struct Print;
|
||||||
|
impl RustFunction for Print {
|
||||||
|
fn execute(&self, parameters: Vec<vm::Value>) -> Result<Vec<vm::Value>, RuntimeError> {
|
||||||
|
println!("{:?}", parameters);
|
||||||
|
Ok(Vec::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_indexable(&self) -> String {
|
||||||
|
"std::print".to_owned()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let compilation_unit = compile(TEST, None).unwrap();
|
||||||
|
|
||||||
|
let mut vm = VirtualMachine::default();
|
||||||
|
|
||||||
|
vm.set_global("max".into(), Max.into());
|
||||||
|
vm.set_global("print".into(), Print.into());
|
||||||
|
|
||||||
|
dbg!(&compilation_unit);
|
||||||
|
|
||||||
|
let mut runner = compilation_unit.with_virtual_machine(&mut vm).execute();
|
||||||
|
|
||||||
|
while runner.next().unwrap().is_none() {
|
||||||
|
// let inner = compile("print(b)", Some(&compilation_unit)).unwrap();
|
||||||
|
// let mut inner_runner = runner.execute(&inner);
|
||||||
|
// while {
|
||||||
|
// match inner_runner.next() {
|
||||||
|
// Ok(Some(_)) => false,
|
||||||
|
// Ok(None) => true,
|
||||||
|
// Err(e) => {
|
||||||
|
// println!("Error: {}", e);
|
||||||
|
// false
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// } {}
|
||||||
|
}
|
||||||
|
|
||||||
|
dbg!(&vm.get_globals());
|
||||||
|
}
|
||||||
38
src/ast.rs
38
src/ast.rs
@ -134,7 +134,7 @@ pub struct Function {
|
|||||||
pub name: Option<Node<String>>,
|
pub name: Option<Node<String>>,
|
||||||
pub params: Vec<Node<String>>,
|
pub params: Vec<Node<String>>,
|
||||||
pub block: Block,
|
pub block: Block,
|
||||||
pub meta: Metadata,
|
pub _meta: Metadata,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for Function {
|
impl Parse for Function {
|
||||||
@ -165,7 +165,7 @@ impl Parse for Function {
|
|||||||
name,
|
name,
|
||||||
params,
|
params,
|
||||||
block,
|
block,
|
||||||
meta: Metadata::produce(&mut stream, pre),
|
_meta: Metadata::produce(&mut stream, pre),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -183,7 +183,7 @@ impl Parse for String {
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Block {
|
pub struct Block {
|
||||||
pub statements: Vec<Node<Statement>>,
|
pub statements: Vec<Node<Statement>>,
|
||||||
pub meta: Metadata,
|
pub _meta: Metadata,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for Block {
|
impl Parse for Block {
|
||||||
@ -200,7 +200,7 @@ impl Parse for Block {
|
|||||||
|
|
||||||
Ok(Block {
|
Ok(Block {
|
||||||
statements,
|
statements,
|
||||||
meta: Metadata::produce(&mut stream, pre),
|
_meta: Metadata::produce(&mut stream, pre),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -465,12 +465,34 @@ impl Parse for PrimaryExpression {
|
|||||||
Expression::FunctionDefinition(function.kind.params, function.kind.block)
|
Expression::FunctionDefinition(function.kind.params, function.kind.block)
|
||||||
} else if let Some(Token::DecimalValue(value)) = peeked {
|
} else if let Some(Token::DecimalValue(value)) = peeked {
|
||||||
stream.next(); // Consume decimal value
|
stream.next(); // Consume decimal value
|
||||||
Expression::Literal(Literal::Integer(LuaInteger(
|
|
||||||
i64::from_str_radix(&value, 10).unwrap(),
|
let initial_value = i64::from_str_radix(&value, 10).unwrap();
|
||||||
)))
|
|
||||||
|
if stream.peek() == Some(Token::Symbol('.')) {
|
||||||
|
stream.next(); // consume dot
|
||||||
|
if let Some(Token::DecimalValue(decimal_string)) = stream.next() {
|
||||||
|
let decimal_value = u64::from_str_radix(&decimal_string, 10).unwrap();
|
||||||
|
let log10 = decimal_value.ilog10();
|
||||||
|
let decimal_value = decimal_value as f64 / (10u64.pow(log10 + 1) as f64);
|
||||||
|
Expression::Literal(Literal::Float(LuaFloat(
|
||||||
|
initial_value as f64 + decimal_value,
|
||||||
|
)))
|
||||||
|
} else {
|
||||||
|
return Err(stream.expected_err("number"));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Expression::Literal(Literal::Integer(LuaInteger(initial_value)))
|
||||||
|
}
|
||||||
} else if let Some(Token::StringLit(value)) = peeked {
|
} else if let Some(Token::StringLit(value)) = peeked {
|
||||||
stream.next(); // Consume string-literal
|
stream.next(); // Consume string-literal
|
||||||
Expression::Literal(Literal::String(value))
|
Expression::Literal(Literal::String(value))
|
||||||
|
} else if let Some(Token::Keyword(Keyword::True) | Token::Keyword(Keyword::False)) = peeked
|
||||||
|
{
|
||||||
|
let value = Token::Keyword(Keyword::True) == stream.next().unwrap();
|
||||||
|
Expression::Literal(Literal::Bool(value))
|
||||||
|
} else if let Some(Token::Keyword(Keyword::Nil)) = peeked {
|
||||||
|
stream.next(); // Consume nil
|
||||||
|
Expression::Literal(Literal::Nil)
|
||||||
} else if let Some(Token::Symbol('{')) = peeked {
|
} else if let Some(Token::Symbol('{')) = peeked {
|
||||||
stream.next();
|
stream.next();
|
||||||
stream.expect_symbol('}')?;
|
stream.expect_symbol('}')?;
|
||||||
@ -556,4 +578,6 @@ pub enum Literal {
|
|||||||
Float(LuaFloat),
|
Float(LuaFloat),
|
||||||
Integer(LuaInteger),
|
Integer(LuaInteger),
|
||||||
String(String),
|
String(String),
|
||||||
|
Bool(bool),
|
||||||
|
Nil,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,9 +2,10 @@ use std::collections::{HashMap, HashSet};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::{AccessModifier, BinaryOperator, Block, Expression, Literal, Statement, UnaryOperator},
|
ast::{AccessModifier, BinaryOperator, Block, Expression, Literal, Statement, UnaryOperator},
|
||||||
vm::{Constant, Instruction, VMFloat},
|
vm::{Constant, Instruction, LuaBool},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
pub struct State {
|
pub struct State {
|
||||||
pub constants: Vec<Constant>,
|
pub constants: Vec<Constant>,
|
||||||
pub prototypes: Vec<Vec<Instruction>>,
|
pub prototypes: Vec<Vec<Instruction>>,
|
||||||
@ -15,7 +16,7 @@ impl State {
|
|||||||
self.constants
|
self.constants
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.find(|(i, c)| *c == value)
|
.find(|(_, c)| *c == value)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.0 as u32
|
.0 as u32
|
||||||
}
|
}
|
||||||
@ -73,7 +74,11 @@ impl LocalCounter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Block {
|
impl Block {
|
||||||
pub fn find_constants(&self, scope: &mut Scope, constants: Vec<Constant>) -> HashSet<Constant> {
|
pub(crate) fn find_constants(
|
||||||
|
&self,
|
||||||
|
scope: &mut Scope,
|
||||||
|
constants: Vec<Constant>,
|
||||||
|
) -> HashSet<Constant> {
|
||||||
let mut constants = constants.iter().cloned().collect::<HashSet<_>>();
|
let mut constants = constants.iter().cloned().collect::<HashSet<_>>();
|
||||||
|
|
||||||
let mut inner_scope = scope.clone();
|
let mut inner_scope = scope.clone();
|
||||||
@ -85,7 +90,7 @@ impl Block {
|
|||||||
constants
|
constants
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compile(&self, state: &mut State, scope: &mut Scope) -> Vec<Instruction> {
|
pub(crate) fn compile(&self, state: &mut State, scope: &mut Scope) -> Vec<Instruction> {
|
||||||
let mut instructions = Vec::new();
|
let mut instructions = Vec::new();
|
||||||
|
|
||||||
let mut inner_scope = scope.clone();
|
let mut inner_scope = scope.clone();
|
||||||
@ -98,7 +103,7 @@ impl Block {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Statement {
|
impl Statement {
|
||||||
pub fn find_constants(&self, scope: &mut Scope) -> HashSet<Constant> {
|
fn find_constants(&self, scope: &mut Scope) -> HashSet<Constant> {
|
||||||
match self {
|
match self {
|
||||||
Statement::Assignment(access, names, expr_list) => {
|
Statement::Assignment(access, names, expr_list) => {
|
||||||
let mut constants = HashSet::new();
|
let mut constants = HashSet::new();
|
||||||
@ -148,7 +153,7 @@ impl Statement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compile(&self, state: &mut State, scope: &mut Scope) -> Vec<Instruction> {
|
fn compile(&self, state: &mut State, scope: &mut Scope) -> Vec<Instruction> {
|
||||||
let mut instructions = Vec::new();
|
let mut instructions = Vec::new();
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
@ -213,8 +218,7 @@ impl Statement {
|
|||||||
None => {
|
None => {
|
||||||
for (i, (name, indexes)) in names.iter().enumerate() {
|
for (i, (name, indexes)) in names.iter().enumerate() {
|
||||||
if indexes.len() > 0 {
|
if indexes.len() > 0 {
|
||||||
let mut table_reg = if let Some(reg) = scope.locals.get(&name.kind)
|
let table_reg = if let Some(reg) = scope.locals.get(&name.kind) {
|
||||||
{
|
|
||||||
*reg
|
*reg
|
||||||
} else if let Some(upval_reg) = scope.upvalues.get(&name.kind) {
|
} else if let Some(upval_reg) = scope.upvalues.get(&name.kind) {
|
||||||
let local = scope.register_counter.next();
|
let local = scope.register_counter.next();
|
||||||
@ -345,7 +349,7 @@ impl Statement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Expression {
|
impl Expression {
|
||||||
pub fn find_constants(&self, scope: &mut Scope) -> HashSet<Constant> {
|
fn find_constants(&self, scope: &mut Scope) -> HashSet<Constant> {
|
||||||
match self {
|
match self {
|
||||||
Expression::ValueRef(name) => {
|
Expression::ValueRef(name) => {
|
||||||
let mut constants = HashSet::new();
|
let mut constants = HashSet::new();
|
||||||
@ -386,6 +390,16 @@ impl Expression {
|
|||||||
constants.insert(Constant::String(value.clone()));
|
constants.insert(Constant::String(value.clone()));
|
||||||
constants
|
constants
|
||||||
}
|
}
|
||||||
|
Literal::Bool(value) => {
|
||||||
|
let mut constants = HashSet::new();
|
||||||
|
constants.insert(Constant::Bool(LuaBool(*value)));
|
||||||
|
constants
|
||||||
|
}
|
||||||
|
Literal::Nil => {
|
||||||
|
let mut constants = HashSet::new();
|
||||||
|
constants.insert(Constant::Nil);
|
||||||
|
constants
|
||||||
|
}
|
||||||
},
|
},
|
||||||
Expression::TableConstructor => {
|
Expression::TableConstructor => {
|
||||||
let constants = HashSet::new();
|
let constants = HashSet::new();
|
||||||
@ -394,7 +408,7 @@ impl Expression {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compile(
|
fn compile(
|
||||||
&self,
|
&self,
|
||||||
state: &mut State,
|
state: &mut State,
|
||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
@ -474,15 +488,15 @@ impl Expression {
|
|||||||
BinaryOperator::And => {
|
BinaryOperator::And => {
|
||||||
instructions.push(Instruction::And(
|
instructions.push(Instruction::And(
|
||||||
reg,
|
reg,
|
||||||
*rhs.get(0).unwrap(),
|
|
||||||
*lhs.get(0).unwrap(),
|
*lhs.get(0).unwrap(),
|
||||||
|
*rhs.get(0).unwrap(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
BinaryOperator::Or => {
|
BinaryOperator::Or => {
|
||||||
instructions.push(Instruction::Or(
|
instructions.push(Instruction::Or(
|
||||||
reg,
|
reg,
|
||||||
*rhs.get(0).unwrap(),
|
|
||||||
*lhs.get(0).unwrap(),
|
*lhs.get(0).unwrap(),
|
||||||
|
*rhs.get(0).unwrap(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -604,6 +618,8 @@ impl Expression {
|
|||||||
Literal::Float(value) => Constant::Float(value.vm_number()),
|
Literal::Float(value) => Constant::Float(value.vm_number()),
|
||||||
Literal::String(value) => Constant::String(value.clone()),
|
Literal::String(value) => Constant::String(value.clone()),
|
||||||
Literal::Integer(lua_integer) => Constant::Integer(*lua_integer),
|
Literal::Integer(lua_integer) => Constant::Integer(*lua_integer),
|
||||||
|
Literal::Bool(value) => Constant::Bool(LuaBool(*value)),
|
||||||
|
Literal::Nil => Constant::Nil,
|
||||||
}),
|
}),
|
||||||
));
|
));
|
||||||
(instructions, vec![reg])
|
(instructions, vec![reg])
|
||||||
|
|||||||
143
src/lib.rs
Normal file
143
src/lib.rs
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
//! Usage example:
|
||||||
|
//! ```rust
|
||||||
|
//! use ferrite_lua::{compile, vm};
|
||||||
|
//!
|
||||||
|
//! #[derive(Debug, PartialEq, Eq)]
|
||||||
|
//! pub struct Print;
|
||||||
|
//! impl vm::RustFunction for Print {
|
||||||
|
//! fn execute(&self, parameters: Vec<vm::Value>) -> Result<Vec<vm::Value>, vm::RuntimeError> {
|
||||||
|
//! println!("{:?}", parameters);
|
||||||
|
//! Ok(Vec::new())
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! fn as_indexable(&self) -> String {
|
||||||
|
//! "std::print".to_owned()
|
||||||
|
//! }
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! let compilation_unit = compile("print(\"hello\")", None).unwrap();
|
||||||
|
//!
|
||||||
|
//! let mut vm = vm::VirtualMachine::default();
|
||||||
|
//! vm.set_global("print".into(), Print.into());
|
||||||
|
//!
|
||||||
|
//! let mut runner = compilation_unit.with_virtual_machine(&mut vm).execute();
|
||||||
|
//!
|
||||||
|
//! while runner.next().unwrap().is_none() { }
|
||||||
|
//! ```
|
||||||
|
|
||||||
|
use std::{fmt::Debug, path::PathBuf};
|
||||||
|
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
ast::Block,
|
||||||
|
token_stream::{
|
||||||
|
TokenStream, TokenStreamError,
|
||||||
|
lexer::{Error as TokenizerError, Token, tokenize},
|
||||||
|
},
|
||||||
|
vm::{ClosureRunner, VirtualMachine},
|
||||||
|
};
|
||||||
|
|
||||||
|
mod ast;
|
||||||
|
mod compile;
|
||||||
|
mod token_stream;
|
||||||
|
pub mod vm;
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
pub enum CompilationError {
|
||||||
|
#[error(transparent)]
|
||||||
|
TokenStreamError(#[from] TokenStreamError),
|
||||||
|
#[error(transparent)]
|
||||||
|
TokenizationError(#[from] TokenizerError),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct CompilationUnit {
|
||||||
|
pub instructions: Vec<vm::Instruction>,
|
||||||
|
pub state: compile::State,
|
||||||
|
pub constants: Vec<vm::Constant>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for CompilationUnit {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.debug_struct("CompilationUnit")
|
||||||
|
.field("instructions", &self.instructions)
|
||||||
|
.field("state", &self.state)
|
||||||
|
.field("constants", &self.constants)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CompilationUnit {
|
||||||
|
pub fn with_virtual_machine<'a>(&self, vm: &'a mut VirtualMachine) -> ExecutionUnit<'a> {
|
||||||
|
let chunk_id = vm.new_prototype(self.instructions.clone());
|
||||||
|
for prototype in &self.state.prototypes {
|
||||||
|
vm.new_prototype(prototype.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
vm.constants = self.constants.clone();
|
||||||
|
|
||||||
|
ExecutionUnit { chunk_id, vm }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ExecutionUnit<'a> {
|
||||||
|
chunk_id: u32,
|
||||||
|
vm: &'a mut VirtualMachine,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ExecutionUnit<'a> {
|
||||||
|
pub fn execute(self) -> ClosureRunner {
|
||||||
|
let closure = self.vm.create_closure(self.chunk_id);
|
||||||
|
closure.run(Vec::new())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn compile(
|
||||||
|
text: &str,
|
||||||
|
unit: Option<&CompilationUnit>,
|
||||||
|
) -> Result<CompilationUnit, CompilationError> {
|
||||||
|
let file_path = PathBuf::from("../examples/test.lua");
|
||||||
|
let tokens = tokenize(text)?;
|
||||||
|
let mut stream = TokenStream::from(&file_path, &tokens);
|
||||||
|
|
||||||
|
// dbg!(&tokens);
|
||||||
|
|
||||||
|
let chunk = stream.parse::<Block>()?;
|
||||||
|
stream.expect(Token::Eof)?;
|
||||||
|
|
||||||
|
// dbg!(&chunk);
|
||||||
|
|
||||||
|
let constants = chunk
|
||||||
|
.find_constants(
|
||||||
|
&mut Default::default(),
|
||||||
|
if let Some(unit) = unit {
|
||||||
|
unit.constants.clone()
|
||||||
|
} else {
|
||||||
|
Vec::new()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.into_iter()
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let mut state = compile::State {
|
||||||
|
constants: constants.clone(),
|
||||||
|
prototypes: if let Some(unit) = unit {
|
||||||
|
unit.state.prototypes.clone()
|
||||||
|
} else {
|
||||||
|
Vec::new()
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let mut scope = Default::default();
|
||||||
|
let instructions = chunk.compile(&mut state, &mut scope);
|
||||||
|
|
||||||
|
// dbg!(&instructions);
|
||||||
|
|
||||||
|
// dbg!(&constants);
|
||||||
|
|
||||||
|
Ok(CompilationUnit {
|
||||||
|
instructions,
|
||||||
|
state,
|
||||||
|
constants,
|
||||||
|
})
|
||||||
|
}
|
||||||
131
src/main.rs
131
src/main.rs
@ -1,131 +0,0 @@
|
|||||||
use std::{cell::RefCell, path::PathBuf, rc::Rc};
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
ast::{Block, Function},
|
|
||||||
token_stream::{
|
|
||||||
TokenStream,
|
|
||||||
lexer::{Token, tokenize},
|
|
||||||
},
|
|
||||||
vm::{LuaFloat, RuntimeError, RustFunction, VirtualMachine},
|
|
||||||
};
|
|
||||||
|
|
||||||
mod ast;
|
|
||||||
mod compile;
|
|
||||||
mod token_stream;
|
|
||||||
mod vm;
|
|
||||||
|
|
||||||
static TEST: &str = include_str!("../examples/test.lua");
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
|
||||||
pub struct Max;
|
|
||||||
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)? {
|
|
||||||
vm::Value::Integer(value) => Ok(vec![if value.0 > 0 { rhs } else { lhs }]),
|
|
||||||
_ => Ok(vec![vm::Value::Nil]),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn as_indexable(&self) -> String {
|
|
||||||
"std::max".to_owned()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
|
||||||
pub struct Print;
|
|
||||||
impl RustFunction for Print {
|
|
||||||
fn execute(&self, parameters: Vec<vm::Value>) -> Result<Vec<vm::Value>, RuntimeError> {
|
|
||||||
println!("{:?}", parameters);
|
|
||||||
Ok(Vec::new())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn as_indexable(&self) -> String {
|
|
||||||
"std::print".to_owned()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn compile(
|
|
||||||
text: &str,
|
|
||||||
constants: Vec<vm::Constant>,
|
|
||||||
prototypes: Vec<Vec<vm::Instruction>>,
|
|
||||||
) -> (Vec<vm::Instruction>, compile::State, Vec<vm::Constant>) {
|
|
||||||
let file_path = PathBuf::from("../examples/test.lua");
|
|
||||||
let tokens = tokenize(text).unwrap();
|
|
||||||
let mut stream = TokenStream::from(&file_path, &tokens);
|
|
||||||
|
|
||||||
dbg!(&tokens);
|
|
||||||
|
|
||||||
let chunk = stream.parse::<Block>().unwrap();
|
|
||||||
stream.expect(Token::Eof).unwrap();
|
|
||||||
|
|
||||||
dbg!(&chunk);
|
|
||||||
|
|
||||||
let constants = chunk
|
|
||||||
.find_constants(&mut Default::default(), constants)
|
|
||||||
.into_iter()
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let mut state = compile::State {
|
|
||||||
constants: constants.clone(),
|
|
||||||
prototypes,
|
|
||||||
};
|
|
||||||
let mut scope = Default::default();
|
|
||||||
let instructions = chunk.compile(&mut state, &mut scope);
|
|
||||||
|
|
||||||
(instructions, state, constants)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let (instructions, state, constants) = compile(TEST, Vec::new(), Vec::new());
|
|
||||||
|
|
||||||
dbg!(&instructions);
|
|
||||||
|
|
||||||
dbg!(&constants);
|
|
||||||
|
|
||||||
let mut vm = VirtualMachine {
|
|
||||||
environment: Default::default(),
|
|
||||||
constants: constants.clone(),
|
|
||||||
prototypes: Default::default(),
|
|
||||||
proto_counter: 0,
|
|
||||||
};
|
|
||||||
let chunk_id = vm.new_prototype(instructions);
|
|
||||||
for prototype in &state.prototypes {
|
|
||||||
vm.new_prototype(prototype.clone());
|
|
||||||
}
|
|
||||||
dbg!(&vm.prototypes);
|
|
||||||
|
|
||||||
vm.environment.borrow_mut().set_global(
|
|
||||||
vm::Constant::String("max".to_owned()),
|
|
||||||
vm::StackValue::Value(vm::Value::RustFunction(Rc::new(RefCell::new(Max)))),
|
|
||||||
);
|
|
||||||
vm.environment.borrow_mut().set_global(
|
|
||||||
vm::Constant::String("print".to_owned()),
|
|
||||||
vm::StackValue::Value(vm::Value::RustFunction(Rc::new(RefCell::new(Print)))),
|
|
||||||
);
|
|
||||||
|
|
||||||
let closure = vm.create_closure(chunk_id);
|
|
||||||
|
|
||||||
let mut run = closure.run(Vec::new());
|
|
||||||
|
|
||||||
while run.next().unwrap().is_none() {
|
|
||||||
// let (instructions, state, constants) =
|
|
||||||
// compile("print(b)", constants.clone(), state.prototypes.clone());
|
|
||||||
|
|
||||||
// // dbg!(&instructions);
|
|
||||||
|
|
||||||
// let mut new_run = run.execute(instructions, state, constants);
|
|
||||||
// while {
|
|
||||||
// match new_run.next() {
|
|
||||||
// Ok(Some(_)) => false,
|
|
||||||
// Ok(None) => true,
|
|
||||||
// Err(e) => {
|
|
||||||
// print!("Error: {}", e);
|
|
||||||
// false
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// } {}
|
|
||||||
}
|
|
||||||
|
|
||||||
dbg!(&vm.environment.borrow().globals);
|
|
||||||
}
|
|
||||||
@ -16,6 +16,10 @@ pub enum Keyword {
|
|||||||
Return,
|
Return,
|
||||||
If,
|
If,
|
||||||
Then,
|
Then,
|
||||||
|
True,
|
||||||
|
False,
|
||||||
|
Nil,
|
||||||
|
Not,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Keyword {
|
impl Keyword {
|
||||||
@ -28,6 +32,10 @@ impl Keyword {
|
|||||||
"return" => Keyword::Return,
|
"return" => Keyword::Return,
|
||||||
"if" => Keyword::If,
|
"if" => Keyword::If,
|
||||||
"then" => Keyword::Then,
|
"then" => Keyword::Then,
|
||||||
|
"true" => Keyword::True,
|
||||||
|
"false" => Keyword::False,
|
||||||
|
"nil" => Keyword::Nil,
|
||||||
|
"not" => Keyword::Not,
|
||||||
_ => None?,
|
_ => None?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -43,6 +51,10 @@ impl ToString for Keyword {
|
|||||||
Keyword::Return => "return",
|
Keyword::Return => "return",
|
||||||
Keyword::If => "if",
|
Keyword::If => "if",
|
||||||
Keyword::Then => "then",
|
Keyword::Then => "then",
|
||||||
|
Keyword::True => "true",
|
||||||
|
Keyword::False => "false",
|
||||||
|
Keyword::Nil => "nil",
|
||||||
|
Keyword::Not => "not",
|
||||||
}
|
}
|
||||||
.to_string()
|
.to_string()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
//! Contains relevant code for parsing tokens received from
|
//! Contains relevant code for parsing tokens received from
|
||||||
//! Lexing/Tokenizing-stage.
|
//! Lexing/Tokenizing-stage.
|
||||||
|
#![allow(dead_code)]
|
||||||
use std::{cell::RefCell, path::PathBuf, rc::Rc};
|
use std::{cell::RefCell, path::PathBuf, rc::Rc};
|
||||||
|
|
||||||
pub mod lexer;
|
pub mod lexer;
|
||||||
|
|||||||
212
src/vm.rs
212
src/vm.rs
@ -1,16 +1,10 @@
|
|||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
use std::{
|
use std::{cell::RefCell, collections::HashMap, fmt::Debug, hash::Hash, rc::Rc};
|
||||||
cell::{RefCell, RefMut},
|
|
||||||
collections::HashMap,
|
|
||||||
fmt::Debug,
|
|
||||||
hash::Hash,
|
|
||||||
rc::Rc,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
CompilationUnit,
|
||||||
ast::{BinaryOperator, UnaryOperator},
|
ast::{BinaryOperator, UnaryOperator},
|
||||||
compile,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Hash, PartialEq, Eq, Copy)]
|
#[derive(Clone, Hash, PartialEq, Eq, Copy)]
|
||||||
@ -64,19 +58,50 @@ impl From<&LuaInteger> for LuaFloat {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Hash, PartialEq, Eq)]
|
||||||
|
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 {
|
||||||
String(String),
|
String(String),
|
||||||
Float(VMFloat),
|
Float(VMFloat),
|
||||||
Integer(LuaInteger),
|
Integer(LuaInteger),
|
||||||
|
Bool(LuaBool),
|
||||||
|
Nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&str> for Constant {
|
||||||
|
fn from(value: &str) -> Self {
|
||||||
|
Constant::String(value.to_owned())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for Constant {
|
impl Debug for Constant {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Self::String(arg0) => f.debug_tuple("String").field(arg0).finish(),
|
Self::String(arg0) => f.debug_tuple("String").field(arg0).finish(),
|
||||||
Self::Float(arg0) => f.debug_tuple("Number").field(&arg0.lua_number()).finish(),
|
Self::Float(arg0) => f.debug_tuple("Float").field(&arg0.lua_number()).finish(),
|
||||||
Self::Integer(arg0) => f.debug_tuple("Integer").field(arg0).finish(),
|
Self::Integer(arg0) => f.debug_tuple("Integer").field(arg0).finish(),
|
||||||
|
Self::Bool(arg0) => f.debug_tuple("Boolean").field(arg0).finish(),
|
||||||
|
Self::Nil => f.debug_tuple("Nil").finish(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -189,36 +214,30 @@ pub enum RuntimeError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone, Default)]
|
||||||
pub struct Environment {
|
pub(crate) struct Environment {
|
||||||
pub globals: HashMap<Constant, Rc<RefCell<Value>>>,
|
pub globals: HashMap<Constant, Rc<RefCell<Value>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Environment {
|
impl Environment {
|
||||||
pub fn get_global(&mut self, key: &Constant) -> Option<StackValue> {
|
fn get_global(&mut self, key: &Constant) -> Option<StackValue> {
|
||||||
let value = self.globals.get_mut(key)?;
|
let value = self.globals.get_mut(key)?;
|
||||||
Some(match &*value.borrow() {
|
Some(match &*value.borrow() {
|
||||||
_ => StackValue::Value(value.borrow().clone()),
|
_ => StackValue::Value(value.borrow().clone()),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_global(&mut self, key: Constant, value: StackValue) {
|
fn set_global(&mut self, key: Constant, value: StackValue) {
|
||||||
if let Some(existing) = self.globals.get_mut(&key) {
|
if let Some(existing) = self.globals.get_mut(&key) {
|
||||||
match value {
|
match value {
|
||||||
StackValue::Value(value) => {
|
StackValue::Value(value) => {
|
||||||
*existing.borrow_mut() = value;
|
*existing.borrow_mut() = value;
|
||||||
}
|
}
|
||||||
StackValue::Ref(reference) => {
|
|
||||||
*existing = reference;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
match value {
|
match value {
|
||||||
StackValue::Value(value) => {
|
StackValue::Value(value) => {
|
||||||
self.globals.insert(key, Rc::new(RefCell::new(value)));
|
self.globals.insert(key, Rc::new(RefCell::new(value)));
|
||||||
}
|
}
|
||||||
StackValue::Ref(reference) => {
|
|
||||||
self.globals.insert(key, reference);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -229,6 +248,7 @@ pub enum Value {
|
|||||||
String(String),
|
String(String),
|
||||||
Float(VMFloat),
|
Float(VMFloat),
|
||||||
Integer(LuaInteger),
|
Integer(LuaInteger),
|
||||||
|
Boolean(LuaBool),
|
||||||
RustFunction(Rc<RefCell<dyn RustFunction>>),
|
RustFunction(Rc<RefCell<dyn RustFunction>>),
|
||||||
Function(Closure),
|
Function(Closure),
|
||||||
Nil,
|
Nil,
|
||||||
@ -241,6 +261,7 @@ impl Value {
|
|||||||
Value::String(value) => Ok(IndexableValue::String(value)),
|
Value::String(value) => Ok(IndexableValue::String(value)),
|
||||||
Value::Float(value) => Ok(IndexableValue::Number(value)),
|
Value::Float(value) => Ok(IndexableValue::Number(value)),
|
||||||
Value::Integer(value) => Ok(IndexableValue::Integer(value)),
|
Value::Integer(value) => Ok(IndexableValue::Integer(value)),
|
||||||
|
Value::Boolean(value) => Ok(IndexableValue::Bool(value)),
|
||||||
Value::RustFunction(value) => {
|
Value::RustFunction(value) => {
|
||||||
Ok(IndexableValue::RustFunction(value.borrow().as_indexable()))
|
Ok(IndexableValue::RustFunction(value.borrow().as_indexable()))
|
||||||
}
|
}
|
||||||
@ -254,6 +275,15 @@ impl Value {
|
|||||||
match self {
|
match self {
|
||||||
Value::Float(vmfloat) => Ok(vmfloat.lua_number()),
|
Value::Float(vmfloat) => Ok(vmfloat.lua_number()),
|
||||||
Value::Integer(lua_integer) => Ok(lua_integer.into()),
|
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())),
|
_ => Err(RuntimeError::NotFloatable(self.clone())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -264,6 +294,7 @@ pub enum IndexableValue {
|
|||||||
String(String),
|
String(String),
|
||||||
Number(VMFloat),
|
Number(VMFloat),
|
||||||
Integer(LuaInteger),
|
Integer(LuaInteger),
|
||||||
|
Bool(LuaBool),
|
||||||
RustFunction(String),
|
RustFunction(String),
|
||||||
Function(u32),
|
Function(u32),
|
||||||
}
|
}
|
||||||
@ -271,11 +302,14 @@ pub enum IndexableValue {
|
|||||||
impl Value {
|
impl Value {
|
||||||
pub fn add(&self, other: &Value) -> Result<Value, RuntimeError> {
|
pub fn add(&self, other: &Value) -> Result<Value, RuntimeError> {
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(Value::Integer(lhs), Value::Integer(rhs)) => {
|
(Value::Integer(_) | Value::Boolean(_), Value::Integer(_) | Value::Boolean(_)) => {
|
||||||
let res = LuaInteger(lhs.0 + rhs.0);
|
let res = LuaInteger(self.as_integer()?.0 + other.as_integer()?.0);
|
||||||
Ok(Value::Integer(res))
|
Ok(Value::Integer(res))
|
||||||
}
|
}
|
||||||
(Value::Float(_) | Value::Integer(_), Value::Float(_) | Value::Integer(_)) => {
|
(
|
||||||
|
Value::Float(_) | Value::Integer(_) | Value::Boolean(_),
|
||||||
|
Value::Float(_) | Value::Integer(_) | Value::Boolean(_),
|
||||||
|
) => {
|
||||||
let res = LuaFloat(self.as_float()?.0 + other.as_float()?.0);
|
let res = LuaFloat(self.as_float()?.0 + other.as_float()?.0);
|
||||||
Ok(Value::Float(res.vm_number()))
|
Ok(Value::Float(res.vm_number()))
|
||||||
}
|
}
|
||||||
@ -290,12 +324,11 @@ impl Value {
|
|||||||
pub fn eq(&self, other: &Value) -> Result<Value, RuntimeError> {
|
pub fn eq(&self, other: &Value) -> Result<Value, RuntimeError> {
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(Value::Integer(lhs), Value::Integer(rhs)) => {
|
(Value::Integer(lhs), Value::Integer(rhs)) => {
|
||||||
let res = LuaInteger((lhs.0 == rhs.0) as i64);
|
Ok(Value::Boolean(LuaBool(lhs.0 == rhs.0)))
|
||||||
Ok(Value::Integer(res))
|
|
||||||
}
|
}
|
||||||
(Value::Float(_) | Value::Integer(_), Value::Float(_) | Value::Integer(_)) => {
|
(Value::Float(_) | Value::Integer(_), Value::Float(_) | Value::Integer(_)) => {
|
||||||
let res = LuaInteger((self.as_float()?.0 == other.as_float()?.0) as i64);
|
let res = LuaBool(self.as_float()?.0 == other.as_float()?.0);
|
||||||
Ok(Value::Integer(res))
|
Ok(Value::Boolean(res))
|
||||||
}
|
}
|
||||||
_ => Err(RuntimeError::InvalidOperands(
|
_ => Err(RuntimeError::InvalidOperands(
|
||||||
BinaryOperator::Equal,
|
BinaryOperator::Equal,
|
||||||
@ -308,12 +341,11 @@ impl Value {
|
|||||||
pub fn lt(&self, other: &Value) -> Result<Value, RuntimeError> {
|
pub fn lt(&self, other: &Value) -> Result<Value, RuntimeError> {
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(Value::Integer(lhs), Value::Integer(rhs)) => {
|
(Value::Integer(lhs), Value::Integer(rhs)) => {
|
||||||
let res = LuaInteger((lhs.0 < rhs.0) as i64);
|
Ok(Value::Boolean(LuaBool(lhs.0 < rhs.0)))
|
||||||
Ok(Value::Integer(res))
|
|
||||||
}
|
}
|
||||||
(Value::Float(_) | Value::Integer(_), Value::Float(_) | Value::Integer(_)) => {
|
(Value::Float(_) | Value::Integer(_), Value::Float(_) | Value::Integer(_)) => {
|
||||||
let res = LuaInteger((self.as_float()?.0 < other.as_float()?.0) as i64);
|
let res = LuaBool(self.as_float()?.0 < other.as_float()?.0);
|
||||||
Ok(Value::Integer(res))
|
Ok(Value::Boolean(res))
|
||||||
}
|
}
|
||||||
_ => Err(RuntimeError::InvalidOperands(
|
_ => Err(RuntimeError::InvalidOperands(
|
||||||
BinaryOperator::LessThan,
|
BinaryOperator::LessThan,
|
||||||
@ -326,12 +358,11 @@ impl Value {
|
|||||||
pub fn lte(&self, other: &Value) -> Result<Value, RuntimeError> {
|
pub fn lte(&self, other: &Value) -> Result<Value, RuntimeError> {
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(Value::Integer(lhs), Value::Integer(rhs)) => {
|
(Value::Integer(lhs), Value::Integer(rhs)) => {
|
||||||
let res = LuaInteger((lhs.0 <= rhs.0) as i64);
|
Ok(Value::Boolean(LuaBool(lhs.0 <= rhs.0)))
|
||||||
Ok(Value::Integer(res))
|
|
||||||
}
|
}
|
||||||
(Value::Float(_) | Value::Integer(_), Value::Float(_) | Value::Integer(_)) => {
|
(Value::Float(_) | Value::Integer(_), Value::Float(_) | Value::Integer(_)) => {
|
||||||
let res = LuaInteger((self.as_float()?.0 <= other.as_float()?.0) as i64);
|
let res = LuaBool(self.as_float()?.0 <= other.as_float()?.0);
|
||||||
Ok(Value::Integer(res))
|
Ok(Value::Boolean(res))
|
||||||
}
|
}
|
||||||
_ => Err(RuntimeError::InvalidOperands(
|
_ => Err(RuntimeError::InvalidOperands(
|
||||||
BinaryOperator::LessThanOrEqual,
|
BinaryOperator::LessThanOrEqual,
|
||||||
@ -351,6 +382,10 @@ impl Value {
|
|||||||
let res = LuaFloat(-lhs.lua_number().0);
|
let res = LuaFloat(-lhs.lua_number().0);
|
||||||
Ok(Value::Float(res.vm_number()))
|
Ok(Value::Float(res.vm_number()))
|
||||||
}
|
}
|
||||||
|
Value::Boolean(val) => {
|
||||||
|
let res = LuaBool(!val.0);
|
||||||
|
Ok(Value::Boolean(res))
|
||||||
|
}
|
||||||
_ => Err(RuntimeError::InvalidOperand(
|
_ => Err(RuntimeError::InvalidOperand(
|
||||||
UnaryOperator::Negation,
|
UnaryOperator::Negation,
|
||||||
self.clone(),
|
self.clone(),
|
||||||
@ -359,18 +394,10 @@ impl Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn and(&self, other: &Value) -> Result<Value, RuntimeError> {
|
pub fn and(&self, other: &Value) -> Result<Value, RuntimeError> {
|
||||||
match (self, other) {
|
if self.is_truthy() {
|
||||||
(Value::Float(_) | Value::Integer(_), Value::Float(_) | Value::Integer(_)) => Ok(
|
Ok(self.clone())
|
||||||
Value::Integer(LuaInteger((self.is_truthy() && other.is_truthy()) as i64)),
|
} else {
|
||||||
),
|
Ok(other.clone())
|
||||||
(Value::Float(_) | Value::Integer(_), _) => {
|
|
||||||
Ok(Value::Integer(LuaInteger(self.is_truthy() as i64)))
|
|
||||||
}
|
|
||||||
(_, Value::Float(_) | Value::Integer(_)) => {
|
|
||||||
Ok(Value::Integer(LuaInteger(other.is_truthy() as i64)))
|
|
||||||
}
|
|
||||||
(Value::Nil, _) | (_, Value::Nil) => Ok(Value::Nil),
|
|
||||||
_ => Ok(Value::Nil),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -384,13 +411,14 @@ impl Value {
|
|||||||
|
|
||||||
pub fn is_truthy(&self) -> bool {
|
pub fn is_truthy(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Value::String(value) => value.len() > 0,
|
Value::String(_) => true,
|
||||||
Value::Float(vmfloat) => vmfloat.lua_number().0 > 0.,
|
Value::Float(_) => true,
|
||||||
Value::Integer(lua_integer) => lua_integer.0 > 0,
|
Value::Integer(_) => true,
|
||||||
|
Value::Boolean(lua_bool) => lua_bool.0,
|
||||||
Value::RustFunction(_) => true,
|
Value::RustFunction(_) => true,
|
||||||
Value::Function(_) => true,
|
Value::Function(_) => true,
|
||||||
Value::Nil => false,
|
Value::Nil => false,
|
||||||
Value::Table(value) => value.borrow().len() > 0,
|
Value::Table(_) => true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -398,8 +426,9 @@ impl Value {
|
|||||||
impl Debug for Value {
|
impl Debug for Value {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Value::Float(arg0) => f.debug_tuple("Number").field(&arg0.lua_number()).finish(),
|
Value::Float(arg0) => f.debug_tuple("Float").field(&arg0.lua_number()).finish(),
|
||||||
Value::Integer(arg0) => f.debug_tuple("Integer").field(arg0).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::String(value) => f.debug_tuple("String").field(value).finish(),
|
||||||
Value::RustFunction(arg0) => f.debug_tuple("RustFunction").field(arg0).finish(),
|
Value::RustFunction(arg0) => f.debug_tuple("RustFunction").field(arg0).finish(),
|
||||||
Value::Function(closure) => f
|
Value::Function(closure) => f
|
||||||
@ -422,12 +451,18 @@ pub trait RustFunction: Debug {
|
|||||||
fn as_indexable(&self) -> String;
|
fn as_indexable(&self) -> String;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
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 VirtualMachine {
|
pub struct VirtualMachine {
|
||||||
pub environment: Rc<RefCell<Environment>>,
|
pub(super) environment: Rc<RefCell<Environment>>,
|
||||||
pub constants: Vec<Constant>,
|
pub(super) constants: Vec<Constant>,
|
||||||
pub prototypes: HashMap<u32, Vec<Instruction>>,
|
pub(super) prototypes: HashMap<u32, Vec<Instruction>>,
|
||||||
pub proto_counter: u32,
|
pub(super) proto_counter: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VirtualMachine {
|
impl VirtualMachine {
|
||||||
@ -440,7 +475,7 @@ impl VirtualMachine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl VirtualMachine {
|
impl VirtualMachine {
|
||||||
pub fn create_closure(&self, prototype: u32) -> Closure {
|
pub(crate) fn create_closure(&self, prototype: u32) -> Closure {
|
||||||
Closure {
|
Closure {
|
||||||
vm: self.clone(),
|
vm: self.clone(),
|
||||||
prototype,
|
prototype,
|
||||||
@ -448,14 +483,29 @@ impl VirtualMachine {
|
|||||||
upvalues: HashMap::new(),
|
upvalues: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_global(&mut self, key: Constant, value: Value) {
|
||||||
|
self.environment
|
||||||
|
.borrow_mut()
|
||||||
|
.set_global(key, StackValue::Value(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_globals(&self) -> HashMap<Constant, Value> {
|
||||||
|
let mut values = HashMap::new();
|
||||||
|
for (key, value) in &self.environment.borrow().globals {
|
||||||
|
values.insert(key.clone(), value.borrow().clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
values
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Closure {
|
pub struct Closure {
|
||||||
pub vm: VirtualMachine,
|
vm: VirtualMachine,
|
||||||
pub prototype: u32,
|
prototype: u32,
|
||||||
pub environment: Rc<RefCell<Environment>>,
|
environment: Rc<RefCell<Environment>>,
|
||||||
pub upvalues: HashMap<u16, Rc<RefCell<Value>>>,
|
upvalues: HashMap<u16, Rc<RefCell<Value>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Closure {
|
impl Closure {
|
||||||
@ -488,43 +538,38 @@ impl Closure {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct ClosureRunner {
|
pub struct ClosureRunner {
|
||||||
pub closure: Closure,
|
closure: Closure,
|
||||||
pub program_counter: usize,
|
program_counter: usize,
|
||||||
pub stack: HashMap<u16, Rc<RefCell<Value>>>,
|
stack: HashMap<u16, Rc<RefCell<Value>>>,
|
||||||
pub inner: Option<Box<ClosureRunner>>,
|
inner: Option<Box<ClosureRunner>>,
|
||||||
pub function_register: u16,
|
function_register: u16,
|
||||||
pub return_registers: Vec<u16>,
|
return_registers: Vec<u16>,
|
||||||
pub top: u16,
|
top: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum StackValue {
|
enum StackValue {
|
||||||
Value(Value),
|
Value(Value),
|
||||||
Ref(Rc<RefCell<Value>>),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ClosureRunner {
|
impl ClosureRunner {
|
||||||
pub fn set_stack(&mut self, idx: u16, value: StackValue) {
|
fn set_stack(&mut self, idx: u16, value: StackValue) {
|
||||||
if let Some(stack_slot) = self.stack.get_mut(&idx) {
|
if let Some(stack_slot) = self.stack.get_mut(&idx) {
|
||||||
match value {
|
match value {
|
||||||
StackValue::Value(value) => {
|
StackValue::Value(value) => {
|
||||||
*stack_slot.borrow_mut() = value;
|
*stack_slot.borrow_mut() = value;
|
||||||
}
|
}
|
||||||
StackValue::Ref(ref_cell) => *stack_slot = ref_cell,
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
match value {
|
match value {
|
||||||
StackValue::Value(value) => {
|
StackValue::Value(value) => {
|
||||||
self.stack.insert(idx, Rc::new(RefCell::new(value)));
|
self.stack.insert(idx, Rc::new(RefCell::new(value)));
|
||||||
}
|
}
|
||||||
StackValue::Ref(reference) => {
|
|
||||||
self.stack.insert(idx, reference);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_stack(&mut self, idx: u16) -> StackValue {
|
fn get_stack(&mut self, idx: u16) -> StackValue {
|
||||||
let value = self.stack.get(&idx);
|
let value = self.stack.get(&idx);
|
||||||
if let Some(value) = value {
|
if let Some(value) = value {
|
||||||
match &*value.borrow() {
|
match &*value.borrow() {
|
||||||
@ -551,17 +596,12 @@ impl ClosureRunner {
|
|||||||
upvalues
|
upvalues
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn execute(
|
pub fn execute(&mut self, unit: &CompilationUnit) -> ClosureRunner {
|
||||||
&mut self,
|
|
||||||
instructions: Vec<Instruction>,
|
|
||||||
state: compile::State,
|
|
||||||
constants: Vec<Constant>,
|
|
||||||
) -> ClosureRunner {
|
|
||||||
let mut vm = self.closure.vm.clone();
|
let mut vm = self.closure.vm.clone();
|
||||||
vm.constants = constants;
|
vm.constants = unit.constants.clone();
|
||||||
let proto_id = vm.new_prototype(instructions);
|
let proto_id = vm.new_prototype(unit.instructions.clone());
|
||||||
for prototype in state.prototypes {
|
for prototype in &unit.state.prototypes {
|
||||||
vm.new_prototype(prototype);
|
vm.new_prototype(prototype.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
let closure = Closure {
|
let closure = Closure {
|
||||||
@ -626,6 +666,8 @@ impl ClosureRunner {
|
|||||||
Constant::String(value) => Value::String(value.clone()),
|
Constant::String(value) => Value::String(value.clone()),
|
||||||
Constant::Float(value) => Value::Float(*value),
|
Constant::Float(value) => Value::Float(*value),
|
||||||
Constant::Integer(value) => Value::Integer(*value),
|
Constant::Integer(value) => Value::Integer(*value),
|
||||||
|
Constant::Bool(lua_bool) => Value::Boolean(*lua_bool),
|
||||||
|
Constant::Nil => Value::Nil,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user