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

View File

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

View File

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

View File

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

View File

@ -378,11 +378,11 @@ impl Vm {
} else {
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 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)?;
function_vm.stack.push(Register::Value(argument));
@ -392,13 +392,15 @@ impl Vm {
if let Some(value) = return_value {
self.set(function_index, value, position)?;
} else {
self.empty(function_index, position)?;
}
}
Operation::Return => {
let should_return_value = instruction.b_as_boolean();
let top_of_stack = (self.stack.len() - 1) as u8;
return if should_return_value {
let top_of_stack = (self.stack.len() - 1) as u8;
let value = self.empty(top_of_stack, position)?;
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) {
Ok(chunk) => println!(
"{}",
chunk
.disassembler("Dust CLI Input")
.styled(pretty_print)
.source(source)
.styled(styled)
.disassemble()
),
Err(error) => {