Add lists

This commit is contained in:
Jeff 2024-09-17 19:35:33 -04:00
parent 6ca96bc1dc
commit f02c3d1fb5
3 changed files with 131 additions and 40 deletions

View File

@ -32,6 +32,15 @@ impl Instruction {
instruction instruction
} }
pub fn load_list(to_register: u8, list_length: u8) -> Instruction {
let mut instruction = Instruction(Operation::LoadList as u32);
instruction.set_destination(to_register);
instruction.set_first_argument(list_length);
instruction
}
pub fn declare_local(to_register: u8, variable_index: u8) -> Instruction { pub fn declare_local(to_register: u8, variable_index: u8) -> Instruction {
let mut instruction = Instruction(Operation::DeclareLocal as u32); let mut instruction = Instruction(Operation::DeclareLocal as u32);
@ -244,6 +253,16 @@ impl Instruction {
format!("R({}) = C({})", self.destination(), constant_index) format!("R({}) = C({})", self.destination(), constant_index)
} }
} }
Operation::LoadList => {
let destination = self.destination();
let first_index = destination - self.first_argument();
let last_index = destination - 1;
format!(
"R({}) = [R({})..R({})]",
destination, first_index, last_index
)
}
Operation::DeclareLocal => { Operation::DeclareLocal => {
let local_index = self.first_argument(); let local_index = self.first_argument();
let identifier_display = if let Some(chunk) = chunk { let identifier_display = if let Some(chunk) = chunk {
@ -430,19 +449,20 @@ impl Display for Instruction {
const MOVE: u8 = 0b0000_0000; const MOVE: u8 = 0b0000_0000;
const CLOSE: u8 = 0b000_0001; const CLOSE: u8 = 0b000_0001;
const LOAD_CONSTANT: u8 = 0b0000_0010; const LOAD_CONSTANT: u8 = 0b0000_0010;
const DECLARE_LOCAL: u8 = 0b0000_0011; const LOAD_LIST: u8 = 0b0000_0011;
const GET_LOCAL: u8 = 0b0000_0100; const DECLARE_LOCAL: u8 = 0b0000_0100;
const SET_LOCAL: u8 = 0b0000_0101; const GET_LOCAL: u8 = 0b0000_0101;
const ADD: u8 = 0b0000_0110; const SET_LOCAL: u8 = 0b0000_0110;
const SUBTRACT: u8 = 0b0000_0111; const ADD: u8 = 0b0000_0111;
const MULTIPLY: u8 = 0b0000_1000; const SUBTRACT: u8 = 0b0000_1000;
const MODULO: u8 = 0b0000_1001; const MULTIPLY: u8 = 0b0000_1001;
const AND: u8 = 0b0000_1010; const MODULO: u8 = 0b0000_1010;
const OR: u8 = 0b0000_1011; const AND: u8 = 0b0000_1011;
const DIVIDE: u8 = 0b0000_1100; const OR: u8 = 0b0000_1100;
const NEGATE: u8 = 0b0000_1101; const DIVIDE: u8 = 0b0000_1101;
const NOT: u8 = 0b0000_1110; const NEGATE: u8 = 0b0000_1110;
const RETURN: u8 = 0b0000_1111; const NOT: u8 = 0b0000_1111;
const RETURN: u8 = 0b0001_0000;
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq)]
pub enum Operation { pub enum Operation {
@ -450,8 +470,9 @@ pub enum Operation {
Move = MOVE as isize, Move = MOVE as isize,
Close = CLOSE as isize, Close = CLOSE as isize,
// Constants // Value loading
LoadConstant = LOAD_CONSTANT as isize, LoadConstant = LOAD_CONSTANT as isize,
LoadList = LOAD_LIST as isize,
// Variables // Variables
DeclareLocal = DECLARE_LOCAL as isize, DeclareLocal = DECLARE_LOCAL as isize,
@ -496,6 +517,7 @@ impl From<u8> for Operation {
MOVE => Operation::Move, MOVE => Operation::Move,
CLOSE => Operation::Close, CLOSE => Operation::Close,
LOAD_CONSTANT => Operation::LoadConstant, LOAD_CONSTANT => Operation::LoadConstant,
LOAD_LIST => Operation::LoadList,
DECLARE_LOCAL => Operation::DeclareLocal, DECLARE_LOCAL => Operation::DeclareLocal,
GET_LOCAL => Operation::GetLocal, GET_LOCAL => Operation::GetLocal,
SET_LOCAL => Operation::SetLocal, SET_LOCAL => Operation::SetLocal,
@ -520,6 +542,7 @@ impl From<Operation> for u8 {
Operation::Move => MOVE, Operation::Move => MOVE,
Operation::Close => CLOSE, Operation::Close => CLOSE,
Operation::LoadConstant => LOAD_CONSTANT, Operation::LoadConstant => LOAD_CONSTANT,
Operation::LoadList => LOAD_LIST,
Operation::DeclareLocal => DECLARE_LOCAL, Operation::DeclareLocal => DECLARE_LOCAL,
Operation::GetLocal => GET_LOCAL, Operation::GetLocal => GET_LOCAL,
Operation::SetLocal => SET_LOCAL, Operation::SetLocal => SET_LOCAL,
@ -543,6 +566,7 @@ impl Display for Operation {
Operation::Move => write!(f, "MOVE"), Operation::Move => write!(f, "MOVE"),
Operation::Close => write!(f, "CLOSE"), Operation::Close => write!(f, "CLOSE"),
Operation::LoadConstant => write!(f, "LOAD_CONSTANT"), Operation::LoadConstant => write!(f, "LOAD_CONSTANT"),
Operation::LoadList => write!(f, "LOAD_LIST"),
Operation::DeclareLocal => write!(f, "DECLARE_LOCAL"), Operation::DeclareLocal => write!(f, "DECLARE_LOCAL"),
Operation::GetLocal => write!(f, "GET_LOCAL"), Operation::GetLocal => write!(f, "GET_LOCAL"),
Operation::SetLocal => write!(f, "SET_LOCAL"), Operation::SetLocal => write!(f, "SET_LOCAL"),

View File

@ -240,35 +240,46 @@ impl<'src> Parser<'src> {
} }
fn parse_unary(&mut self, _allow_assignment: bool) -> Result<(), ParseError> { fn parse_unary(&mut self, _allow_assignment: bool) -> Result<(), ParseError> {
let operator_position = self.previous_position; let operator = self.current_token;
let mut instruction = match self.previous_token.kind() { let operator_position = self.current_position;
TokenKind::Minus => {
self.advance()?;
self.parse_expression()?;
Instruction::negate(self.current_register, self.current_register - 1) self.advance()?;
self.parse_expression()?;
let (previous_instruction, previous_position) =
self.chunk.pop_instruction(self.current_position)?;
let (is_constant, destination, from_register) = match previous_instruction.operation() {
Operation::LoadConstant => {
self.decrement_register()?;
(
true,
previous_instruction.destination(),
previous_instruction.first_argument(),
)
} }
_ => {
self.emit_instruction(previous_instruction, previous_position);
(false, self.current_register, self.current_register - 1)
}
};
let mut instruction = match operator.kind() {
TokenKind::Bang => Instruction::not(destination, from_register),
TokenKind::Minus => Instruction::negate(destination, from_register),
_ => { _ => {
return Err(ParseError::ExpectedTokenMultiple { return Err(ParseError::ExpectedTokenMultiple {
expected: vec![TokenKind::Minus], expected: &[TokenKind::Minus],
found: self.previous_token.to_owned(), found: operator.to_owned(),
position: operator_position, position: operator_position,
}) })
} }
}; };
let (previous_instruction, previous_position) = if is_constant {
self.chunk.pop_instruction(self.current_position)?; instruction.set_first_argument_to_constant();
match previous_instruction.operation() {
Operation::LoadConstant => {
self.decrement_register()?;
instruction.set_first_argument(previous_instruction.destination());
instruction.set_first_argument_to_constant();
}
_ => {
self.emit_instruction(previous_instruction, previous_position);
}
} }
self.increment_register()?; self.increment_register()?;
@ -340,7 +351,7 @@ impl<'src> Parser<'src> {
TokenKind::DoublePipe => Instruction::or(self.current_register, left, right), TokenKind::DoublePipe => Instruction::or(self.current_register, left, right),
_ => { _ => {
return Err(ParseError::ExpectedTokenMultiple { return Err(ParseError::ExpectedTokenMultiple {
expected: vec![ expected: &[
TokenKind::Plus, TokenKind::Plus,
TokenKind::Minus, TokenKind::Minus,
TokenKind::Star, TokenKind::Star,
@ -450,7 +461,7 @@ impl<'src> Parser<'src> {
} }
} }
pub fn parse_block(&mut self, _allow_assignment: bool) -> Result<(), ParseError> { fn parse_block(&mut self, _allow_assignment: bool) -> Result<(), ParseError> {
self.advance()?; self.advance()?;
self.chunk.begin_scope(); self.chunk.begin_scope();
@ -463,6 +474,34 @@ impl<'src> Parser<'src> {
Ok(()) Ok(())
} }
fn parse_list(&mut self, _allow_assignment: bool) -> Result<(), ParseError> {
self.advance()?;
let start = self.current_position.0;
let mut length = 0;
while !self.allow(TokenKind::RightSquareBrace)? && !self.is_eof() {
self.parse_expression()?;
length += 1;
if !self.allow(TokenKind::Comma)? {
self.expect(TokenKind::RightSquareBrace)?;
break;
}
}
let end = self.current_position.1;
self.emit_instruction(
Instruction::load_list(self.current_register, length),
Span(start, end),
);
Ok(())
}
fn parse_expression(&mut self) -> Result<(), ParseError> { fn parse_expression(&mut self) -> Result<(), ParseError> {
self.parse(Precedence::None) self.parse(Precedence::None)
} }
@ -700,7 +739,11 @@ impl From<&TokenKind> for ParseRule<'_> {
precedence: Precedence::Unary, precedence: Precedence::Unary,
}, },
TokenKind::Colon => todo!(), TokenKind::Colon => todo!(),
TokenKind::Comma => todo!(), TokenKind::Comma => ParseRule {
prefix: None,
infix: None,
precedence: Precedence::None,
},
TokenKind::Dot => todo!(), TokenKind::Dot => todo!(),
TokenKind::DoubleAmpersand => ParseRule { TokenKind::DoubleAmpersand => ParseRule {
prefix: None, prefix: None,
@ -731,7 +774,11 @@ impl From<&TokenKind> for ParseRule<'_> {
infix: None, infix: None,
precedence: Precedence::None, precedence: Precedence::None,
}, },
TokenKind::LeftSquareBrace => todo!(), TokenKind::LeftSquareBrace => ParseRule {
prefix: Some(Parser::parse_list),
infix: None,
precedence: Precedence::None,
},
TokenKind::Less => todo!(), TokenKind::Less => todo!(),
TokenKind::LessOrEqual => todo!(), TokenKind::LessOrEqual => todo!(),
TokenKind::Minus => ParseRule { TokenKind::Minus => ParseRule {
@ -758,7 +805,11 @@ impl From<&TokenKind> for ParseRule<'_> {
infix: None, infix: None,
precedence: Precedence::None, precedence: Precedence::None,
}, },
TokenKind::RightSquareBrace => todo!(), TokenKind::RightSquareBrace => ParseRule {
prefix: None,
infix: None,
precedence: Precedence::None,
},
TokenKind::Semicolon => ParseRule { TokenKind::Semicolon => ParseRule {
prefix: None, prefix: None,
infix: None, infix: None,
@ -791,7 +842,7 @@ pub enum ParseError {
position: Span, position: Span,
}, },
ExpectedTokenMultiple { ExpectedTokenMultiple {
expected: Vec<TokenKind>, expected: &'static [TokenKind],
found: TokenOwned, found: TokenOwned,
position: Span, position: Span,
}, },

View File

@ -54,6 +54,22 @@ impl Vm {
self.insert(value, to_register, position)?; self.insert(value, to_register, position)?;
} }
Operation::LoadList => {
let to_register = instruction.destination();
let length = instruction.first_argument();
let first_register = to_register - length;
let last_register = to_register - 1;
let mut list = Vec::with_capacity(length as usize);
for register_index in first_register..=last_register {
let value = self.clone(register_index, position)?;
list.push(value);
}
self.insert(Value::list(list), to_register, position)?;
}
Operation::DeclareLocal => { Operation::DeclareLocal => {
let from_register = instruction.destination(); let from_register = instruction.destination();
let to_local = instruction.first_argument(); let to_local = instruction.first_argument();