Add types to functions and improve calls
This commit is contained in:
parent
2527cc2de7
commit
2864bee057
@ -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,
|
||||
})
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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(())
|
||||
}
|
||||
|
||||
|
@ -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}")?;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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(),
|
||||
}
|
||||
};
|
||||
|
@ -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))
|
||||
|
@ -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) => {
|
||||
|
Loading…
Reference in New Issue
Block a user