1
0

Continue implemnting functions; Begin adding types

This commit is contained in:
Jeff 2024-10-09 06:15:06 -04:00
parent bdc34cb10e
commit 259721f6cb
6 changed files with 295 additions and 166 deletions

View File

@ -3,7 +3,10 @@ use std::fmt::{self, Debug, Display, Formatter};
use colored::Colorize;
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)]
pub struct Chunk {
@ -214,18 +217,20 @@ impl Chunk {
pub fn declare_local(
&mut self,
identifier: Identifier,
mutable: bool,
r#type: Option<Type>,
is_mutable: bool,
register_index: u8,
position: Span,
) -> Result<u8, ChunkError> {
let starting_length = self.locals.len();
if starting_length + 1 > (u8::MAX as usize) {
Err(ChunkError::IdentifierOverflow { position })
Err(ChunkError::LocalOverflow { position })
} else {
self.locals.push(Local::new(
identifier,
mutable,
r#type,
is_mutable,
self.scope_depth,
Some(register_index),
));
@ -308,6 +313,7 @@ impl PartialEq for Chunk {
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct Local {
pub identifier: Identifier,
pub r#type: Option<Type>,
pub is_mutable: bool,
pub depth: usize,
pub register_index: Option<u8>,
@ -316,12 +322,14 @@ pub struct Local {
impl Local {
pub fn new(
identifier: Identifier,
r#type: Option<Type>,
mutable: bool,
depth: usize,
register_index: Option<u8>,
) -> Self {
Self {
identifier,
r#type,
is_mutable: mutable,
depth,
register_index,
@ -334,6 +342,7 @@ pub struct ChunkDisassembler<'a> {
chunk: &'a Chunk,
width: Option<usize>,
styled: bool,
indent: usize,
}
impl<'a> ChunkDisassembler<'a> {
@ -357,8 +366,8 @@ impl<'a> ChunkDisassembler<'a> {
"",
"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
@ -375,6 +384,7 @@ impl<'a> ChunkDisassembler<'a> {
chunk,
width: None,
styled: false,
indent: 0,
}
}
@ -390,6 +400,12 @@ impl<'a> ChunkDisassembler<'a> {
self
}
pub fn indent(&mut self, indent: usize) -> &mut Self {
self.indent = indent;
self
}
pub fn disassemble(&self) -> String {
let width = self.width.unwrap_or_else(Self::default_width);
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 push_line = |line: &str| {
for _ in 0..self.indent {
disassembly.push_str(" ");
}
disassembly.push_str(line);
};
let name_line = style(center(self.name));
disassembly.push_str(&name_line);
push_line(&name_line);
let info_line = center(&format!(
"{} 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 {
disassembly.push_str(&style(center(line)));
push_line(&style(center(line)));
}
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}"
);
disassembly.push_str(&center(&instruction_display));
push_line(&center(&instruction_display));
}
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() {
@ -474,17 +497,34 @@ impl<'a> ChunkDisassembler<'a> {
format!("{index:<5} {value_display:<trucated_length$}")
};
disassembly.push_str(&center(&constant_display));
push_line(&center(&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 {
disassembly.push_str(&style(center(line)));
push_line(&style(center(line)));
}
for (
index,
Local {
identifier,
r#type,
depth,
register_index,
is_mutable: mutable,
@ -496,11 +536,15 @@ impl<'a> ChunkDisassembler<'a> {
.map(|value| value.to_string())
.unwrap_or_else(|| "empty".to_string());
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!(
"{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(&center(&local_display));
push_line(&center(&local_display));
}
let expected_length = self.predict_length();
@ -573,7 +617,7 @@ pub enum ChunkError {
index: usize,
position: Span,
},
IdentifierOverflow {
LocalOverflow {
position: Span,
},
IdentifierNotFound {
@ -594,8 +638,8 @@ impl AnnotatedError for ChunkError {
ChunkError::ConstantOverflow { .. } => "Constant overflow",
ChunkError::ConstantIndexOutOfBounds { .. } => "Constant index out of bounds",
ChunkError::InstructionUnderflow { .. } => "Instruction underflow",
ChunkError::LocalIndexOutOfBounds { .. } => "Identifier index out of bounds",
ChunkError::IdentifierOverflow { .. } => "Identifier overflow",
ChunkError::LocalIndexOutOfBounds { .. } => "Local index out of bounds",
ChunkError::LocalOverflow { .. } => "Local overflow",
ChunkError::IdentifierNotFound { .. } => "Identifier not found",
}
}
@ -611,13 +655,13 @@ impl AnnotatedError for ChunkError {
}
ChunkError::InstructionUnderflow { .. } => None,
ChunkError::LocalIndexOutOfBounds { index, .. } => {
Some(format!("Identifier index: {}", index))
Some(format!("Local index: {}", index))
}
ChunkError::IdentifierNotFound { identifier, .. } => {
Some(format!("Identifier: {}", identifier))
}
ChunkError::IdentifierOverflow { .. } => Some("Identifier overflow".to_string()),
ChunkError::ConstantOverflow { .. } => Some("Constant overflow".to_string()),
ChunkError::LocalOverflow { .. } => None,
ChunkError::ConstantOverflow { .. } => None,
}
}
@ -629,7 +673,7 @@ impl AnnotatedError for ChunkError {
ChunkError::IdentifierNotFound { position, .. } => *position,
ChunkError::InstructionUnderflow { position, .. } => *position,
ChunkError::LocalIndexOutOfBounds { position, .. } => *position,
ChunkError::IdentifierOverflow { position, .. } => *position,
ChunkError::LocalOverflow { position, .. } => *position,
ChunkError::ConstantOverflow { position, .. } => *position,
}
}

View File

@ -93,6 +93,10 @@ impl<'src> Lexer<'src> {
}
}
pub fn skip_to(&mut self, position: usize) {
self.position = position;
}
/// Produce the next token.
pub fn next_token(&mut self) -> Result<(Token<'src>, Span), LexError> {
self.skip_whitespace();
@ -539,6 +543,7 @@ impl<'src> Lexer<'src> {
"loop" => Token::Loop,
"map" => Token::Map,
"mut" => Token::Mut,
"str" => Token::Str,
"struct" => Token::Struct,
"true" => Token::Boolean("true"),
"while" => Token::While,

View File

@ -8,7 +8,7 @@ use colored::Colorize;
use crate::{
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> {
@ -17,7 +17,11 @@ pub fn parse(source: &str) -> Result<Chunk, DustError> {
while !parser.is_eof() {
parser
.parse_statement(true)
.parse_statement(Allowed {
assignment: true,
explicit_return: false,
implicit_return: true,
})
.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> {
let (current_token, current_position) = lexer.next_token()?;
log::info!("Begin chunk");
log::info!(
"{} at {}",
"Begin chunk with {} at {}",
current_token.to_string().bold(),
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;
if current == 0 {
@ -140,8 +143,7 @@ impl<'src> Parser<'src> {
self.chunk.push_instruction(instruction, position);
}
fn emit_constant(&mut self, value: Value) -> Result<(), ParseError> {
let position = self.previous_position;
fn emit_constant(&mut self, value: Value, position: Span) -> Result<(), ParseError> {
let constant_index = self.chunk.push_constant(value, position)?;
self.emit_instruction(
@ -152,11 +154,7 @@ impl<'src> Parser<'src> {
Ok(())
}
fn parse_boolean(
&mut self,
_allow_assignment: bool,
_allow_return: bool,
) -> Result<(), ParseError> {
fn parse_boolean(&mut self, _: Allowed) -> Result<(), ParseError> {
let boolean_text = if let Token::Boolean(text) = self.current_token {
text
} else {
@ -171,7 +169,6 @@ impl<'src> Parser<'src> {
let boolean = boolean_text.parse::<bool>().unwrap();
self.advance()?;
self.emit_instruction(
Instruction::load_boolean(self.current_register, boolean, false),
position,
@ -180,11 +177,9 @@ impl<'src> Parser<'src> {
Ok(())
}
fn parse_byte(
&mut self,
_allow_assignment: bool,
_allow_return: bool,
) -> Result<(), ParseError> {
fn parse_byte(&mut self, _: Allowed) -> Result<(), ParseError> {
let position = self.current_position;
if let Token::Byte(text) = self.current_token {
self.advance()?;
@ -195,33 +190,29 @@ impl<'src> Parser<'src> {
})?;
let value = Value::byte(byte);
self.emit_constant(value)?;
self.emit_constant(value, position)?;
}
Ok(())
}
fn parse_character(
&mut self,
_allow_assignment: bool,
_allow_return: bool,
) -> Result<(), ParseError> {
fn parse_character(&mut self, _: Allowed) -> Result<(), ParseError> {
let position = self.current_position;
if let Token::Character(character) = self.current_token {
self.advance()?;
let value = Value::character(character);
self.emit_constant(value)?;
self.emit_constant(value, position)?;
}
Ok(())
}
fn parse_float(
&mut self,
_allow_assignment: bool,
_allow_return: bool,
) -> Result<(), ParseError> {
fn parse_float(&mut self, _: Allowed) -> Result<(), ParseError> {
let position = self.current_position;
if let Token::Float(text) = self.current_token {
self.advance()?;
@ -233,17 +224,15 @@ impl<'src> Parser<'src> {
})?;
let value = Value::float(float);
self.emit_constant(value)?;
self.emit_constant(value, position)?;
}
Ok(())
}
fn parse_integer(
&mut self,
_allow_assignment: bool,
_allow_return: bool,
) -> Result<(), ParseError> {
fn parse_integer(&mut self, _: Allowed) -> Result<(), ParseError> {
let position = self.current_position;
if let Token::Integer(text) = self.current_token {
self.advance()?;
@ -255,43 +244,33 @@ impl<'src> Parser<'src> {
})?;
let value = Value::integer(integer);
self.emit_constant(value)?;
self.emit_constant(value, position)?;
}
Ok(())
}
fn parse_string(
&mut self,
_allow_assignment: bool,
_allow_return: bool,
) -> Result<(), ParseError> {
fn parse_string(&mut self, _: Allowed) -> Result<(), ParseError> {
let position = self.current_position;
if let Token::String(text) = self.current_token {
self.advance()?;
let value = Value::string(text);
self.emit_constant(value)?;
self.emit_constant(value, position)?;
}
Ok(())
}
fn parse_grouped(
&mut self,
_allow_assignment: bool,
_allow_return: bool,
) -> Result<(), ParseError> {
fn parse_grouped(&mut self, _: Allowed) -> Result<(), ParseError> {
self.allow(TokenKind::LeftParenthesis)?;
self.parse(Precedence::Assignment)?; // Do not allow assignment
self.expect(TokenKind::RightParenthesis)
}
fn parse_unary(
&mut self,
_allow_assignment: bool,
_allow_return: bool,
) -> Result<(), ParseError> {
fn parse_unary(&mut self, _: Allowed) -> Result<(), ParseError> {
let operator = self.current_token;
let operator_position = self.current_position;
@ -428,6 +407,7 @@ impl<'src> Parser<'src> {
current
};
let mut new_instruction = match operator.kind() {
TokenKind::Plus => Instruction::add(register, left, right),
TokenKind::PlusEqual => Instruction::add(register, left, right),
@ -605,11 +585,7 @@ impl<'src> Parser<'src> {
Ok(())
}
fn parse_variable(
&mut self,
allow_assignment: bool,
_allow_return: bool,
) -> Result<(), ParseError> {
fn parse_variable(&mut self, allowed: Allowed) -> Result<(), ParseError> {
let token = self.current_token;
let start_position = self.current_position;
@ -617,7 +593,7 @@ impl<'src> Parser<'src> {
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
.chunk
.get_local(local_index, start_position)?
@ -687,16 +663,31 @@ impl<'src> Parser<'src> {
}
}
fn parse_block(
&mut self,
_allow_assignment: bool,
_allow_return: bool,
) -> Result<(), ParseError> {
self.expect(TokenKind::LeftCurlyBrace)?;
fn parse_type_from(&mut self, token: Token, position: Span) -> Result<Type, ParseError> {
match token {
Token::Bool => Ok(Type::Boolean),
Token::FloatKeyword => Ok(Type::Float),
Token::Int => Ok(Type::Integer),
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();
while !self.allow(TokenKind::RightCurlyBrace)? && !self.is_eof() {
self.parse_statement(_allow_return)?;
self.parse_statement(allowed)?;
}
self.chunk.end_scope();
@ -704,11 +695,7 @@ impl<'src> Parser<'src> {
Ok(())
}
fn parse_list(
&mut self,
_allow_assignment: bool,
_allow_return: bool,
) -> Result<(), ParseError> {
fn parse_list(&mut self, _: Allowed) -> Result<(), ParseError> {
let start = self.current_position.0;
self.advance()?;
@ -745,7 +732,8 @@ impl<'src> Parser<'src> {
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();
self.advance()?;
@ -762,7 +750,7 @@ impl<'src> Parser<'src> {
}
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()?;
@ -780,28 +768,25 @@ impl<'src> Parser<'src> {
if self.allow(TokenKind::Else)? {
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 {
self.parse_block(allow_assignment, allow_return)?;
self.parse_block(allowed)?;
}
}
Ok(())
}
fn parse_while(
&mut self,
allow_assignment: bool,
allow_return: bool,
) -> Result<(), ParseError> {
fn parse_while(&mut self, mut allowed: Allowed) -> Result<(), ParseError> {
self.advance()?;
allowed.implicit_return = false;
let jump_start = self.chunk.len();
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_distance = jump_end.abs_diff(jump_start) as u8;
@ -847,20 +832,27 @@ impl<'src> Parser<'src> {
Ok(())
}
fn parse_statement(&mut self, allow_return: bool) -> Result<(), ParseError> {
fn parse_statement(&mut self, allowed: Allowed) -> Result<(), ParseError> {
match self.current_token {
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)?;
}
Token::LeftCurlyBrace => {
self.parse_block(true, true)?;
self.parse_block(allowed)?;
self.allow(TokenKind::Semicolon)?;
}
_ => {
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);
}
}
@ -869,19 +861,15 @@ impl<'src> Parser<'src> {
Ok(())
}
fn parse_let_statement(
&mut self,
allow_assignment: bool,
_allow_return: bool,
) -> Result<(), ParseError> {
if !allow_assignment {
fn parse_let_statement(&mut self, allowed: Allowed) -> Result<(), ParseError> {
if !allowed.assignment {
return Err(ParseError::ExpectedExpression {
found: self.current_token.to_owned(),
position: self.current_position,
});
}
self.allow(TokenKind::Let)?;
self.expect(TokenKind::Let)?;
let is_mutable = self.allow(TokenKind::Mut)?;
let position = self.current_position;
@ -896,40 +884,104 @@ impl<'src> Parser<'src> {
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.parse_expression()?;
self.increment_register()?;
if self.current_register == register {
self.increment_register()?;
}
let (previous_instruction, previous_position) = self.chunk.get_last_instruction()?;
let register = previous_instruction.a();
let local_index =
self.chunk
.declare_local(identifier, is_mutable, register, *previous_position)?;
self.emit_instruction(
Instruction::define_local(register, local_index, is_mutable),
position,
);
self.allow(TokenKind::Semicolon)?;
if let Operation::LoadConstant | Operation::LoadBoolean | Operation::Add =
previous_instruction.operation()
{
let register = previous_instruction.a();
let local_index = self.chunk.declare_local(
identifier,
explicit_type,
is_mutable,
register,
*previous_position,
)?;
self.emit_instruction(
Instruction::define_local(register, local_index, is_mutable),
position,
);
}
Ok(())
}
fn parse_function(
&mut self,
_allow_assignment: bool,
_allow_return: bool,
) -> Result<(), ParseError> {
self.advance()?;
self.expect(TokenKind::LeftParenthesis)?;
fn parse_function(&mut self, _: Allowed) -> Result<(), ParseError> {
let function_start = self.current_position.0;
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_position = function_parser.previous_position;
@ -937,8 +989,10 @@ impl<'src> Parser<'src> {
self.current_position = function_parser.current_position;
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(())
}
@ -954,7 +1008,14 @@ impl<'src> Parser<'src> {
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;
}
@ -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>;
#[derive(Debug, Clone, Copy)]
@ -1374,19 +1442,19 @@ impl AnnotatedError for ParseError {
fn details(&self) -> Option<String> {
match self {
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 {
expected, found, ..
} => Some(format!("Expected \"{expected}\", found \"{found}\"")),
} => Some(format!("Expected {expected} but found {found}")),
Self::ExpectedTokenMultiple {
expected, found, ..
} => {
let mut details = String::from("Expected");
for (index, token) in expected.iter().enumerate() {
details.push_str(&format!(" \"{token}\""));
details.push_str(&format!(" {token}"));
if index < expected.len() - 2 {
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)
}
Self::ExpectedMutableVariable { found, .. } => {
Some(format!("Expected mutable variable, found \"{found}\""))
Some(format!("Expected mutable variable, found {found}"))
}
Self::InvalidAssignmentTarget { found, .. } => {
Some(format!("Invalid assignment target, found \"{found}\""))
Some(format!("Invalid assignment target, found {found}"))
}
Self::UndefinedVariable { identifier, .. } => {
Some(format!("Undefined variable \"{identifier}\""))
Some(format!("Undefined variable {identifier}"))
}
Self::RegisterOverflow { .. } => None,
Self::RegisterUnderflow { .. } => None,
@ -1430,10 +1498,10 @@ impl AnnotatedError for ParseError {
Self::UndefinedVariable { position, .. } => *position,
Self::RegisterOverflow { position } => *position,
Self::RegisterUnderflow { position } => *position,
Self::Chunk(error) => error.position(),
Self::Lex(error) => error.position(),
Self::ParseFloatError { position, .. } => *position,
Self::ParseIntError { position, .. } => *position,
Self::Chunk(error) => error.position(),
Self::Lex(error) => error.position(),
}
}
}

View File

@ -45,7 +45,7 @@ use serde::{
Deserialize, Deserializer, Serialize, Serializer,
};
use crate::{Chunk, EnumType, FunctionType, Identifier, RangeableType, StructType, Type};
use crate::{Chunk, EnumType, Identifier, RangeableType, StructType, Type};
/// 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 {
matches!(
self,
@ -1452,6 +1460,10 @@ pub struct Function {
}
impl Function {
pub fn body(&self) -> &Chunk {
&self.body
}
pub fn call(
self,
_type_arguments: Option<Vec<Type>>,

View File

@ -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() {
let value = register.ok_or(VmError::EmptyRegister {
index: self.register_stack.len().saturating_sub(1),

View File

@ -39,7 +39,7 @@ fn add_assign() {
(Instruction::r#return(), Span(24, 24))
],
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)
],
vec![
Local::new(Identifier::new("a"), false, 0, Some(0)),
Local::new(Identifier::new("b"), false, 1, Some(1)),
Local::new(Identifier::new("c"), false, 2, Some(2)),
Local::new(Identifier::new("d"), false, 1, Some(3)),
Local::new(Identifier::new("e"), false, 0, Some(4)),
Local::new(Identifier::new("a"), None, false, 0, Some(0)),
Local::new(Identifier::new("b"), None, false, 1, Some(1)),
Local::new(Identifier::new("c"), None, false, 2, Some(2)),
Local::new(Identifier::new("d"), None, false, 1, Some(3)),
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)),
],
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))
],
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)),
],
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)),
],
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))
],
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)),
],
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)),
],
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![
Local::new(Identifier::new("a"), false, 0, Some(0)),
Local::new(Identifier::new("b"), false, 0, Some(1)),
Local::new(Identifier::new("a"), None, false, 0, Some(0)),
Local::new(Identifier::new("b"), None, false, 0, Some(1)),
]
))
);
@ -931,7 +931,7 @@ fn r#while() {
(Instruction::r#return(), Span(42, 42)),
],
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)),]
)),
);