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
|
||||
|
||||
global sometable = {}
|
||||
sometable["hello"] = "there"
|
||||
|
||||
print(max(11, 9))
|
||||
print(add(10)(15))
|
||||
|
||||
77
src/ast.rs
77
src/ast.rs
@ -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,8 +479,9 @@ impl Parse for PrimaryExpression {
|
||||
Expression::ValueRef(stream.parse()?)
|
||||
};
|
||||
|
||||
while let Some(Token::Symbol('(')) = stream.peek() {
|
||||
stream.next();
|
||||
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(
|
||||
@ -445,6 +492,10 @@ impl Parse for PrimaryExpression {
|
||||
expression_list,
|
||||
);
|
||||
}
|
||||
Token::Symbol('[') => todo!(),
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
|
||||
for unop in unary_operators.into_iter().rev() {
|
||||
expression = Expression::UnOp(
|
||||
|
||||
@ -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,7 +211,35 @@ impl Statement {
|
||||
}
|
||||
}
|
||||
None => {
|
||||
for (i, name) in names.iter().enumerate() {
|
||||
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 {
|
||||
if let Some(reg) = scope.locals.get(&name.kind) {
|
||||
instructions.push(Instruction::Move(
|
||||
*reg,
|
||||
@ -219,6 +262,7 @@ impl Statement {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Statement::Return(expr_list) => {
|
||||
let mut ret_registers = Vec::new();
|
||||
for expr in &expr_list.0 {
|
||||
|
||||
@ -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)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user