Add lists
This commit is contained in:
parent
6ca96bc1dc
commit
f02c3d1fb5
@ -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"),
|
||||
|
@ -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,
|
||||
},
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user