Implement constructors with one function call inside
This commit is contained in:
parent
4ecf6ed3eb
commit
9e9106991e
@ -16,8 +16,12 @@ function min(x, y)
|
||||
return m
|
||||
end
|
||||
|
||||
function f(x)
|
||||
return x + 5
|
||||
end
|
||||
|
||||
global sometable = {}
|
||||
sometable["hello"] = {}
|
||||
sometable["hello"] = { add(10)(15) }
|
||||
sometable["hello"].there = "my dude"
|
||||
print(sometable.hello.there)
|
||||
|
||||
|
||||
48
src/ast.rs
48
src/ast.rs
@ -337,7 +337,7 @@ pub enum Expression {
|
||||
FunctionDefinition(Vec<Node<String>>, Block),
|
||||
FunctionCall(Box<Node<Expression>>, Node<ExpressionList>),
|
||||
Literal(Literal),
|
||||
TableConstructor,
|
||||
TableConstructor(Vec<(Option<Node<Expression>>, Node<Expression>)>),
|
||||
IndexedAccess(Box<Node<Expression>>, Box<Node<Expression>>),
|
||||
}
|
||||
|
||||
@ -495,8 +495,19 @@ impl Parse for PrimaryExpression {
|
||||
Expression::Literal(Literal::Nil)
|
||||
} else if let Some(Token::Symbol('{')) = peeked {
|
||||
stream.next();
|
||||
|
||||
let mut entries = Vec::new();
|
||||
if let Ok(entry) = stream.parse::<TableConstructorEntry>() {
|
||||
entries.push((entry.0, entry.1));
|
||||
while let Some(Token::Symbol(',') | Token::Symbol(';')) = stream.peek() {
|
||||
stream.next();
|
||||
let entry = stream.parse::<TableConstructorEntry>()?;
|
||||
entries.push((entry.0, entry.1))
|
||||
}
|
||||
}
|
||||
|
||||
stream.expect_symbol('}')?;
|
||||
Expression::TableConstructor
|
||||
Expression::TableConstructor(entries)
|
||||
} else {
|
||||
Expression::ValueRef(stream.parse()?)
|
||||
};
|
||||
@ -588,6 +599,39 @@ fn parse_binop_rhs(
|
||||
Ok(lhs.0)
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct TableConstructorEntry(Option<Node<Expression>>, Node<Expression>);
|
||||
|
||||
impl Parse for TableConstructorEntry {
|
||||
fn parse(mut stream: TokenStream) -> Result<Self, TokenStreamError> {
|
||||
if let Some(Token::Symbol('[')) = stream.peek() {
|
||||
stream.next();
|
||||
let key = stream.parse()?;
|
||||
stream.expect_symbol(']')?;
|
||||
stream.expect_symbol('=')?;
|
||||
let value = stream.parse()?;
|
||||
Ok(TableConstructorEntry(Some(key), value))
|
||||
} else {
|
||||
if let (Some(Token::Word(_)), Some(Token::Symbol('='))) =
|
||||
(stream.peek(), stream.peek2())
|
||||
{
|
||||
let key = stream.parse::<Node<String>>()?;
|
||||
let key = key.with(Expression::Literal(Literal::String(key.kind.clone())));
|
||||
if let Some(Token::Symbol('=')) = stream.peek() {
|
||||
stream.next();
|
||||
let value = stream.parse()?;
|
||||
Ok(TableConstructorEntry(Some(key), value))
|
||||
} else {
|
||||
Ok(TableConstructorEntry(None, key))
|
||||
}
|
||||
} else {
|
||||
let value = stream.parse()?;
|
||||
Ok(TableConstructorEntry(None, value))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Literal {
|
||||
Float(LuaFloat),
|
||||
|
||||
@ -2,7 +2,7 @@ use std::collections::{HashMap, HashSet};
|
||||
|
||||
use crate::{
|
||||
ast::{AccessModifier, BinaryOperator, Block, Expression, Literal, Statement, UnaryOperator},
|
||||
vm::{Constant, Instruction, LuaBool},
|
||||
vm::{Constant, Instruction, LuaBool, LuaInteger},
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
@ -401,8 +401,18 @@ impl Expression {
|
||||
constants
|
||||
}
|
||||
},
|
||||
Expression::TableConstructor => {
|
||||
let constants = HashSet::new();
|
||||
Expression::TableConstructor(entries) => {
|
||||
let mut constants = HashSet::new();
|
||||
let mut counter = 1;
|
||||
for (key, value) in entries {
|
||||
if let Some(key) = key {
|
||||
constants.extend(key.kind.find_constants(scope));
|
||||
} else {
|
||||
constants.insert(Constant::Integer(LuaInteger(counter)));
|
||||
counter += 1;
|
||||
}
|
||||
constants.extend(value.kind.find_constants(scope));
|
||||
}
|
||||
constants
|
||||
}
|
||||
Expression::IndexedAccess(expr, index) => {
|
||||
@ -630,10 +640,49 @@ impl Expression {
|
||||
));
|
||||
(instructions, vec![reg])
|
||||
}
|
||||
Expression::TableConstructor => {
|
||||
Expression::TableConstructor(entries) => {
|
||||
let mut instructions = Vec::new();
|
||||
let reg = scope.register_counter.next();
|
||||
instructions.push(Instruction::NewTable(reg));
|
||||
|
||||
let mut counter = 1;
|
||||
for (key, value) in entries {
|
||||
if let Some(key) = key {
|
||||
let (instr, key_regs) = key.kind.compile(state, scope, Some(1));
|
||||
instructions.extend(instr);
|
||||
let (instr, value_regs) = value.kind.compile(state, scope, Some(1));
|
||||
instructions.extend(instr);
|
||||
instructions.push(Instruction::SetTable(
|
||||
reg,
|
||||
*key_regs.first().unwrap(),
|
||||
*value_regs.first().unwrap(),
|
||||
));
|
||||
} else {
|
||||
let (instr, value_regs) = value.kind.compile(
|
||||
state,
|
||||
scope,
|
||||
if entries.len() == 1 { None } else { Some(1) },
|
||||
);
|
||||
instructions.extend(instr);
|
||||
|
||||
if value_regs.len() > 0 {
|
||||
let key_reg = scope.register_counter.next();
|
||||
instructions.push(Instruction::LoadK(
|
||||
key_reg,
|
||||
state.get_constant(&Constant::Integer(LuaInteger(counter))),
|
||||
));
|
||||
instructions.push(Instruction::SetTable(
|
||||
reg,
|
||||
key_reg,
|
||||
*value_regs.first().unwrap(),
|
||||
));
|
||||
counter += 1;
|
||||
} else {
|
||||
instructions.push(Instruction::SetList(reg));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(instructions, vec![reg])
|
||||
}
|
||||
Expression::IndexedAccess(expr, index) => {
|
||||
|
||||
31
src/vm.rs
31
src/vm.rs
@ -124,6 +124,8 @@ pub enum Instruction {
|
||||
SetUpVal(u16, u16),
|
||||
/// R(A)[R(B)] := R(C)
|
||||
SetTable(u16, u16, u16),
|
||||
/// R(A) := all values returned from previous function
|
||||
SetList(u16),
|
||||
/// R(A) := R(B)[R(C)]
|
||||
GetTable(u16, u16, u16),
|
||||
/// R(A) := {}
|
||||
@ -172,6 +174,7 @@ impl Debug for Instruction {
|
||||
Instruction::GetTable(arg0, arg1, arg2) => {
|
||||
write!(f, "GETTABLE {} {} {}", arg0, arg1, arg2)
|
||||
}
|
||||
Instruction::SetList(arg0) => write!(f, "SETLIST {}", arg0),
|
||||
Instruction::NewTable(arg0) => write!(f, "NEWTABLE {}", arg0),
|
||||
Instruction::Jmp(arg0) => write!(f, "JMP {}", arg0),
|
||||
Instruction::Test(arg0, arg1, arg2) => write!(f, "TEST {} {} {}", arg0, arg1, arg2),
|
||||
@ -259,7 +262,7 @@ impl Value {
|
||||
pub fn as_indexable(self) -> Result<IndexableValue, RuntimeError> {
|
||||
match self {
|
||||
Value::String(value) => Ok(IndexableValue::String(value)),
|
||||
Value::Float(value) => Ok(IndexableValue::Number(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) => {
|
||||
@ -292,7 +295,7 @@ impl Value {
|
||||
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
|
||||
pub enum IndexableValue {
|
||||
String(String),
|
||||
Number(VMFloat),
|
||||
Float(VMFloat),
|
||||
Integer(LuaInteger),
|
||||
Bool(LuaBool),
|
||||
RustFunction(String),
|
||||
@ -768,6 +771,30 @@ impl ClosureRunner {
|
||||
|
||||
self.set_stack(*res, value);
|
||||
}
|
||||
Instruction::SetList(reg) => {
|
||||
let table = self.stack.get(reg).cloned();
|
||||
match table {
|
||||
Some(value) => {
|
||||
let mut table = value.borrow_mut();
|
||||
if let Value::Table(table) = &mut *table {
|
||||
let mut counter = 1;
|
||||
for i in self.function_register..self.top {
|
||||
let value = self.get_stack(i + 1);
|
||||
match value {
|
||||
StackValue::Value(value) => table.borrow_mut().insert(
|
||||
IndexableValue::Integer(LuaInteger(counter)),
|
||||
value.clone(),
|
||||
),
|
||||
};
|
||||
counter += 1;
|
||||
}
|
||||
} else {
|
||||
return Err(RuntimeError::NotTable(table.clone()));
|
||||
}
|
||||
}
|
||||
None => todo!(),
|
||||
}
|
||||
}
|
||||
Instruction::NewTable(reg) => {
|
||||
self.set_stack(
|
||||
*reg,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user