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

View File

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

View File

@ -54,6 +54,22 @@ impl Vm {
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 => {
let from_register = instruction.destination();
let to_local = instruction.first_argument();