Add broken table assignment

This commit is contained in:
Sofia 2026-03-17 19:14:11 +02:00
parent 83bccbbf4d
commit 7e5aaf56f1
5 changed files with 185 additions and 44 deletions

45
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,45 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "lldb",
"request": "launch",
"name": "Debug executable 'ferrite-lua'",
"cargo": {
"args": [
"build",
"--bin=ferrite-lua",
"--package=ferrite-lua"
],
"filter": {
"name": "ferrite-lua",
"kind": "bin"
}
},
"args": [],
"cwd": "${workspaceFolder}"
},
{
"type": "lldb",
"request": "launch",
"name": "Debug unit tests in executable 'ferrite-lua'",
"cargo": {
"args": [
"test",
"--no-run",
"--bin=ferrite-lua",
"--package=ferrite-lua"
],
"filter": {
"name": "ferrite-lua",
"kind": "bin"
}
},
"args": [],
"cwd": "${workspaceFolder}"
}
]
}

View File

@ -17,6 +17,7 @@ function min(x, y)
end end
global sometable = {} global sometable = {}
sometable["hello"] = "there"
print(max(11, 9)) print(max(11, 9))
print(add(10)(15)) print(add(10)(15))

View File

@ -206,7 +206,11 @@ impl Parse for Block {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Statement { pub enum Statement {
Assignment(Option<AccessModifier>, Vec<Node<String>>, ExpressionList), Assignment(
Option<AccessModifier>,
Vec<(Node<String>, Vec<Node<Expression>>)>,
ExpressionList,
),
Return(ExpressionList), Return(ExpressionList),
If(Node<Expression>, Block), If(Node<Expression>, Block),
Expression(Node<Expression>), Expression(Node<Expression>),
@ -220,7 +224,7 @@ impl Parse for Statement {
if let Some(name) = function.kind.name { if let Some(name) = function.kind.name {
Ok(Self::Assignment( Ok(Self::Assignment(
None, None,
vec![name], vec![(name, Vec::new())],
ExpressionList(vec![Node { ExpressionList(vec![Node {
kind: Expression::FunctionDefinition( kind: Expression::FunctionDefinition(
function.kind.params, function.kind.params,
@ -252,23 +256,23 @@ impl Parse for Statement {
_ => panic!(), _ => panic!(),
}; };
let mut names = Vec::new(); let mut names = Vec::new();
names.push(stream.parse()?); names.push((stream.parse()?, Vec::new()));
while stream.peek() == Some(Token::Symbol(',')) { while stream.peek() == Some(Token::Symbol(',')) {
stream.next(); stream.next();
names.push(stream.parse()?); names.push((stream.parse()?, Vec::new()));
} }
stream.expect(Token::Symbol('='))?; stream.expect(Token::Symbol('='))?;
let expr = stream.parse()?; let expr = stream.parse()?;
Ok(Statement::Assignment(Some(access_modifier), names, expr)) Ok(Statement::Assignment(Some(access_modifier), names, expr))
} else if let Some(Token::Word(_)) = peeked } else if stream.parse_peek::<IndexedAssignment>().is_ok() {
&& stream.peek2() == Some(Token::Symbol('=')) let access = stream.parse::<IndexedAssignment>().unwrap();
{
let name = stream.parse()?; let expression = stream.parse()?;
stream.expect(Token::Symbol('='))?;
Ok(Self::Assignment( Ok(Self::Assignment(
None, None,
vec![name], vec![(access.0.0, access.0.1)],
ExpressionList(vec![stream.parse()?]), ExpressionList(vec![expression]),
)) ))
} else if let Ok(expr) = stream.parse() { } else if let Ok(expr) = stream.parse() {
Ok(Self::Expression(expr)) Ok(Self::Expression(expr))
@ -284,6 +288,48 @@ pub enum AccessModifier {
Global, Global,
} }
#[derive(Debug, Clone)]
pub struct IndexedAccess(Node<String>, Vec<Node<Expression>>);
impl Parse for IndexedAccess {
fn parse(mut stream: TokenStream) -> Result<Self, TokenStreamError> {
let name = stream.parse()?;
let mut expressions = Vec::new();
while let Some(Token::Symbol('[') | Token::Symbol('.')) = stream.peek() {
match stream.next().unwrap() {
Token::Symbol('[') => {
let expression = stream.parse()?;
stream.expect_symbol(']')?;
expressions.push(expression);
}
Token::Symbol('.') => {
let word = stream.parse::<Node<String>>()?;
stream.expect_symbol(']')?;
expressions.push(Node {
kind: Expression::Literal(Literal::String(word.kind)),
meta: word.meta,
});
}
_ => panic!(),
}
}
Ok(IndexedAccess(name, expressions))
}
}
#[derive(Debug, Clone)]
pub struct IndexedAssignment(IndexedAccess);
impl Parse for IndexedAssignment {
fn parse(mut stream: TokenStream) -> Result<Self, TokenStreamError> {
let access = stream.parse()?;
stream.expect_symbol('=')?;
Ok(IndexedAssignment(access))
}
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Expression { pub enum Expression {
ValueRef(String), ValueRef(String),
@ -433,17 +479,22 @@ impl Parse for PrimaryExpression {
Expression::ValueRef(stream.parse()?) Expression::ValueRef(stream.parse()?)
}; };
while let Some(Token::Symbol('(')) = stream.peek() { while let Some(Token::Symbol('(') | Token::Symbol('[')) = stream.peek() {
stream.next(); match stream.next().unwrap() {
let expression_list = stream.parse::<Node<ExpressionList>>()?; Token::Symbol('(') => {
stream.expect(Token::Symbol(')'))?; let expression_list = stream.parse::<Node<ExpressionList>>()?;
expression = Expression::FunctionCall( stream.expect(Token::Symbol(')'))?;
Box::new(Node { expression = Expression::FunctionCall(
kind: expression, Box::new(Node {
meta: Metadata::produce(&mut stream, pre.clone()), kind: expression,
}), meta: Metadata::produce(&mut stream, pre.clone()),
expression_list, }),
); expression_list,
);
}
Token::Symbol('[') => todo!(),
_ => panic!(),
}
} }
for unop in unary_operators.into_iter().rev() { for unop in unary_operators.into_iter().rev() {

View File

@ -103,18 +103,27 @@ impl Statement {
Statement::Assignment(access, names, expr_list) => { Statement::Assignment(access, names, expr_list) => {
let mut constants = HashSet::new(); let mut constants = HashSet::new();
if *access == Some(AccessModifier::Global) { if *access == Some(AccessModifier::Global) {
for name in names { for (name, indexes) in names {
constants.insert(Constant::String(name.kind.clone())); constants.insert(Constant::String(name.kind.clone()));
for index in indexes {
constants.extend(index.kind.find_constants(scope));
}
} }
} else if *access == None { } else if *access == None {
for name in names { for (name, indexes) in names {
if !scope.locals.contains_key(&name.kind) { if !scope.locals.contains_key(&name.kind) {
constants.insert(Constant::String(name.kind.clone())); constants.insert(Constant::String(name.kind.clone()));
} }
for index in indexes {
constants.extend(index.kind.find_constants(scope));
}
} }
} else { } else {
for name in names { for (name, indexes) in names {
scope.locals.insert(name.kind.clone(), 0); scope.locals.insert(name.kind.clone(), 0);
for index in indexes {
constants.extend(index.kind.find_constants(scope));
}
} }
} }
for expr in &expr_list.0 { for expr in &expr_list.0 {
@ -176,18 +185,24 @@ impl Statement {
match access_modifier { match access_modifier {
Some(AccessModifier::Local) => { Some(AccessModifier::Local) => {
for (i, name) in names.iter().enumerate() { for (i, (name, indexes)) in names.iter().enumerate() {
instructions.push(Instruction::Move( instructions.push(Instruction::Move(
*new_registers.get(i).unwrap(), *new_registers.get(i).unwrap(),
expr_regs.get(i).cloned().unwrap(), expr_regs.get(i).cloned().unwrap(),
)); ));
if indexes.len() > 0 {
todo!()
}
scope scope
.locals .locals
.insert(name.kind.clone(), *new_registers.get(i).unwrap()); .insert(name.kind.clone(), *new_registers.get(i).unwrap());
} }
} }
Some(AccessModifier::Global) => { Some(AccessModifier::Global) => {
for (i, name) in names.iter().enumerate() { for (i, (name, indexes)) in names.iter().enumerate() {
if indexes.len() > 0 {
todo!()
}
let global = state.get_constant(&Constant::String(name.kind.clone())); let global = state.get_constant(&Constant::String(name.kind.clone()));
instructions.push(Instruction::SetGlobal( instructions.push(Instruction::SetGlobal(
expr_regs.get(i).cloned().unwrap(), expr_regs.get(i).cloned().unwrap(),
@ -196,24 +211,53 @@ impl Statement {
} }
} }
None => { None => {
for (i, name) in names.iter().enumerate() { for (i, (name, indexes)) in names.iter().enumerate() {
if let Some(reg) = scope.locals.get(&name.kind) { if indexes.len() > 0 {
instructions.push(Instruction::Move( let table_reg = if let Some(reg) = scope.locals.get(&name.kind) {
*reg, *reg
expr_regs.get(i).cloned().unwrap(), } else if let Some(upval_reg) = scope.upvalues.get(&name.kind) {
)); let local = scope.register_counter.next();
} else if let Some(upval_reg) = scope.upvalues.get(&name.kind) { instructions.push(Instruction::GetUpVal(local, *upval_reg));
instructions.push(Instruction::SetUpVal( local
*upval_reg, } else {
let global =
state.get_constant(&Constant::String(name.kind.clone()));
let local = scope.register_counter.next();
instructions.push(Instruction::GetGlobal(local, global));
local
};
if indexes.len() > 1 {
todo!()
}
let (instr, index_reg) =
indexes.last().unwrap().kind.compile(state, scope, Some(1));
instructions.extend(instr);
instructions.push(Instruction::SetTable(
table_reg,
*index_reg.first().unwrap(),
expr_regs.get(i).cloned().unwrap(), expr_regs.get(i).cloned().unwrap(),
)); ));
} else { } else {
let global = if let Some(reg) = scope.locals.get(&name.kind) {
state.get_constant(&Constant::String(name.kind.clone())); instructions.push(Instruction::Move(
instructions.push(Instruction::SetGlobal( *reg,
expr_regs.get(i).cloned().unwrap(), expr_regs.get(i).cloned().unwrap(),
global, ));
)); } else if let Some(upval_reg) = scope.upvalues.get(&name.kind) {
instructions.push(Instruction::SetUpVal(
*upval_reg,
expr_regs.get(i).cloned().unwrap(),
));
} else {
let global =
state.get_constant(&Constant::String(name.kind.clone()));
instructions.push(Instruction::SetGlobal(
expr_regs.get(i).cloned().unwrap(),
global,
));
}
} }
} }
} }

View File

@ -57,12 +57,12 @@ fn compile(
let tokens = tokenize(text).unwrap(); let tokens = tokenize(text).unwrap();
let mut stream = TokenStream::from(&file_path, &tokens); let mut stream = TokenStream::from(&file_path, &tokens);
// dbg!(&tokens); dbg!(&tokens);
let chunk = stream.parse::<Block>().unwrap(); let chunk = stream.parse::<Block>().unwrap();
stream.expect(Token::Eof).unwrap(); stream.expect(Token::Eof).unwrap();
// dbg!(&chunk); dbg!(&chunk);
let constants = chunk let constants = chunk
.find_constants(&mut Default::default(), constants) .find_constants(&mut Default::default(), constants)