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 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(&center(&instruction_display)); push_line(&center(&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(&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 { 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(&center(&local_display)); push_line(&center(&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,
} }
} }

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. /// 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,

View File

@ -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()?;
self.increment_register()?;
if self.current_register == register {
self.increment_register()?;
}
let (previous_instruction, previous_position) = self.chunk.get_last_instruction()?; 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( if let Operation::LoadConstant | Operation::LoadBoolean | Operation::Add =
Instruction::define_local(register, local_index, is_mutable), previous_instruction.operation()
position, {
); let register = previous_instruction.a();
self.allow(TokenKind::Semicolon)?; 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(()) 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(),
} }
} }
} }

View File

@ -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>>,

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() { 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),

View File

@ -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)),]
)), )),
); );