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