Add broken table assignment
This commit is contained in:
parent
83bccbbf4d
commit
7e5aaf56f1
45
.vscode/launch.json
vendored
Normal file
45
.vscode/launch.json
vendored
Normal 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}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -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))
|
||||||
|
|||||||
95
src/ast.rs
95
src/ast.rs
@ -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() {
|
||||||
|
|||||||
@ -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,
|
||||||
|
));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user