1
0

Add types to functions and improve calls

This commit is contained in:
Jeff 2024-10-12 20:19:21 -04:00
parent 2527cc2de7
commit 2864bee057
7 changed files with 153 additions and 57 deletions

View File

@ -132,6 +132,10 @@ impl Chunk {
operations operations
} }
pub fn constants(&self) -> &[Option<Value>] {
&self.constants
}
pub fn get_constant(&self, index: u8, position: Span) -> Result<&Value, ChunkError> { pub fn get_constant(&self, index: u8, position: Span) -> Result<&Value, ChunkError> {
let index = index as usize; let index = index as usize;
@ -333,6 +337,7 @@ impl Local {
pub struct ChunkDisassembler<'a> { pub struct ChunkDisassembler<'a> {
name: &'a str, name: &'a str,
chunk: &'a Chunk, chunk: &'a Chunk,
source: Option<&'a str>,
width: usize, width: usize,
styled: bool, styled: bool,
indent: usize, indent: usize,
@ -375,12 +380,19 @@ impl<'a> ChunkDisassembler<'a> {
Self { Self {
name, name,
chunk, chunk,
source: None,
width: Self::default_width(), width: Self::default_width(),
styled: false, styled: false,
indent: 0, indent: 0,
} }
} }
pub fn source(&mut self, source: &'a str) -> &mut Self {
self.source = Some(source);
self
}
pub fn width(&mut self, width: usize) -> &mut Self { pub fn width(&mut self, width: usize) -> &mut Self {
self.width = width; self.width = width;
@ -439,6 +451,17 @@ impl<'a> ChunkDisassembler<'a> {
push(self.name, self.styled); push(self.name, self.styled);
if let Some(source) = self.source {
let length = if source.len() < self.width {
source.len() - 2
} else {
self.width - 2
};
let source_line = format!("\"{}\"", &source[..length]).dimmed();
push(&source_line, false);
}
let info_line = format!( let info_line = format!(
"{} instructions, {} constants, {} locals", "{} instructions, {} constants, {} locals",
self.chunk.instructions.len(), self.chunk.instructions.len(),
@ -518,10 +541,7 @@ impl<'a> ChunkDisassembler<'a> {
for (index, value_option) in self.chunk.constants.iter().enumerate() { for (index, value_option) in self.chunk.constants.iter().enumerate() {
let value_display = value_option let value_display = value_option
.as_ref() .as_ref()
.map(|value| match value { .map(|value| value.to_string())
Value::Primitive(value_data) => value_data.to_string(),
Value::Object(_) => "object".to_string(),
})
.unwrap_or("empty".to_string()); .unwrap_or("empty".to_string());
let trucated_length = 8; let trucated_length = 8;
let with_elipsis = trucated_length - 3; let with_elipsis = trucated_length - 3;
@ -535,15 +555,16 @@ impl<'a> ChunkDisassembler<'a> {
if let Some(function_disassembly) = if let Some(function_disassembly) =
value_option.as_ref().and_then(|value| match value { value_option.as_ref().and_then(|value| match value {
Value::Primitive(value_data) => value_data.as_function().map(|function| { Value::Function(function) => Some(
function function
.chunk .chunk()
.disassembler("function") .disassembler("function")
.styled(self.styled) .styled(self.styled)
.indent(self.indent + 1) .indent(self.indent + 1)
.width(self.width) .width(self.width)
.disassemble() .disassemble(),
}), ),
Value::Primitive(_) => None,
Value::Object(_) => None, Value::Object(_) => None,
}) })
{ {

View File

@ -95,6 +95,10 @@ impl<'src> Lexer<'src> {
} }
} }
pub fn source(&self) -> &'src str {
self.source
}
pub fn skip_to(&mut self, position: usize) { pub fn skip_to(&mut self, position: usize) {
self.position = position; self.position = position;
} }

View File

@ -1,6 +1,6 @@
use std::{ use std::{
fmt::{self, Display, Formatter}, fmt::{self, Display, Formatter},
mem::replace, mem::{replace, take},
num::{ParseFloatError, ParseIntError}, num::{ParseFloatError, ParseIntError},
}; };
@ -8,8 +8,8 @@ use colored::Colorize;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{ use crate::{
AnnotatedError, Chunk, ChunkError, DustError, Identifier, Instruction, LexError, Lexer, AnnotatedError, Chunk, ChunkError, DustError, FunctionType, Identifier, Instruction, LexError,
Operation, Span, Token, TokenKind, TokenOwned, Type, Value, Lexer, Operation, Span, Token, TokenKind, TokenOwned, Type, Value,
}; };
pub fn parse(source: &str) -> Result<Chunk, DustError> { pub fn parse(source: &str) -> Result<Chunk, DustError> {
@ -36,12 +36,17 @@ pub fn parse(source: &str) -> Result<Chunk, DustError> {
pub struct Parser<'src> { pub struct Parser<'src> {
chunk: Chunk, chunk: Chunk,
lexer: Lexer<'src>, lexer: Lexer<'src>,
current_register: u8, current_register: u8,
current_token: Token<'src>, current_token: Token<'src>,
current_position: Span, current_position: Span,
previous_token: Token<'src>, previous_token: Token<'src>,
previous_position: Span, previous_position: Span,
parsed_expression: bool, parsed_expression: bool,
latest_value_type: Option<Type>,
} }
impl<'src> Parser<'src> { impl<'src> Parser<'src> {
@ -63,6 +68,7 @@ impl<'src> Parser<'src> {
previous_token: Token::Eof, previous_token: Token::Eof,
previous_position: Span(0, 0), previous_position: Span(0, 0),
parsed_expression: false, parsed_expression: false,
latest_value_type: None,
}) })
} }
@ -142,6 +148,8 @@ impl<'src> Parser<'src> {
} }
fn emit_constant(&mut self, value: Value, position: Span) -> Result<(), ParseError> { fn emit_constant(&mut self, value: Value, position: Span) -> Result<(), ParseError> {
self.latest_value_type = Some(value.r#type());
let constant_index = self.chunk.push_constant(value, position)?; let constant_index = self.chunk.push_constant(value, position)?;
self.emit_instruction( self.emit_instruction(
@ -165,6 +173,7 @@ impl<'src> Parser<'src> {
position, position,
); );
self.latest_value_type = Some(Type::Boolean);
self.parsed_expression = true; self.parsed_expression = true;
Ok(()) Ok(())
@ -954,34 +963,26 @@ impl<'src> Parser<'src> {
} }
fn parse_return(&mut self, allowed: Allowed) -> Result<(), ParseError> { fn parse_return(&mut self, allowed: Allowed) -> Result<(), ParseError> {
let start = self.current_position.0;
if !allowed.explicit_return { if !allowed.explicit_return {
return Err(ParseError::UnexpectedReturn { return Err(ParseError::UnexpectedReturn {
position: self.current_position, position: self.current_position,
}); });
} }
let start = self.current_position.0;
self.advance()?; self.advance()?;
let has_return_value = if !matches!( let has_return_value = if matches!(
self.current_token, self.current_token,
Token::Semicolon | Token::RightCurlyBrace Token::Semicolon | Token::RightCurlyBrace
) { ) {
self.parse_statement( false
Allowed { } else {
assignment: false, self.parse_expression()?;
explicit_return: false,
implicit_return: false,
},
Context::None,
)?;
true true
} else {
false
}; };
let end = self.current_position.1; let end = self.current_position.1;
self.emit_instruction(Instruction::r#return(has_return_value), Span(start, end)); self.emit_instruction(Instruction::r#return(has_return_value), Span(start, end));
@ -1060,6 +1061,8 @@ impl<'src> Parser<'src> {
function_parser.expect(Token::LeftParenthesis)?; function_parser.expect(Token::LeftParenthesis)?;
let mut value_parameters: Option<Vec<(Identifier, Type)>> = None;
while function_parser.current_token != Token::RightParenthesis { while function_parser.current_token != Token::RightParenthesis {
let start = function_parser.current_position.0; let start = function_parser.current_position.0;
let is_mutable = function_parser.allow(Token::Mut)?; let is_mutable = function_parser.allow(Token::Mut)?;
@ -1086,6 +1089,12 @@ impl<'src> Parser<'src> {
let end = function_parser.current_position.1; let end = function_parser.current_position.1;
if let Some(value_parameters) = value_parameters.as_mut() {
value_parameters.push((parameter.clone(), r#type.clone()));
} else {
value_parameters = Some(vec![(parameter.clone(), r#type.clone())]);
};
function_parser.chunk.declare_local( function_parser.chunk.declare_local(
parameter, parameter,
Some(r#type), Some(r#type),
@ -1119,7 +1128,13 @@ impl<'src> Parser<'src> {
self.current_token = function_parser.current_token; self.current_token = function_parser.current_token;
self.current_position = function_parser.current_position; self.current_position = function_parser.current_position;
let function = Value::function(function_parser.chunk); let return_type = take(&mut self.latest_value_type).map(Box::new);
let function_type = FunctionType {
type_parameters: None,
value_parameters,
return_type,
};
let function = Value::function(function_parser.chunk, function_type);
let function_end = self.current_position.1; let function_end = self.current_position.1;
self.lexer.skip_to(function_end); self.lexer.skip_to(function_end);
@ -1131,6 +1146,17 @@ impl<'src> Parser<'src> {
} }
fn parse_call(&mut self) -> Result<(), ParseError> { fn parse_call(&mut self) -> Result<(), ParseError> {
let last_instruction = self.chunk.get_last_instruction()?.0;
if !last_instruction.is_expression() {
return Err(ParseError::ExpectedExpression {
found: self.previous_token.to_owned(),
position: self.previous_position,
});
}
let start = self.current_position.0;
self.advance()?; self.advance()?;
let function_register = self.current_register; let function_register = self.current_register;
@ -1143,14 +1169,7 @@ impl<'src> Parser<'src> {
let register = self.current_register; let register = self.current_register;
self.parse( self.parse_expression()?;
Precedence::None,
Allowed {
assignment: false,
explicit_return: false,
implicit_return: false,
},
)?;
if self.current_register == register { if self.current_register == register {
return Err(ParseError::ExpectedExpression { return Err(ParseError::ExpectedExpression {
@ -1162,11 +1181,15 @@ impl<'src> Parser<'src> {
argument_count += 1; argument_count += 1;
} }
let end = self.current_position.1;
self.emit_instruction( self.emit_instruction(
Instruction::call(function_register, argument_count), Instruction::call(function_register, argument_count),
self.current_position, Span(start, end),
); );
self.parsed_expression = true;
Ok(()) Ok(())
} }

View File

@ -191,20 +191,17 @@ impl Type {
} }
( (
Type::Function(FunctionType { Type::Function(FunctionType {
name: left_name,
type_parameters: left_type_parameters, type_parameters: left_type_parameters,
value_parameters: left_value_parameters, value_parameters: left_value_parameters,
return_type: left_return, return_type: left_return,
}), }),
Type::Function(FunctionType { Type::Function(FunctionType {
name: right_name,
type_parameters: right_type_parameters, type_parameters: right_type_parameters,
value_parameters: right_value_parameters, value_parameters: right_value_parameters,
return_type: right_return, return_type: right_return,
}), }),
) => { ) => {
if left_name != right_name if left_return != right_return
|| left_return != right_return
|| left_type_parameters != right_type_parameters || left_type_parameters != right_type_parameters
|| left_value_parameters != right_value_parameters || left_value_parameters != right_value_parameters
{ {
@ -419,7 +416,6 @@ impl Ord for Type {
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct FunctionType { pub struct FunctionType {
pub name: Identifier,
pub type_parameters: Option<Vec<Identifier>>, pub type_parameters: Option<Vec<Identifier>>,
pub value_parameters: Option<Vec<(Identifier, Type)>>, pub value_parameters: Option<Vec<(Identifier, Type)>>,
pub return_type: Option<Box<Type>>, pub return_type: Option<Box<Type>>,
@ -433,11 +429,11 @@ impl Display for FunctionType {
write!(f, "<")?; write!(f, "<")?;
for (index, type_parameter) in type_parameters.iter().enumerate() { for (index, type_parameter) in type_parameters.iter().enumerate() {
write!(f, "{type_parameter}")?; if index > 0 {
if index != type_parameters.len() - 1 {
write!(f, ", ")?; write!(f, ", ")?;
} }
write!(f, "{type_parameter}")?;
} }
write!(f, ">")?; write!(f, ">")?;
@ -447,11 +443,11 @@ impl Display for FunctionType {
if let Some(value_parameters) = &self.value_parameters { if let Some(value_parameters) = &self.value_parameters {
for (index, (identifier, r#type)) in value_parameters.iter().enumerate() { for (index, (identifier, r#type)) in value_parameters.iter().enumerate() {
write!(f, "{identifier}: {type}")?; if index > 0 {
if index != value_parameters.len() - 1 {
write!(f, ", ")?; write!(f, ", ")?;
} }
write!(f, "{identifier}: {type}")?;
} }
} }

View File

@ -31,7 +31,7 @@ use serde::{
Deserialize, Deserializer, Serialize, Serializer, Deserialize, Deserializer, Serialize, Serializer,
}; };
use crate::{Chunk, RangeableType, Span, Type, Vm, VmError}; use crate::{Chunk, FunctionType, RangeableType, Span, Type, Vm, VmError};
/// Dust value representation /// Dust value representation
/// ///
@ -39,6 +39,7 @@ use crate::{Chunk, RangeableType, Span, Type, Vm, VmError};
#[derive(Debug, Eq, PartialEq, PartialOrd, Ord)] #[derive(Debug, Eq, PartialEq, PartialOrd, Ord)]
pub enum Value { pub enum Value {
Primitive(Primitive), Primitive(Primitive),
Function(Function),
Object(Object), Object(Object),
} }
@ -59,8 +60,11 @@ impl Value {
Value::Primitive(Primitive::Float(value)) Value::Primitive(Primitive::Float(value))
} }
pub fn function(body: Chunk) -> Self { pub fn function(body: Chunk, r#type: FunctionType) -> Self {
Value::Primitive(Primitive::Function(Function { chunk: body })) Value::Primitive(Primitive::Function(Function {
chunk: body,
r#type: Type::Function(r#type),
}))
} }
pub fn integer<T: Into<i64>>(into_i64: T) -> Self { pub fn integer<T: Into<i64>>(into_i64: T) -> Self {
@ -79,9 +83,14 @@ impl Value {
Value::Primitive(Primitive::String(to_string.to_string())) Value::Primitive(Primitive::String(to_string.to_string()))
} }
pub fn is_function(&self) -> bool {
matches!(self, Value::Function(_))
}
pub fn r#type(&self) -> Type { pub fn r#type(&self) -> Type {
match self { match self {
Value::Primitive(data) => data.r#type(), Value::Primitive(data) => data.r#type(),
Value::Function(function) => function.r#type().clone(),
Value::Object(Object::List { Value::Object(Object::List {
start, start,
end, end,
@ -231,6 +240,7 @@ impl Value {
pub fn display(&self, vm: &Vm, position: Span) -> Result<String, ValueError> { pub fn display(&self, vm: &Vm, position: Span) -> Result<String, ValueError> {
match self { match self {
Value::Primitive(primitive) => Ok(primitive.to_string()), Value::Primitive(primitive) => Ok(primitive.to_string()),
Value::Function(function) => Ok(function.to_string()),
Value::Object(object) => object.display(vm, position), Value::Object(object) => object.display(vm, position),
} }
} }
@ -290,6 +300,7 @@ impl Clone for Value {
match self { match self {
Value::Primitive(data) => Value::Primitive(data.clone()), Value::Primitive(data) => Value::Primitive(data.clone()),
Value::Function(function) => Value::Function(function.clone()),
Value::Object(object) => Value::Object(object.clone()), Value::Object(object) => Value::Object(object.clone()),
} }
} }
@ -299,7 +310,8 @@ impl Display for Value {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self { match self {
Value::Primitive(primitive) => write!(f, "{primitive}"), Value::Primitive(primitive) => write!(f, "{primitive}"),
Value::Object(_) => write!(f, "object"), Value::Function(function) => write!(f, "{function}"),
Value::Object(object) => write!(f, "{object}"),
} }
} }
} }
@ -308,6 +320,7 @@ impl Serialize for Value {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> { fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
match self { match self {
Value::Primitive(data) => data.serialize(serializer), Value::Primitive(data) => data.serialize(serializer),
Value::Function(function) => function.serialize(serializer),
Value::Object(object) => object.serialize(serializer), Value::Object(object) => object.serialize(serializer),
} }
} }
@ -371,7 +384,7 @@ impl Primitive {
Primitive::Boolean(_) => Type::Boolean, Primitive::Boolean(_) => Type::Boolean,
Primitive::Byte(_) => Type::Byte, Primitive::Byte(_) => Type::Byte,
Primitive::Character(_) => Type::Character, Primitive::Character(_) => Type::Character,
Primitive::Function(Function { .. }) => todo!(), Primitive::Function(Function { r#type, .. }) => r#type.clone(),
Primitive::Float(_) => Type::Float, Primitive::Float(_) => Type::Float,
Primitive::Integer(_) => Type::Integer, Primitive::Integer(_) => Type::Integer,
Primitive::Range(range) => range.r#type(), Primitive::Range(range) => range.r#type(),
@ -643,7 +656,32 @@ impl Ord for Primitive {
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct Function { pub struct Function {
pub chunk: Chunk, chunk: Chunk,
r#type: Type,
}
impl Function {
pub fn new(chunk: Chunk, r#type: Type) -> Self {
Self { chunk, r#type }
}
pub fn chunk(&self) -> &Chunk {
&self.chunk
}
pub fn take_chunk(self) -> Chunk {
self.chunk
}
pub fn r#type(&self) -> &Type {
&self.r#type
}
}
impl Display for Function {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "{}", self.r#type)
}
} }
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
@ -894,6 +932,16 @@ impl Object {
} }
} }
impl Display for Object {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Object::List { start, end, .. } => {
write!(f, "List [R{}..=R{}]", start, end)
}
}
}
}
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum ValueError { pub enum ValueError {
CannotAdd(Value, Value), CannotAdd(Value, Value),
@ -918,6 +966,7 @@ impl Display for ValueError {
let get_value_display = |value: &Value| -> String { let get_value_display = |value: &Value| -> String {
match value { match value {
Value::Primitive(primitive) => primitive.to_string(), Value::Primitive(primitive) => primitive.to_string(),
Value::Function(function) => function.to_string(),
Value::Object(_) => "Object".to_string(), Value::Object(_) => "Object".to_string(),
} }
}; };

View File

@ -378,11 +378,11 @@ impl Vm {
} else { } else {
todo!() todo!()
}; };
let mut function_vm = Vm::new(function.chunk); let mut function_vm = Vm::new(function.take_chunk());
let first_argument_index = function_index + 1; let first_argument_index = function_index + 1;
let last_argument_index = first_argument_index + argument_count; let last_argument_index = first_argument_index + argument_count;
for argument_index in first_argument_index..=last_argument_index { for argument_index in first_argument_index..last_argument_index {
let argument = self.empty(argument_index, position)?; let argument = self.empty(argument_index, position)?;
function_vm.stack.push(Register::Value(argument)); function_vm.stack.push(Register::Value(argument));
@ -392,13 +392,15 @@ impl Vm {
if let Some(value) = return_value { if let Some(value) = return_value {
self.set(function_index, value, position)?; self.set(function_index, value, position)?;
} else {
self.empty(function_index, position)?;
} }
} }
Operation::Return => { Operation::Return => {
let should_return_value = instruction.b_as_boolean(); let should_return_value = instruction.b_as_boolean();
let top_of_stack = (self.stack.len() - 1) as u8;
return if should_return_value { return if should_return_value {
let top_of_stack = (self.stack.len() - 1) as u8;
let value = self.empty(top_of_stack, position)?; let value = self.empty(top_of_stack, position)?;
Ok(Some(value)) Ok(Some(value))

View File

@ -60,13 +60,14 @@ fn main() {
} }
} }
fn parse_and_display(source: &str, pretty_print: bool) { fn parse_and_display(source: &str, styled: bool) {
match parse(source) { match parse(source) {
Ok(chunk) => println!( Ok(chunk) => println!(
"{}", "{}",
chunk chunk
.disassembler("Dust CLI Input") .disassembler("Dust CLI Input")
.styled(pretty_print) .source(source)
.styled(styled)
.disassemble() .disassemble()
), ),
Err(error) => { Err(error) => {