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
global sometable = {}
sometable["hello"] = "there"
print(max(11, 9))
print(add(10)(15))

View File

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

View File

@ -103,18 +103,27 @@ impl Statement {
Statement::Assignment(access, names, expr_list) => {
let mut constants = HashSet::new();
if *access == Some(AccessModifier::Global) {
for name in names {
for (name, indexes) in names {
constants.insert(Constant::String(name.kind.clone()));
for index in indexes {
constants.extend(index.kind.find_constants(scope));
}
}
} else if *access == None {
for name in names {
for (name, indexes) in names {
if !scope.locals.contains_key(&name.kind) {
constants.insert(Constant::String(name.kind.clone()));
}
for index in indexes {
constants.extend(index.kind.find_constants(scope));
}
}
} else {
for name in names {
for (name, indexes) in names {
scope.locals.insert(name.kind.clone(), 0);
for index in indexes {
constants.extend(index.kind.find_constants(scope));
}
}
}
for expr in &expr_list.0 {
@ -176,18 +185,24 @@ impl Statement {
match access_modifier {
Some(AccessModifier::Local) => {
for (i, name) in names.iter().enumerate() {
for (i, (name, indexes)) in names.iter().enumerate() {
instructions.push(Instruction::Move(
*new_registers.get(i).unwrap(),
expr_regs.get(i).cloned().unwrap(),
));
if indexes.len() > 0 {
todo!()
}
scope
.locals
.insert(name.kind.clone(), *new_registers.get(i).unwrap());
}
}
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()));
instructions.push(Instruction::SetGlobal(
expr_regs.get(i).cloned().unwrap(),
@ -196,24 +211,53 @@ impl Statement {
}
}
None => {
for (i, name) in names.iter().enumerate() {
if let Some(reg) = scope.locals.get(&name.kind) {
instructions.push(Instruction::Move(
*reg,
expr_regs.get(i).cloned().unwrap(),
));
} else if let Some(upval_reg) = scope.upvalues.get(&name.kind) {
instructions.push(Instruction::SetUpVal(
*upval_reg,
for (i, (name, indexes)) in names.iter().enumerate() {
if indexes.len() > 0 {
let table_reg = if let Some(reg) = scope.locals.get(&name.kind) {
*reg
} else if let Some(upval_reg) = scope.upvalues.get(&name.kind) {
let local = scope.register_counter.next();
instructions.push(Instruction::GetUpVal(local, *upval_reg));
local
} 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(),
));
} else {
let global =
state.get_constant(&Constant::String(name.kind.clone()));
instructions.push(Instruction::SetGlobal(
expr_regs.get(i).cloned().unwrap(),
global,
));
if let Some(reg) = scope.locals.get(&name.kind) {
instructions.push(Instruction::Move(
*reg,
expr_regs.get(i).cloned().unwrap(),
));
} 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 mut stream = TokenStream::from(&file_path, &tokens);
// dbg!(&tokens);
dbg!(&tokens);
let chunk = stream.parse::<Block>().unwrap();
stream.expect(Token::Eof).unwrap();
// dbg!(&chunk);
dbg!(&chunk);
let constants = chunk
.find_constants(&mut Default::default(), constants)