Continue implemnting functions; Begin adding types
This commit is contained in:
parent
bdc34cb10e
commit
259721f6cb
@ -3,7 +3,10 @@ use std::fmt::{self, Debug, Display, Formatter};
|
|||||||
use colored::Colorize;
|
use colored::Colorize;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{AnnotatedError, Identifier, Instruction, Operation, Span, Value};
|
use crate::{
|
||||||
|
value::ValueKind, AnnotatedError, Function, Identifier, Instruction, Operation, Span, Type,
|
||||||
|
Value,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Clone, PartialOrd, Ord, Serialize, Deserialize)]
|
#[derive(Clone, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub struct Chunk {
|
pub struct Chunk {
|
||||||
@ -214,18 +217,20 @@ impl Chunk {
|
|||||||
pub fn declare_local(
|
pub fn declare_local(
|
||||||
&mut self,
|
&mut self,
|
||||||
identifier: Identifier,
|
identifier: Identifier,
|
||||||
mutable: bool,
|
r#type: Option<Type>,
|
||||||
|
is_mutable: bool,
|
||||||
register_index: u8,
|
register_index: u8,
|
||||||
position: Span,
|
position: Span,
|
||||||
) -> Result<u8, ChunkError> {
|
) -> Result<u8, ChunkError> {
|
||||||
let starting_length = self.locals.len();
|
let starting_length = self.locals.len();
|
||||||
|
|
||||||
if starting_length + 1 > (u8::MAX as usize) {
|
if starting_length + 1 > (u8::MAX as usize) {
|
||||||
Err(ChunkError::IdentifierOverflow { position })
|
Err(ChunkError::LocalOverflow { position })
|
||||||
} else {
|
} else {
|
||||||
self.locals.push(Local::new(
|
self.locals.push(Local::new(
|
||||||
identifier,
|
identifier,
|
||||||
mutable,
|
r#type,
|
||||||
|
is_mutable,
|
||||||
self.scope_depth,
|
self.scope_depth,
|
||||||
Some(register_index),
|
Some(register_index),
|
||||||
));
|
));
|
||||||
@ -308,6 +313,7 @@ impl PartialEq for Chunk {
|
|||||||
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub struct Local {
|
pub struct Local {
|
||||||
pub identifier: Identifier,
|
pub identifier: Identifier,
|
||||||
|
pub r#type: Option<Type>,
|
||||||
pub is_mutable: bool,
|
pub is_mutable: bool,
|
||||||
pub depth: usize,
|
pub depth: usize,
|
||||||
pub register_index: Option<u8>,
|
pub register_index: Option<u8>,
|
||||||
@ -316,12 +322,14 @@ pub struct Local {
|
|||||||
impl Local {
|
impl Local {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
identifier: Identifier,
|
identifier: Identifier,
|
||||||
|
r#type: Option<Type>,
|
||||||
mutable: bool,
|
mutable: bool,
|
||||||
depth: usize,
|
depth: usize,
|
||||||
register_index: Option<u8>,
|
register_index: Option<u8>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
identifier,
|
identifier,
|
||||||
|
r#type,
|
||||||
is_mutable: mutable,
|
is_mutable: mutable,
|
||||||
depth,
|
depth,
|
||||||
register_index,
|
register_index,
|
||||||
@ -334,6 +342,7 @@ pub struct ChunkDisassembler<'a> {
|
|||||||
chunk: &'a Chunk,
|
chunk: &'a Chunk,
|
||||||
width: Option<usize>,
|
width: Option<usize>,
|
||||||
styled: bool,
|
styled: bool,
|
||||||
|
indent: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ChunkDisassembler<'a> {
|
impl<'a> ChunkDisassembler<'a> {
|
||||||
@ -357,8 +366,8 @@ impl<'a> ChunkDisassembler<'a> {
|
|||||||
"",
|
"",
|
||||||
"Locals",
|
"Locals",
|
||||||
"------",
|
"------",
|
||||||
"INDEX IDENTIFIER MUTABLE DEPTH REGISTER",
|
"INDEX IDENTIFIER TYPE MUTABLE DEPTH REGISTER",
|
||||||
"----- ---------- ------- ----- --------",
|
"----- ---------- -------- ------- ----- --------",
|
||||||
];
|
];
|
||||||
|
|
||||||
/// The default width of the disassembly output. To correctly align the output, this should
|
/// The default width of the disassembly output. To correctly align the output, this should
|
||||||
@ -375,6 +384,7 @@ impl<'a> ChunkDisassembler<'a> {
|
|||||||
chunk,
|
chunk,
|
||||||
width: None,
|
width: None,
|
||||||
styled: false,
|
styled: false,
|
||||||
|
indent: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -390,6 +400,12 @@ impl<'a> ChunkDisassembler<'a> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn indent(&mut self, indent: usize) -> &mut Self {
|
||||||
|
self.indent = indent;
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub fn disassemble(&self) -> String {
|
pub fn disassemble(&self) -> String {
|
||||||
let width = self.width.unwrap_or_else(Self::default_width);
|
let width = self.width.unwrap_or_else(Self::default_width);
|
||||||
let center = |line: &str| format!("{line:^width$}\n");
|
let center = |line: &str| format!("{line:^width$}\n");
|
||||||
@ -402,9 +418,16 @@ impl<'a> ChunkDisassembler<'a> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let mut disassembly = String::with_capacity(self.predict_length());
|
let mut disassembly = String::with_capacity(self.predict_length());
|
||||||
|
let mut push_line = |line: &str| {
|
||||||
|
for _ in 0..self.indent {
|
||||||
|
disassembly.push_str(" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
disassembly.push_str(line);
|
||||||
|
};
|
||||||
let name_line = style(center(self.name));
|
let name_line = style(center(self.name));
|
||||||
|
|
||||||
disassembly.push_str(&name_line);
|
push_line(&name_line);
|
||||||
|
|
||||||
let info_line = center(&format!(
|
let info_line = center(&format!(
|
||||||
"{} instructions, {} constants, {} locals",
|
"{} instructions, {} constants, {} locals",
|
||||||
@ -420,10 +443,10 @@ impl<'a> ChunkDisassembler<'a> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
disassembly.push_str(&styled_info_line);
|
push_line(&styled_info_line);
|
||||||
|
|
||||||
for line in Self::INSTRUCTION_HEADER {
|
for line in Self::INSTRUCTION_HEADER {
|
||||||
disassembly.push_str(&style(center(line)));
|
push_line(&style(center(line)));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (index, (instruction, position)) in self.chunk.instructions.iter().enumerate() {
|
for (index, (instruction, position)) in self.chunk.instructions.iter().enumerate() {
|
||||||
@ -454,11 +477,11 @@ impl<'a> ChunkDisassembler<'a> {
|
|||||||
"{index:<5} {bytecode:<08X} {operation:15} {info:25} {jump_offset:8} {position:8}"
|
"{index:<5} {bytecode:<08X} {operation:15} {info:25} {jump_offset:8} {position:8}"
|
||||||
);
|
);
|
||||||
|
|
||||||
disassembly.push_str(¢er(&instruction_display));
|
push_line(¢er(&instruction_display));
|
||||||
}
|
}
|
||||||
|
|
||||||
for line in Self::CONSTANT_HEADER {
|
for line in Self::CONSTANT_HEADER {
|
||||||
disassembly.push_str(&style(center(line)));
|
push_line(&style(center(line)));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (index, value_option) in self.chunk.constants.iter().enumerate() {
|
for (index, value_option) in self.chunk.constants.iter().enumerate() {
|
||||||
@ -474,17 +497,34 @@ impl<'a> ChunkDisassembler<'a> {
|
|||||||
format!("{index:<5} {value_display:<trucated_length$}")
|
format!("{index:<5} {value_display:<trucated_length$}")
|
||||||
};
|
};
|
||||||
|
|
||||||
disassembly.push_str(¢er(&constant_display));
|
push_line(¢er(&constant_display));
|
||||||
|
|
||||||
|
if let Some(chunk) = value_option.as_ref().and_then(|value| match value {
|
||||||
|
Value::Raw(value_data) => value_data.as_function().map(|function| function.body()),
|
||||||
|
Value::Reference(arc) => arc.as_function().map(|function| function.body()),
|
||||||
|
Value::Mutable(arc) => todo!(),
|
||||||
|
}) {
|
||||||
|
let mut function_disassembler = chunk.disassembler("function");
|
||||||
|
|
||||||
|
function_disassembler
|
||||||
|
.styled(self.styled)
|
||||||
|
.indent(self.indent + 1);
|
||||||
|
|
||||||
|
let function_disassembly = function_disassembler.disassemble();
|
||||||
|
|
||||||
|
push_line(&function_disassembly);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for line in Self::LOCAL_HEADER {
|
for line in Self::LOCAL_HEADER {
|
||||||
disassembly.push_str(&style(center(line)));
|
push_line(&style(center(line)));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (
|
for (
|
||||||
index,
|
index,
|
||||||
Local {
|
Local {
|
||||||
identifier,
|
identifier,
|
||||||
|
r#type,
|
||||||
depth,
|
depth,
|
||||||
register_index,
|
register_index,
|
||||||
is_mutable: mutable,
|
is_mutable: mutable,
|
||||||
@ -496,11 +536,15 @@ impl<'a> ChunkDisassembler<'a> {
|
|||||||
.map(|value| value.to_string())
|
.map(|value| value.to_string())
|
||||||
.unwrap_or_else(|| "empty".to_string());
|
.unwrap_or_else(|| "empty".to_string());
|
||||||
let identifier_display = identifier.as_str();
|
let identifier_display = identifier.as_str();
|
||||||
|
let type_display = r#type
|
||||||
|
.as_ref()
|
||||||
|
.map(|r#type| r#type.to_string())
|
||||||
|
.unwrap_or("unknown".to_string());
|
||||||
let local_display = format!(
|
let local_display = format!(
|
||||||
"{index:<5} {identifier_display:10} {mutable:7} {depth:<5} {register_display:8}"
|
"{index:<5} {identifier_display:10} {type_display:8} {mutable:7} {depth:<5} {register_display:8}"
|
||||||
);
|
);
|
||||||
|
|
||||||
disassembly.push_str(¢er(&local_display));
|
push_line(¢er(&local_display));
|
||||||
}
|
}
|
||||||
|
|
||||||
let expected_length = self.predict_length();
|
let expected_length = self.predict_length();
|
||||||
@ -573,7 +617,7 @@ pub enum ChunkError {
|
|||||||
index: usize,
|
index: usize,
|
||||||
position: Span,
|
position: Span,
|
||||||
},
|
},
|
||||||
IdentifierOverflow {
|
LocalOverflow {
|
||||||
position: Span,
|
position: Span,
|
||||||
},
|
},
|
||||||
IdentifierNotFound {
|
IdentifierNotFound {
|
||||||
@ -594,8 +638,8 @@ impl AnnotatedError for ChunkError {
|
|||||||
ChunkError::ConstantOverflow { .. } => "Constant overflow",
|
ChunkError::ConstantOverflow { .. } => "Constant overflow",
|
||||||
ChunkError::ConstantIndexOutOfBounds { .. } => "Constant index out of bounds",
|
ChunkError::ConstantIndexOutOfBounds { .. } => "Constant index out of bounds",
|
||||||
ChunkError::InstructionUnderflow { .. } => "Instruction underflow",
|
ChunkError::InstructionUnderflow { .. } => "Instruction underflow",
|
||||||
ChunkError::LocalIndexOutOfBounds { .. } => "Identifier index out of bounds",
|
ChunkError::LocalIndexOutOfBounds { .. } => "Local index out of bounds",
|
||||||
ChunkError::IdentifierOverflow { .. } => "Identifier overflow",
|
ChunkError::LocalOverflow { .. } => "Local overflow",
|
||||||
ChunkError::IdentifierNotFound { .. } => "Identifier not found",
|
ChunkError::IdentifierNotFound { .. } => "Identifier not found",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -611,13 +655,13 @@ impl AnnotatedError for ChunkError {
|
|||||||
}
|
}
|
||||||
ChunkError::InstructionUnderflow { .. } => None,
|
ChunkError::InstructionUnderflow { .. } => None,
|
||||||
ChunkError::LocalIndexOutOfBounds { index, .. } => {
|
ChunkError::LocalIndexOutOfBounds { index, .. } => {
|
||||||
Some(format!("Identifier index: {}", index))
|
Some(format!("Local index: {}", index))
|
||||||
}
|
}
|
||||||
ChunkError::IdentifierNotFound { identifier, .. } => {
|
ChunkError::IdentifierNotFound { identifier, .. } => {
|
||||||
Some(format!("Identifier: {}", identifier))
|
Some(format!("Identifier: {}", identifier))
|
||||||
}
|
}
|
||||||
ChunkError::IdentifierOverflow { .. } => Some("Identifier overflow".to_string()),
|
ChunkError::LocalOverflow { .. } => None,
|
||||||
ChunkError::ConstantOverflow { .. } => Some("Constant overflow".to_string()),
|
ChunkError::ConstantOverflow { .. } => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -629,7 +673,7 @@ impl AnnotatedError for ChunkError {
|
|||||||
ChunkError::IdentifierNotFound { position, .. } => *position,
|
ChunkError::IdentifierNotFound { position, .. } => *position,
|
||||||
ChunkError::InstructionUnderflow { position, .. } => *position,
|
ChunkError::InstructionUnderflow { position, .. } => *position,
|
||||||
ChunkError::LocalIndexOutOfBounds { position, .. } => *position,
|
ChunkError::LocalIndexOutOfBounds { position, .. } => *position,
|
||||||
ChunkError::IdentifierOverflow { position, .. } => *position,
|
ChunkError::LocalOverflow { position, .. } => *position,
|
||||||
ChunkError::ConstantOverflow { position, .. } => *position,
|
ChunkError::ConstantOverflow { position, .. } => *position,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -93,6 +93,10 @@ impl<'src> Lexer<'src> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn skip_to(&mut self, position: usize) {
|
||||||
|
self.position = position;
|
||||||
|
}
|
||||||
|
|
||||||
/// Produce the next token.
|
/// Produce the next token.
|
||||||
pub fn next_token(&mut self) -> Result<(Token<'src>, Span), LexError> {
|
pub fn next_token(&mut self) -> Result<(Token<'src>, Span), LexError> {
|
||||||
self.skip_whitespace();
|
self.skip_whitespace();
|
||||||
@ -539,6 +543,7 @@ impl<'src> Lexer<'src> {
|
|||||||
"loop" => Token::Loop,
|
"loop" => Token::Loop,
|
||||||
"map" => Token::Map,
|
"map" => Token::Map,
|
||||||
"mut" => Token::Mut,
|
"mut" => Token::Mut,
|
||||||
|
"str" => Token::Str,
|
||||||
"struct" => Token::Struct,
|
"struct" => Token::Struct,
|
||||||
"true" => Token::Boolean("true"),
|
"true" => Token::Boolean("true"),
|
||||||
"while" => Token::While,
|
"while" => Token::While,
|
||||||
|
@ -8,7 +8,7 @@ use colored::Colorize;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
AnnotatedError, Chunk, ChunkError, DustError, Identifier, Instruction, LexError, Lexer,
|
AnnotatedError, Chunk, ChunkError, DustError, Identifier, Instruction, LexError, Lexer,
|
||||||
Operation, Span, Token, TokenKind, TokenOwned, Value,
|
Operation, Span, Token, TokenKind, TokenOwned, Type, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn parse(source: &str) -> Result<Chunk, DustError> {
|
pub fn parse(source: &str) -> Result<Chunk, DustError> {
|
||||||
@ -17,7 +17,11 @@ pub fn parse(source: &str) -> Result<Chunk, DustError> {
|
|||||||
|
|
||||||
while !parser.is_eof() {
|
while !parser.is_eof() {
|
||||||
parser
|
parser
|
||||||
.parse_statement(true)
|
.parse_statement(Allowed {
|
||||||
|
assignment: true,
|
||||||
|
explicit_return: false,
|
||||||
|
implicit_return: true,
|
||||||
|
})
|
||||||
.map_err(|error| DustError::Parse { error, source })?;
|
.map_err(|error| DustError::Parse { error, source })?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,9 +43,8 @@ impl<'src> Parser<'src> {
|
|||||||
pub fn new(mut lexer: Lexer<'src>) -> Result<Self, ParseError> {
|
pub fn new(mut lexer: Lexer<'src>) -> Result<Self, ParseError> {
|
||||||
let (current_token, current_position) = lexer.next_token()?;
|
let (current_token, current_position) = lexer.next_token()?;
|
||||||
|
|
||||||
log::info!("Begin chunk");
|
|
||||||
log::info!(
|
log::info!(
|
||||||
"{} at {}",
|
"Begin chunk with {} at {}",
|
||||||
current_token.to_string().bold(),
|
current_token.to_string().bold(),
|
||||||
current_position.to_string()
|
current_position.to_string()
|
||||||
);
|
);
|
||||||
@ -81,7 +84,7 @@ impl<'src> Parser<'src> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decrement_register(&mut self) -> Result<(), ParseError> {
|
fn _decrement_register(&mut self) -> Result<(), ParseError> {
|
||||||
let current = self.current_register;
|
let current = self.current_register;
|
||||||
|
|
||||||
if current == 0 {
|
if current == 0 {
|
||||||
@ -140,8 +143,7 @@ impl<'src> Parser<'src> {
|
|||||||
self.chunk.push_instruction(instruction, position);
|
self.chunk.push_instruction(instruction, position);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_constant(&mut self, value: Value) -> Result<(), ParseError> {
|
fn emit_constant(&mut self, value: Value, position: Span) -> Result<(), ParseError> {
|
||||||
let position = self.previous_position;
|
|
||||||
let constant_index = self.chunk.push_constant(value, position)?;
|
let constant_index = self.chunk.push_constant(value, position)?;
|
||||||
|
|
||||||
self.emit_instruction(
|
self.emit_instruction(
|
||||||
@ -152,11 +154,7 @@ impl<'src> Parser<'src> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_boolean(
|
fn parse_boolean(&mut self, _: Allowed) -> Result<(), ParseError> {
|
||||||
&mut self,
|
|
||||||
_allow_assignment: bool,
|
|
||||||
_allow_return: bool,
|
|
||||||
) -> Result<(), ParseError> {
|
|
||||||
let boolean_text = if let Token::Boolean(text) = self.current_token {
|
let boolean_text = if let Token::Boolean(text) = self.current_token {
|
||||||
text
|
text
|
||||||
} else {
|
} else {
|
||||||
@ -171,7 +169,6 @@ impl<'src> Parser<'src> {
|
|||||||
let boolean = boolean_text.parse::<bool>().unwrap();
|
let boolean = boolean_text.parse::<bool>().unwrap();
|
||||||
|
|
||||||
self.advance()?;
|
self.advance()?;
|
||||||
|
|
||||||
self.emit_instruction(
|
self.emit_instruction(
|
||||||
Instruction::load_boolean(self.current_register, boolean, false),
|
Instruction::load_boolean(self.current_register, boolean, false),
|
||||||
position,
|
position,
|
||||||
@ -180,11 +177,9 @@ impl<'src> Parser<'src> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_byte(
|
fn parse_byte(&mut self, _: Allowed) -> Result<(), ParseError> {
|
||||||
&mut self,
|
let position = self.current_position;
|
||||||
_allow_assignment: bool,
|
|
||||||
_allow_return: bool,
|
|
||||||
) -> Result<(), ParseError> {
|
|
||||||
if let Token::Byte(text) = self.current_token {
|
if let Token::Byte(text) = self.current_token {
|
||||||
self.advance()?;
|
self.advance()?;
|
||||||
|
|
||||||
@ -195,33 +190,29 @@ impl<'src> Parser<'src> {
|
|||||||
})?;
|
})?;
|
||||||
let value = Value::byte(byte);
|
let value = Value::byte(byte);
|
||||||
|
|
||||||
self.emit_constant(value)?;
|
self.emit_constant(value, position)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_character(
|
fn parse_character(&mut self, _: Allowed) -> Result<(), ParseError> {
|
||||||
&mut self,
|
let position = self.current_position;
|
||||||
_allow_assignment: bool,
|
|
||||||
_allow_return: bool,
|
|
||||||
) -> Result<(), ParseError> {
|
|
||||||
if let Token::Character(character) = self.current_token {
|
if let Token::Character(character) = self.current_token {
|
||||||
self.advance()?;
|
self.advance()?;
|
||||||
|
|
||||||
let value = Value::character(character);
|
let value = Value::character(character);
|
||||||
|
|
||||||
self.emit_constant(value)?;
|
self.emit_constant(value, position)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_float(
|
fn parse_float(&mut self, _: Allowed) -> Result<(), ParseError> {
|
||||||
&mut self,
|
let position = self.current_position;
|
||||||
_allow_assignment: bool,
|
|
||||||
_allow_return: bool,
|
|
||||||
) -> Result<(), ParseError> {
|
|
||||||
if let Token::Float(text) = self.current_token {
|
if let Token::Float(text) = self.current_token {
|
||||||
self.advance()?;
|
self.advance()?;
|
||||||
|
|
||||||
@ -233,17 +224,15 @@ impl<'src> Parser<'src> {
|
|||||||
})?;
|
})?;
|
||||||
let value = Value::float(float);
|
let value = Value::float(float);
|
||||||
|
|
||||||
self.emit_constant(value)?;
|
self.emit_constant(value, position)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_integer(
|
fn parse_integer(&mut self, _: Allowed) -> Result<(), ParseError> {
|
||||||
&mut self,
|
let position = self.current_position;
|
||||||
_allow_assignment: bool,
|
|
||||||
_allow_return: bool,
|
|
||||||
) -> Result<(), ParseError> {
|
|
||||||
if let Token::Integer(text) = self.current_token {
|
if let Token::Integer(text) = self.current_token {
|
||||||
self.advance()?;
|
self.advance()?;
|
||||||
|
|
||||||
@ -255,43 +244,33 @@ impl<'src> Parser<'src> {
|
|||||||
})?;
|
})?;
|
||||||
let value = Value::integer(integer);
|
let value = Value::integer(integer);
|
||||||
|
|
||||||
self.emit_constant(value)?;
|
self.emit_constant(value, position)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_string(
|
fn parse_string(&mut self, _: Allowed) -> Result<(), ParseError> {
|
||||||
&mut self,
|
let position = self.current_position;
|
||||||
_allow_assignment: bool,
|
|
||||||
_allow_return: bool,
|
|
||||||
) -> Result<(), ParseError> {
|
|
||||||
if let Token::String(text) = self.current_token {
|
if let Token::String(text) = self.current_token {
|
||||||
self.advance()?;
|
self.advance()?;
|
||||||
|
|
||||||
let value = Value::string(text);
|
let value = Value::string(text);
|
||||||
|
|
||||||
self.emit_constant(value)?;
|
self.emit_constant(value, position)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_grouped(
|
fn parse_grouped(&mut self, _: Allowed) -> Result<(), ParseError> {
|
||||||
&mut self,
|
|
||||||
_allow_assignment: bool,
|
|
||||||
_allow_return: bool,
|
|
||||||
) -> Result<(), ParseError> {
|
|
||||||
self.allow(TokenKind::LeftParenthesis)?;
|
self.allow(TokenKind::LeftParenthesis)?;
|
||||||
self.parse(Precedence::Assignment)?; // Do not allow assignment
|
self.parse(Precedence::Assignment)?; // Do not allow assignment
|
||||||
self.expect(TokenKind::RightParenthesis)
|
self.expect(TokenKind::RightParenthesis)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_unary(
|
fn parse_unary(&mut self, _: Allowed) -> Result<(), ParseError> {
|
||||||
&mut self,
|
|
||||||
_allow_assignment: bool,
|
|
||||||
_allow_return: bool,
|
|
||||||
) -> Result<(), ParseError> {
|
|
||||||
let operator = self.current_token;
|
let operator = self.current_token;
|
||||||
let operator_position = self.current_position;
|
let operator_position = self.current_position;
|
||||||
|
|
||||||
@ -428,6 +407,7 @@ impl<'src> Parser<'src> {
|
|||||||
|
|
||||||
current
|
current
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut new_instruction = match operator.kind() {
|
let mut new_instruction = match operator.kind() {
|
||||||
TokenKind::Plus => Instruction::add(register, left, right),
|
TokenKind::Plus => Instruction::add(register, left, right),
|
||||||
TokenKind::PlusEqual => Instruction::add(register, left, right),
|
TokenKind::PlusEqual => Instruction::add(register, left, right),
|
||||||
@ -605,11 +585,7 @@ impl<'src> Parser<'src> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_variable(
|
fn parse_variable(&mut self, allowed: Allowed) -> Result<(), ParseError> {
|
||||||
&mut self,
|
|
||||||
allow_assignment: bool,
|
|
||||||
_allow_return: bool,
|
|
||||||
) -> Result<(), ParseError> {
|
|
||||||
let token = self.current_token;
|
let token = self.current_token;
|
||||||
let start_position = self.current_position;
|
let start_position = self.current_position;
|
||||||
|
|
||||||
@ -617,7 +593,7 @@ impl<'src> Parser<'src> {
|
|||||||
|
|
||||||
let local_index = self.parse_identifier_from(token, start_position)?;
|
let local_index = self.parse_identifier_from(token, start_position)?;
|
||||||
|
|
||||||
if allow_assignment && self.allow(TokenKind::Equal)? {
|
if allowed.assignment && self.allow(TokenKind::Equal)? {
|
||||||
let is_mutable = self
|
let is_mutable = self
|
||||||
.chunk
|
.chunk
|
||||||
.get_local(local_index, start_position)?
|
.get_local(local_index, start_position)?
|
||||||
@ -687,16 +663,31 @@ impl<'src> Parser<'src> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_block(
|
fn parse_type_from(&mut self, token: Token, position: Span) -> Result<Type, ParseError> {
|
||||||
&mut self,
|
match token {
|
||||||
_allow_assignment: bool,
|
Token::Bool => Ok(Type::Boolean),
|
||||||
_allow_return: bool,
|
Token::FloatKeyword => Ok(Type::Float),
|
||||||
) -> Result<(), ParseError> {
|
Token::Int => Ok(Type::Integer),
|
||||||
self.expect(TokenKind::LeftCurlyBrace)?;
|
Token::Str => Ok(Type::String { length: None }),
|
||||||
|
_ => Err(ParseError::ExpectedTokenMultiple {
|
||||||
|
expected: &[
|
||||||
|
TokenKind::Bool,
|
||||||
|
TokenKind::FloatKeyword,
|
||||||
|
TokenKind::Int,
|
||||||
|
TokenKind::Str,
|
||||||
|
],
|
||||||
|
found: self.current_token.to_owned(),
|
||||||
|
position,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_block(&mut self, allowed: Allowed) -> Result<(), ParseError> {
|
||||||
|
self.advance()?;
|
||||||
self.chunk.begin_scope();
|
self.chunk.begin_scope();
|
||||||
|
|
||||||
while !self.allow(TokenKind::RightCurlyBrace)? && !self.is_eof() {
|
while !self.allow(TokenKind::RightCurlyBrace)? && !self.is_eof() {
|
||||||
self.parse_statement(_allow_return)?;
|
self.parse_statement(allowed)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.chunk.end_scope();
|
self.chunk.end_scope();
|
||||||
@ -704,11 +695,7 @@ impl<'src> Parser<'src> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_list(
|
fn parse_list(&mut self, _: Allowed) -> Result<(), ParseError> {
|
||||||
&mut self,
|
|
||||||
_allow_assignment: bool,
|
|
||||||
_allow_return: bool,
|
|
||||||
) -> Result<(), ParseError> {
|
|
||||||
let start = self.current_position.0;
|
let start = self.current_position.0;
|
||||||
|
|
||||||
self.advance()?;
|
self.advance()?;
|
||||||
@ -745,7 +732,8 @@ impl<'src> Parser<'src> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_if(&mut self, allow_assignment: bool, allow_return: bool) -> Result<(), ParseError> {
|
fn parse_if(&mut self, mut allowed: Allowed) -> Result<(), ParseError> {
|
||||||
|
allowed.implicit_return = false;
|
||||||
let length = self.chunk.len();
|
let length = self.chunk.len();
|
||||||
|
|
||||||
self.advance()?;
|
self.advance()?;
|
||||||
@ -762,7 +750,7 @@ impl<'src> Parser<'src> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Token::LeftCurlyBrace = self.current_token {
|
if let Token::LeftCurlyBrace = self.current_token {
|
||||||
self.parse_block(allow_assignment, allow_return)?;
|
self.parse_block(allowed)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let last_operation = self.chunk.get_last_operation()?;
|
let last_operation = self.chunk.get_last_operation()?;
|
||||||
@ -780,28 +768,25 @@ impl<'src> Parser<'src> {
|
|||||||
|
|
||||||
if self.allow(TokenKind::Else)? {
|
if self.allow(TokenKind::Else)? {
|
||||||
if let Token::If = self.current_token {
|
if let Token::If = self.current_token {
|
||||||
self.parse_if(allow_assignment, allow_return)?;
|
self.parse_if(allowed)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Token::LeftCurlyBrace = self.current_token {
|
if let Token::LeftCurlyBrace = self.current_token {
|
||||||
self.parse_block(allow_assignment, allow_return)?;
|
self.parse_block(allowed)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_while(
|
fn parse_while(&mut self, mut allowed: Allowed) -> Result<(), ParseError> {
|
||||||
&mut self,
|
|
||||||
allow_assignment: bool,
|
|
||||||
allow_return: bool,
|
|
||||||
) -> Result<(), ParseError> {
|
|
||||||
self.advance()?;
|
self.advance()?;
|
||||||
|
|
||||||
|
allowed.implicit_return = false;
|
||||||
let jump_start = self.chunk.len();
|
let jump_start = self.chunk.len();
|
||||||
|
|
||||||
self.parse(Precedence::Assignment)?; // Do not allow assignment
|
self.parse(Precedence::Assignment)?; // Do not allow assignment
|
||||||
self.parse_block(allow_assignment, allow_return)?;
|
self.parse_block(allowed)?;
|
||||||
|
|
||||||
let jump_end = self.chunk.len();
|
let jump_end = self.chunk.len();
|
||||||
let jump_distance = jump_end.abs_diff(jump_start) as u8;
|
let jump_distance = jump_end.abs_diff(jump_start) as u8;
|
||||||
@ -847,20 +832,27 @@ impl<'src> Parser<'src> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_statement(&mut self, allow_return: bool) -> Result<(), ParseError> {
|
fn parse_statement(&mut self, allowed: Allowed) -> Result<(), ParseError> {
|
||||||
match self.current_token {
|
match self.current_token {
|
||||||
Token::Let => {
|
Token::Let => {
|
||||||
self.parse_let_statement(true, allow_return)?;
|
self.parse_let_statement(Allowed {
|
||||||
|
assignment: true,
|
||||||
|
explicit_return: false,
|
||||||
|
implicit_return: false,
|
||||||
|
})?;
|
||||||
self.allow(TokenKind::Semicolon)?;
|
self.allow(TokenKind::Semicolon)?;
|
||||||
}
|
}
|
||||||
Token::LeftCurlyBrace => {
|
Token::LeftCurlyBrace => {
|
||||||
self.parse_block(true, true)?;
|
self.parse_block(allowed)?;
|
||||||
self.allow(TokenKind::Semicolon)?;
|
self.allow(TokenKind::Semicolon)?;
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
self.parse_expression()?;
|
self.parse_expression()?;
|
||||||
|
|
||||||
if !self.allow(TokenKind::Semicolon)? && self.is_eof() {
|
if allowed.implicit_return
|
||||||
|
&& !self.allow(TokenKind::Semicolon)?
|
||||||
|
&& (self.is_eof() || matches!(self.current_token, Token::RightCurlyBrace))
|
||||||
|
{
|
||||||
self.emit_instruction(Instruction::r#return(), self.current_position);
|
self.emit_instruction(Instruction::r#return(), self.current_position);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -869,19 +861,15 @@ impl<'src> Parser<'src> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_let_statement(
|
fn parse_let_statement(&mut self, allowed: Allowed) -> Result<(), ParseError> {
|
||||||
&mut self,
|
if !allowed.assignment {
|
||||||
allow_assignment: bool,
|
|
||||||
_allow_return: bool,
|
|
||||||
) -> Result<(), ParseError> {
|
|
||||||
if !allow_assignment {
|
|
||||||
return Err(ParseError::ExpectedExpression {
|
return Err(ParseError::ExpectedExpression {
|
||||||
found: self.current_token.to_owned(),
|
found: self.current_token.to_owned(),
|
||||||
position: self.current_position,
|
position: self.current_position,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
self.allow(TokenKind::Let)?;
|
self.expect(TokenKind::Let)?;
|
||||||
|
|
||||||
let is_mutable = self.allow(TokenKind::Mut)?;
|
let is_mutable = self.allow(TokenKind::Mut)?;
|
||||||
let position = self.current_position;
|
let position = self.current_position;
|
||||||
@ -896,40 +884,104 @@ impl<'src> Parser<'src> {
|
|||||||
position: self.current_position,
|
position: self.current_position,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
let explicit_type = if self.allow(TokenKind::Colon)? {
|
||||||
|
Some(self.parse_type_from(self.current_token, self.current_position)?)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
let register = self.current_register;
|
||||||
|
|
||||||
self.expect(TokenKind::Equal)?;
|
self.expect(TokenKind::Equal)?;
|
||||||
self.parse_expression()?;
|
self.parse_expression()?;
|
||||||
|
|
||||||
|
if self.current_register == register {
|
||||||
self.increment_register()?;
|
self.increment_register()?;
|
||||||
|
}
|
||||||
|
|
||||||
let (previous_instruction, previous_position) = self.chunk.get_last_instruction()?;
|
let (previous_instruction, previous_position) = self.chunk.get_last_instruction()?;
|
||||||
|
|
||||||
|
if let Operation::LoadConstant | Operation::LoadBoolean | Operation::Add =
|
||||||
|
previous_instruction.operation()
|
||||||
|
{
|
||||||
let register = previous_instruction.a();
|
let register = previous_instruction.a();
|
||||||
let local_index =
|
let local_index = self.chunk.declare_local(
|
||||||
self.chunk
|
identifier,
|
||||||
.declare_local(identifier, is_mutable, register, *previous_position)?;
|
explicit_type,
|
||||||
|
is_mutable,
|
||||||
|
register,
|
||||||
|
*previous_position,
|
||||||
|
)?;
|
||||||
|
|
||||||
self.emit_instruction(
|
self.emit_instruction(
|
||||||
Instruction::define_local(register, local_index, is_mutable),
|
Instruction::define_local(register, local_index, is_mutable),
|
||||||
position,
|
position,
|
||||||
);
|
);
|
||||||
self.allow(TokenKind::Semicolon)?;
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_function(
|
fn parse_function(&mut self, _: Allowed) -> Result<(), ParseError> {
|
||||||
&mut self,
|
let function_start = self.current_position.0;
|
||||||
_allow_assignment: bool,
|
|
||||||
_allow_return: bool,
|
|
||||||
) -> Result<(), ParseError> {
|
|
||||||
self.advance()?;
|
|
||||||
|
|
||||||
self.expect(TokenKind::LeftParenthesis)?;
|
|
||||||
|
|
||||||
let mut function_parser = Parser::new(self.lexer)?;
|
let mut function_parser = Parser::new(self.lexer)?;
|
||||||
|
|
||||||
self.expect(TokenKind::RightParenthesis)?;
|
function_parser.expect(TokenKind::LeftParenthesis)?;
|
||||||
|
|
||||||
function_parser.parse_block(false, true)?;
|
while function_parser.current_token != Token::RightParenthesis {
|
||||||
|
let start = function_parser.current_position.0;
|
||||||
|
let is_mutable = function_parser.allow(TokenKind::Mut)?;
|
||||||
|
let parameter = if let Token::Identifier(text) = function_parser.current_token {
|
||||||
|
function_parser.advance()?;
|
||||||
|
|
||||||
|
Identifier::new(text)
|
||||||
|
} else {
|
||||||
|
return Err(ParseError::ExpectedToken {
|
||||||
|
expected: TokenKind::Identifier,
|
||||||
|
found: function_parser.current_token.to_owned(),
|
||||||
|
position: function_parser.current_position,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
function_parser.expect(TokenKind::Colon)?;
|
||||||
|
|
||||||
|
let r#type = function_parser.parse_type_from(
|
||||||
|
function_parser.current_token,
|
||||||
|
function_parser.current_position,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
function_parser.advance()?;
|
||||||
|
|
||||||
|
let end = function_parser.current_position.1;
|
||||||
|
let local_index = function_parser.chunk.declare_local(
|
||||||
|
parameter,
|
||||||
|
Some(r#type),
|
||||||
|
is_mutable,
|
||||||
|
function_parser.current_register,
|
||||||
|
Span(start, end),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
function_parser.chunk.define_local(
|
||||||
|
local_index,
|
||||||
|
function_parser.current_register,
|
||||||
|
Span(start, end),
|
||||||
|
)?;
|
||||||
|
function_parser.increment_register()?;
|
||||||
|
function_parser.allow(TokenKind::Comma)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
function_parser.advance()?;
|
||||||
|
function_parser.expect(TokenKind::LeftCurlyBrace)?;
|
||||||
|
|
||||||
|
while function_parser.current_token != Token::RightCurlyBrace {
|
||||||
|
function_parser.parse_statement(Allowed {
|
||||||
|
assignment: true,
|
||||||
|
explicit_return: true,
|
||||||
|
implicit_return: true,
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
|
||||||
|
function_parser.advance()?;
|
||||||
|
|
||||||
self.previous_token = function_parser.previous_token;
|
self.previous_token = function_parser.previous_token;
|
||||||
self.previous_position = function_parser.previous_position;
|
self.previous_position = function_parser.previous_position;
|
||||||
@ -937,8 +989,10 @@ impl<'src> Parser<'src> {
|
|||||||
self.current_position = function_parser.current_position;
|
self.current_position = function_parser.current_position;
|
||||||
|
|
||||||
let function = Value::function(function_parser.take_chunk());
|
let function = Value::function(function_parser.take_chunk());
|
||||||
|
let function_end = self.current_position.1;
|
||||||
|
|
||||||
self.emit_constant(function)?;
|
self.lexer.skip_to(function_end);
|
||||||
|
self.emit_constant(function, Span(function_start, function_end))?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -954,7 +1008,14 @@ impl<'src> Parser<'src> {
|
|||||||
self.current_token.to_string().bold(),
|
self.current_token.to_string().bold(),
|
||||||
);
|
);
|
||||||
|
|
||||||
prefix_parser(self, allow_assignment, allow_return)?;
|
prefix_parser(
|
||||||
|
self,
|
||||||
|
Allowed {
|
||||||
|
assignment: true,
|
||||||
|
explicit_return: allow_return,
|
||||||
|
implicit_return: allow_return,
|
||||||
|
},
|
||||||
|
)?;
|
||||||
parsed = true;
|
parsed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1056,7 +1117,14 @@ impl Display for Precedence {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type PrefixFunction<'a> = fn(&mut Parser<'a>, bool, bool) -> Result<(), ParseError>;
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
struct Allowed {
|
||||||
|
assignment: bool,
|
||||||
|
explicit_return: bool,
|
||||||
|
implicit_return: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
type PrefixFunction<'a> = fn(&mut Parser<'a>, Allowed) -> Result<(), ParseError>;
|
||||||
type InfixFunction<'a> = fn(&mut Parser<'a>) -> Result<(), ParseError>;
|
type InfixFunction<'a> = fn(&mut Parser<'a>) -> Result<(), ParseError>;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
@ -1374,19 +1442,19 @@ impl AnnotatedError for ParseError {
|
|||||||
fn details(&self) -> Option<String> {
|
fn details(&self) -> Option<String> {
|
||||||
match self {
|
match self {
|
||||||
Self::CannotMutateImmutableVariable { identifier, .. } => {
|
Self::CannotMutateImmutableVariable { identifier, .. } => {
|
||||||
Some(format!("Cannot mutate immutable variable \"{identifier}\""))
|
Some(format!("Cannot mutate immutable variable {identifier}"))
|
||||||
}
|
}
|
||||||
Self::ExpectedExpression { found, .. } => Some(format!("Found \"{found}\"")),
|
Self::ExpectedExpression { found, .. } => Some(format!("Found {found}")),
|
||||||
Self::ExpectedToken {
|
Self::ExpectedToken {
|
||||||
expected, found, ..
|
expected, found, ..
|
||||||
} => Some(format!("Expected \"{expected}\", found \"{found}\"")),
|
} => Some(format!("Expected {expected} but found {found}")),
|
||||||
Self::ExpectedTokenMultiple {
|
Self::ExpectedTokenMultiple {
|
||||||
expected, found, ..
|
expected, found, ..
|
||||||
} => {
|
} => {
|
||||||
let mut details = String::from("Expected");
|
let mut details = String::from("Expected");
|
||||||
|
|
||||||
for (index, token) in expected.iter().enumerate() {
|
for (index, token) in expected.iter().enumerate() {
|
||||||
details.push_str(&format!(" \"{token}\""));
|
details.push_str(&format!(" {token}"));
|
||||||
|
|
||||||
if index < expected.len() - 2 {
|
if index < expected.len() - 2 {
|
||||||
details.push_str(", ");
|
details.push_str(", ");
|
||||||
@ -1397,18 +1465,18 @@ impl AnnotatedError for ParseError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
details.push_str(&format!(" found \"{found}\""));
|
details.push_str(&format!(" but found {found}"));
|
||||||
|
|
||||||
Some(details)
|
Some(details)
|
||||||
}
|
}
|
||||||
Self::ExpectedMutableVariable { found, .. } => {
|
Self::ExpectedMutableVariable { found, .. } => {
|
||||||
Some(format!("Expected mutable variable, found \"{found}\""))
|
Some(format!("Expected mutable variable, found {found}"))
|
||||||
}
|
}
|
||||||
Self::InvalidAssignmentTarget { found, .. } => {
|
Self::InvalidAssignmentTarget { found, .. } => {
|
||||||
Some(format!("Invalid assignment target, found \"{found}\""))
|
Some(format!("Invalid assignment target, found {found}"))
|
||||||
}
|
}
|
||||||
Self::UndefinedVariable { identifier, .. } => {
|
Self::UndefinedVariable { identifier, .. } => {
|
||||||
Some(format!("Undefined variable \"{identifier}\""))
|
Some(format!("Undefined variable {identifier}"))
|
||||||
}
|
}
|
||||||
Self::RegisterOverflow { .. } => None,
|
Self::RegisterOverflow { .. } => None,
|
||||||
Self::RegisterUnderflow { .. } => None,
|
Self::RegisterUnderflow { .. } => None,
|
||||||
@ -1430,10 +1498,10 @@ impl AnnotatedError for ParseError {
|
|||||||
Self::UndefinedVariable { position, .. } => *position,
|
Self::UndefinedVariable { position, .. } => *position,
|
||||||
Self::RegisterOverflow { position } => *position,
|
Self::RegisterOverflow { position } => *position,
|
||||||
Self::RegisterUnderflow { position } => *position,
|
Self::RegisterUnderflow { position } => *position,
|
||||||
Self::Chunk(error) => error.position(),
|
|
||||||
Self::Lex(error) => error.position(),
|
|
||||||
Self::ParseFloatError { position, .. } => *position,
|
Self::ParseFloatError { position, .. } => *position,
|
||||||
Self::ParseIntError { position, .. } => *position,
|
Self::ParseIntError { position, .. } => *position,
|
||||||
|
Self::Chunk(error) => error.position(),
|
||||||
|
Self::Lex(error) => error.position(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@ use serde::{
|
|||||||
Deserialize, Deserializer, Serialize, Serializer,
|
Deserialize, Deserializer, Serialize, Serializer,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{Chunk, EnumType, FunctionType, Identifier, RangeableType, StructType, Type};
|
use crate::{Chunk, EnumType, Identifier, RangeableType, StructType, Type};
|
||||||
|
|
||||||
/// Dust value representation
|
/// Dust value representation
|
||||||
///
|
///
|
||||||
@ -1063,6 +1063,14 @@ impl ValueData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn as_function(&self) -> Option<&Function> {
|
||||||
|
if let ValueData::Function(function) = self {
|
||||||
|
Some(function)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_rangeable(&self) -> bool {
|
pub fn is_rangeable(&self) -> bool {
|
||||||
matches!(
|
matches!(
|
||||||
self,
|
self,
|
||||||
@ -1452,6 +1460,10 @@ pub struct Function {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Function {
|
impl Function {
|
||||||
|
pub fn body(&self) -> &Chunk {
|
||||||
|
&self.body
|
||||||
|
}
|
||||||
|
|
||||||
pub fn call(
|
pub fn call(
|
||||||
self,
|
self,
|
||||||
_type_arguments: Option<Vec<Type>>,
|
_type_arguments: Option<Vec<Type>>,
|
||||||
|
@ -482,7 +482,7 @@ impl Vm {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pop(&mut self, position: Span) -> Result<Value, VmError> {
|
fn _pop(&mut self, position: Span) -> Result<Value, VmError> {
|
||||||
if let Some(register) = self.register_stack.pop() {
|
if let Some(register) = self.register_stack.pop() {
|
||||||
let value = register.ok_or(VmError::EmptyRegister {
|
let value = register.ok_or(VmError::EmptyRegister {
|
||||||
index: self.register_stack.len().saturating_sub(1),
|
index: self.register_stack.len().saturating_sub(1),
|
||||||
|
@ -39,7 +39,7 @@ fn add_assign() {
|
|||||||
(Instruction::r#return(), Span(24, 24))
|
(Instruction::r#return(), Span(24, 24))
|
||||||
],
|
],
|
||||||
vec![Value::integer(1), Value::integer(2)],
|
vec![Value::integer(1), Value::integer(2)],
|
||||||
vec![Local::new(Identifier::new("a"), true, 0, Some(0))]
|
vec![Local::new(Identifier::new("a"), None, true, 0, Some(0))]
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -105,11 +105,11 @@ fn block_scope() {
|
|||||||
Value::integer(1)
|
Value::integer(1)
|
||||||
],
|
],
|
||||||
vec![
|
vec![
|
||||||
Local::new(Identifier::new("a"), false, 0, Some(0)),
|
Local::new(Identifier::new("a"), None, false, 0, Some(0)),
|
||||||
Local::new(Identifier::new("b"), false, 1, Some(1)),
|
Local::new(Identifier::new("b"), None, false, 1, Some(1)),
|
||||||
Local::new(Identifier::new("c"), false, 2, Some(2)),
|
Local::new(Identifier::new("c"), None, false, 2, Some(2)),
|
||||||
Local::new(Identifier::new("d"), false, 1, Some(3)),
|
Local::new(Identifier::new("d"), None, false, 1, Some(3)),
|
||||||
Local::new(Identifier::new("e"), false, 0, Some(4)),
|
Local::new(Identifier::new("e"), None, false, 0, Some(4)),
|
||||||
]
|
]
|
||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
@ -148,7 +148,7 @@ fn define_local() {
|
|||||||
(Instruction::define_local(0, 0, false), Span(4, 5)),
|
(Instruction::define_local(0, 0, false), Span(4, 5)),
|
||||||
],
|
],
|
||||||
vec![Value::integer(42)],
|
vec![Value::integer(42)],
|
||||||
vec![Local::new(Identifier::new("x"), false, 0, Some(0))]
|
vec![Local::new(Identifier::new("x"), None, false, 0, Some(0))]
|
||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -197,7 +197,7 @@ fn divide_assign() {
|
|||||||
(Instruction::r#return(), Span(24, 24))
|
(Instruction::r#return(), Span(24, 24))
|
||||||
],
|
],
|
||||||
vec![Value::integer(2), Value::integer(2)],
|
vec![Value::integer(2), Value::integer(2)],
|
||||||
vec![Local::new(Identifier::new("a"), true, 0, Some(0))]
|
vec![Local::new(Identifier::new("a"), None, true, 0, Some(0))]
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -261,7 +261,7 @@ fn equality_assignment_long() {
|
|||||||
(Instruction::r#return(), Span(44, 44)),
|
(Instruction::r#return(), Span(44, 44)),
|
||||||
],
|
],
|
||||||
vec![Value::integer(4), Value::integer(4)],
|
vec![Value::integer(4), Value::integer(4)],
|
||||||
vec![Local::new(Identifier::new("a"), false, 0, Some(0))]
|
vec![Local::new(Identifier::new("a"), None, false, 0, Some(0))]
|
||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -290,7 +290,7 @@ fn equality_assignment_short() {
|
|||||||
(Instruction::r#return(), Span(17, 17)),
|
(Instruction::r#return(), Span(17, 17)),
|
||||||
],
|
],
|
||||||
vec![Value::integer(4), Value::integer(4)],
|
vec![Value::integer(4), Value::integer(4)],
|
||||||
vec![Local::new(Identifier::new("a"), false, 0, Some(0))]
|
vec![Local::new(Identifier::new("a"), None, false, 0, Some(0))]
|
||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -686,7 +686,7 @@ fn multiply_assign() {
|
|||||||
(Instruction::r#return(), Span(23, 23))
|
(Instruction::r#return(), Span(23, 23))
|
||||||
],
|
],
|
||||||
vec![Value::integer(2), Value::integer(3)],
|
vec![Value::integer(2), Value::integer(3)],
|
||||||
vec![Local::new(Identifier::new("a"), true, 0, Some(0)),]
|
vec![Local::new(Identifier::new("a"), None, true, 0, Some(0)),]
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -825,7 +825,7 @@ fn set_local() {
|
|||||||
(Instruction::r#return(), Span(25, 25)),
|
(Instruction::r#return(), Span(25, 25)),
|
||||||
],
|
],
|
||||||
vec![Value::integer(41), Value::integer(42)],
|
vec![Value::integer(41), Value::integer(42)],
|
||||||
vec![Local::new(Identifier::new("x"), true, 0, Some(0)),]
|
vec![Local::new(Identifier::new("x"), None, true, 0, Some(0)),]
|
||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -874,7 +874,7 @@ fn subtract_assign() {
|
|||||||
(Instruction::r#return(), Span(25, 25)),
|
(Instruction::r#return(), Span(25, 25)),
|
||||||
],
|
],
|
||||||
vec![Value::integer(42), Value::integer(2)],
|
vec![Value::integer(42), Value::integer(2)],
|
||||||
vec![Local::new(Identifier::new("x"), true, 0, Some(0)),]
|
vec![Local::new(Identifier::new("x"), None, true, 0, Some(0)),]
|
||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -901,8 +901,8 @@ fn variable_and() {
|
|||||||
],
|
],
|
||||||
vec![],
|
vec![],
|
||||||
vec![
|
vec![
|
||||||
Local::new(Identifier::new("a"), false, 0, Some(0)),
|
Local::new(Identifier::new("a"), None, false, 0, Some(0)),
|
||||||
Local::new(Identifier::new("b"), false, 0, Some(1)),
|
Local::new(Identifier::new("b"), None, false, 0, Some(1)),
|
||||||
]
|
]
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
@ -931,7 +931,7 @@ fn r#while() {
|
|||||||
(Instruction::r#return(), Span(42, 42)),
|
(Instruction::r#return(), Span(42, 42)),
|
||||||
],
|
],
|
||||||
vec![Value::integer(0), Value::integer(5), Value::integer(1),],
|
vec![Value::integer(0), Value::integer(5), Value::integer(1),],
|
||||||
vec![Local::new(Identifier::new("x"), true, 0, Some(0)),]
|
vec![Local::new(Identifier::new("x"), None, true, 0, Some(0)),]
|
||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user