From 34cea3518da7c07ba53bffefd75cfe4d84db3a5b Mon Sep 17 00:00:00 2001 From: Jeff Date: Sat, 22 Jun 2024 17:17:35 -0400 Subject: [PATCH] Begin refactoring built-ins --- dust-lang/src/abstract_tree/assignment.rs | 91 ++++------ .../src/abstract_tree/built_in_function.rs | 118 +++++++++++++ .../abstract_tree/built_in_function_call.rs | 165 ------------------ dust-lang/src/abstract_tree/expression.rs | 30 +--- dust-lang/src/abstract_tree/mod.rs | 4 +- dust-lang/src/abstract_tree/value_node.rs | 23 +-- dust-lang/src/error.rs | 4 + dust-lang/src/lexer.rs | 3 - dust-lang/src/value.rs | 16 ++ 9 files changed, 193 insertions(+), 261 deletions(-) create mode 100644 dust-lang/src/abstract_tree/built_in_function.rs delete mode 100644 dust-lang/src/abstract_tree/built_in_function_call.rs diff --git a/dust-lang/src/abstract_tree/assignment.rs b/dust-lang/src/abstract_tree/assignment.rs index bd14127..ba228c9 100644 --- a/dust-lang/src/abstract_tree/assignment.rs +++ b/dust-lang/src/abstract_tree/assignment.rs @@ -70,60 +70,6 @@ impl AbstractNode for Assignment { context.set_type(self.identifier.node.clone(), statement_type.clone())?; } - Ok(()) - } - - fn validate(&self, context: &Context, manage_memory: bool) -> Result<(), ValidationError> { - let relevant_statement = self.statement.last_evaluated_statement(); - let statement_type = if let Some(r#type) = relevant_statement.expected_type(context)? { - r#type - } else { - return Err(ValidationError::CannotAssignToNone( - self.statement.position(), - )); - }; - - if let Some(constructor) = &self.constructor { - let r#type = constructor.clone().construct(&context)?; - - r#type - .check(&statement_type) - .map_err(|conflict| ValidationError::TypeCheck { - conflict, - actual_position: self.statement.position(), - expected_position: Some(constructor.position()), - })?; - - context.set_type(self.identifier.node.clone(), r#type.clone())?; - } else { - context.set_type(self.identifier.node.clone(), statement_type.clone())?; - } - - self.statement.validate(context, manage_memory)?; - - if let ( - Some(TypeConstructor::Invokation(TypeInvokationConstructor { - identifier, - type_arguments, - })), - Statement::Expression(Expression::Value(_)), - Type::Enum { - type_parameters, .. - }, - ) = (&self.constructor, relevant_statement, &statement_type) - { - if let (Some(parameters), Some(arguments)) = (type_parameters, type_arguments) { - if parameters.len() != arguments.len() { - return Err(ValidationError::FullTypeNotKnown { - identifier: identifier.node.clone(), - position: self.constructor.clone().unwrap().position(), - }); - } - } - - return Ok(()); - } - if let (Some(constructor), Statement::Expression(Expression::FunctionCall(function_call))) = (&self.constructor, relevant_statement) { @@ -161,6 +107,43 @@ impl AbstractNode for Assignment { Ok(()) } + fn validate(&self, context: &Context, manage_memory: bool) -> Result<(), ValidationError> { + let relevant_statement = self.statement.last_evaluated_statement(); + let statement_type = if let Some(r#type) = relevant_statement.expected_type(context)? { + r#type + } else { + return Err(ValidationError::CannotAssignToNone( + self.statement.position(), + )); + }; + + self.statement.validate(context, manage_memory)?; + + if let ( + Some(TypeConstructor::Invokation(TypeInvokationConstructor { + identifier, + type_arguments, + })), + Type::Enum { + type_parameters, .. + }, + ) = (&self.constructor, &statement_type) + { + if let (Some(parameters), Some(arguments)) = (type_parameters, type_arguments) { + if parameters.len() != arguments.len() { + return Err(ValidationError::FullTypeNotKnown { + identifier: identifier.node.clone(), + position: self.constructor.clone().unwrap().position(), + }); + } + } + + return Ok(()); + } + + Ok(()) + } + fn evaluate( self, context: &Context, diff --git a/dust-lang/src/abstract_tree/built_in_function.rs b/dust-lang/src/abstract_tree/built_in_function.rs new file mode 100644 index 0000000..9067427 --- /dev/null +++ b/dust-lang/src/abstract_tree/built_in_function.rs @@ -0,0 +1,118 @@ +use std::{ + array, + fs::read_to_string, + io::{stdin, stdout, Write}, + slice, + sync::OnceLock, + thread, + time::Duration, +}; + +use rayon::iter::IntoParallelIterator; +use serde::{Deserialize, Serialize}; + +use crate::{ + context::Context, + error::{RuntimeError, ValidationError}, + identifier::Identifier, + value::{Function, ValueInner}, + Value, +}; + +use super::{ + AbstractNode, Block, Evaluation, Expression, Statement, Type, TypeConstructor, WithPos, +}; + +pub enum BuiltInExpression { + Length(BuiltInFunctionCall), +} + +pub struct BuiltInFunctionCall { + function: F, + context: Context, +} + +pub trait FunctionLogic { + fn type_parameters() -> Option>; + fn value_parameters() -> impl IntoIterator; + fn return_type() -> Type; + fn call( + self, + context: &Context, + manage_memory: bool, + ) -> Result, RuntimeError>; +} + +impl AbstractNode for BuiltInFunctionCall { + fn define_types(&self, _: &Context) -> Result<(), ValidationError> { + if let Some(type_arguments) = F::type_parameters() { + for (identifier, r#type) in type_arguments { + self.context.set_type(identifier, r#type)?; + } + } + + Ok(()) + } + + fn validate(&self, _context: &Context, _manage_memory: bool) -> Result<(), ValidationError> { + Ok(()) + } + + fn evaluate( + self, + _: &Context, + manage_memory: bool, + ) -> Result, RuntimeError> { + self.function.call(&self.context, manage_memory) + } + + fn expected_type(&self, _: &Context) -> Result, ValidationError> { + Ok(Some(F::return_type())) + } +} + +pub struct Length { + argument: Expression, +} + +impl FunctionLogic for Length { + fn type_parameters() -> Option> { + None::> + } + + fn value_parameters() -> impl IntoIterator { + [(Identifier::new("list"))].into_iter() + } + + fn return_type() -> Type { + todo!() + } + + fn call( + self, + context: &Context, + manage_memory: bool, + ) -> Result, RuntimeError> { + let position = self.argument.position(); + let evaluation = self.argument.evaluate(context, manage_memory)?; + let value = if let Some(Evaluation::Return(value)) = evaluation { + value + } else { + return Err(RuntimeError::ValidationFailure( + ValidationError::ExpectedExpression(position), + )); + }; + let list = if let ValueInner::List(list) = value.inner().as_ref() { + list + } else { + return Err(RuntimeError::ValidationFailure( + ValidationError::ExpectedList { + actual: value.r#type(context)?, + position, + }, + )); + }; + + Ok(Some(Evaluation::Return(Value::integer(list.len() as i64)))) + } +} diff --git a/dust-lang/src/abstract_tree/built_in_function_call.rs b/dust-lang/src/abstract_tree/built_in_function_call.rs deleted file mode 100644 index e9ce9c4..0000000 --- a/dust-lang/src/abstract_tree/built_in_function_call.rs +++ /dev/null @@ -1,165 +0,0 @@ -use std::{ - fs::read_to_string, - io::{stdin, stdout, Write}, - thread, - time::Duration, -}; - -use serde::{Deserialize, Serialize}; - -use crate::{ - context::Context, - error::{RuntimeError, ValidationError}, - value::ValueInner, - Value, -}; - -use super::{AbstractNode, Evaluation, Expression, Type, TypeConstructor}; - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub enum BuiltInFunctionCall { - JsonParse(TypeConstructor, Expression), - Length(Expression), - ReadFile(Expression), - ReadLine, - Sleep(Expression), - WriteLine(Expression), -} -impl AbstractNode for BuiltInFunctionCall { - fn define_types(&self, _context: &Context) -> Result<(), ValidationError> { - match self { - BuiltInFunctionCall::JsonParse(_, expression) => expression.define_types(_context), - BuiltInFunctionCall::Length(expression) => expression.define_types(_context), - BuiltInFunctionCall::ReadFile(expression) => expression.define_types(_context), - BuiltInFunctionCall::ReadLine => Ok(()), - BuiltInFunctionCall::Sleep(expression) => expression.define_types(_context), - BuiltInFunctionCall::WriteLine(expression) => expression.define_types(_context), - } - } - - fn validate(&self, _context: &Context, _manage_memory: bool) -> Result<(), ValidationError> { - match self { - BuiltInFunctionCall::JsonParse(_, expression) => { - expression.validate(_context, _manage_memory) - } - BuiltInFunctionCall::Length(expression) => { - expression.validate(_context, _manage_memory) - } - BuiltInFunctionCall::ReadFile(expression) => { - expression.validate(_context, _manage_memory) - } - BuiltInFunctionCall::ReadLine => Ok(()), - BuiltInFunctionCall::Sleep(expression) => expression.validate(_context, _manage_memory), - BuiltInFunctionCall::WriteLine(expression) => { - expression.validate(_context, _manage_memory) - } - } - } - - fn evaluate( - self, - context: &Context, - _manage_memory: bool, - ) -> Result, RuntimeError> { - fn evaluate_expression( - expression: Expression, - context: &Context, - _manage_memory: bool, - ) -> Result { - let position = expression.position(); - let evaluation = expression.evaluate(context, _manage_memory)?; - - if let Some(Evaluation::Return(value)) = evaluation { - Ok(value) - } else { - Err(RuntimeError::ValidationFailure( - ValidationError::ExpectedExpression(position), - )) - } - } - - match self { - BuiltInFunctionCall::JsonParse(_type, expression) => { - let position = expression.position(); - let value = evaluate_expression(expression, context, _manage_memory)?; - - if let ValueInner::String(string) = value.inner().as_ref() { - let deserialized = serde_json::from_str(&string)?; - - Ok(Some(Evaluation::Return(deserialized))) - } else { - Err(RuntimeError::ValidationFailure( - ValidationError::ExpectedString { - actual: value.r#type(context)?, - position, - }, - )) - } - } - BuiltInFunctionCall::Length(expression) => { - let value = evaluate_expression(expression, context, _manage_memory)?; - let length = if let ValueInner::List(list) = value.inner().as_ref() { - list.len() as i64 - } else { - todo!("Create an error for this occurence.") - }; - - Ok(Some(Evaluation::Return(Value::integer(length)))) - } - BuiltInFunctionCall::ReadFile(expression) => { - let value = evaluate_expression(expression, context, _manage_memory)?; - let file_contents = if let ValueInner::String(path) = value.inner().as_ref() { - read_to_string(path)? - } else { - String::with_capacity(0) - }; - - Ok(Some(Evaluation::Return(Value::string(file_contents)))) - } - BuiltInFunctionCall::ReadLine => { - let mut buffer = String::new(); - - stdin().read_line(&mut buffer)?; - - Ok(Some(Evaluation::Return(Value::string( - buffer.strip_suffix('\n').unwrap_or(&buffer), - )))) - } - BuiltInFunctionCall::Sleep(expression) => { - let value = evaluate_expression(expression, context, _manage_memory)?; - - if let ValueInner::Integer(milliseconds) = value.inner().as_ref() { - thread::sleep(Duration::from_millis(*milliseconds as u64)); - } - - Ok(None) - } - BuiltInFunctionCall::WriteLine(expression) => { - let value = evaluate_expression(expression, context, _manage_memory)?; - - if let ValueInner::String(output) = value.inner().as_ref() { - let mut stdout = stdout(); - - stdout.write_all(output.as_bytes())?; - stdout.write(b"\n")?; - stdout.flush()?; - } - - Ok(None) - } - } - } - - fn expected_type(&self, context: &Context) -> Result, ValidationError> { - match self { - BuiltInFunctionCall::JsonParse(r#type, _) => { - Ok(Some(r#type.clone().construct(&context)?)) - } - BuiltInFunctionCall::Length(_) => Ok(Some(Type::Integer)), - BuiltInFunctionCall::ReadFile(_) => Ok(Some(Type::String)), - BuiltInFunctionCall::ReadLine => Ok(Some(Type::String)), - BuiltInFunctionCall::Sleep(_) => Ok(None), - BuiltInFunctionCall::WriteLine(_) => Ok(None), - } - } -} diff --git a/dust-lang/src/abstract_tree/expression.rs b/dust-lang/src/abstract_tree/expression.rs index 33d5a77..7ec586a 100644 --- a/dust-lang/src/abstract_tree/expression.rs +++ b/dust-lang/src/abstract_tree/expression.rs @@ -4,7 +4,6 @@ use crate::{ context::Context, error::{RuntimeError, ValidationError}, identifier::Identifier, - value::ValueInner, }; use super::{ @@ -47,24 +46,7 @@ impl AbstractNode for Expression { Expression::As(inner) => inner.node.define_types(_context), Expression::BuiltInFunctionCall(inner) => inner.node.define_types(_context), Expression::FunctionCall(inner) => inner.node.define_types(_context), - Expression::Identifier(identifier) => { - let found = _context.get_value(&identifier.node)?; - - if let Some(value) = &found { - if let ValueInner::Function(function) = value.inner().as_ref() { - function.body().define_types(_context)?; - } - } - - if found.is_some() { - Ok(()) - } else { - Err(ValidationError::VariableNotFound { - identifier: identifier.node.clone(), - position: identifier.position, - }) - } - } + Expression::Identifier(_) => Ok(()), Expression::MapIndex(inner) => inner.node.define_types(_context), Expression::ListIndex(inner) => inner.node.define_types(_context), Expression::Logic(inner) => inner.node.define_types(_context), @@ -83,15 +65,9 @@ impl AbstractNode for Expression { function_call.node.validate(context, manage_memory) } Expression::Identifier(identifier) => { - let found = context.get_value(&identifier.node)?; + let found = context.add_expected_use(&identifier.node)?; - if let Some(value) = &found { - if let ValueInner::Function(function) = value.inner().as_ref() { - function.body().validate(context, manage_memory)?; - } - } - - if found.is_some() { + if found { Ok(()) } else { Err(ValidationError::VariableNotFound { diff --git a/dust-lang/src/abstract_tree/mod.rs b/dust-lang/src/abstract_tree/mod.rs index d4a7a82..d7b5a42 100644 --- a/dust-lang/src/abstract_tree/mod.rs +++ b/dust-lang/src/abstract_tree/mod.rs @@ -2,7 +2,7 @@ pub mod r#as; pub mod assignment; pub mod async_block; pub mod block; -pub mod built_in_function_call; +pub mod built_in_function; pub mod enum_declaration; pub mod expression; pub mod function_call; @@ -29,7 +29,7 @@ pub use self::{ assignment::{Assignment, AssignmentOperator}, async_block::AsyncBlock, block::Block, - built_in_function_call::BuiltInFunctionCall, + built_in_function::FunctionLogic, enum_declaration::{EnumDeclaration, EnumVariant}, expression::Expression, function_call::FunctionCall, diff --git a/dust-lang/src/abstract_tree/value_node.rs b/dust-lang/src/abstract_tree/value_node.rs index 8c6c1ac..6103dea 100644 --- a/dust-lang/src/abstract_tree/value_node.rs +++ b/dust-lang/src/abstract_tree/value_node.rs @@ -33,6 +33,7 @@ pub enum ValueNode { }, Function(FunctionNode), } + impl ValueNode { pub fn function( type_parameters: Option>, @@ -51,28 +52,28 @@ impl ValueNode { } impl AbstractNode for ValueNode { - fn define_types(&self, _context: &Context) -> Result<(), ValidationError> { + fn define_types(&self, outer_context: &Context) -> Result<(), ValidationError> { match self { ValueNode::EnumInstance { content, .. } => { if let Some(expressions) = content { for expression in expressions { - expression.define_types(_context)?; + expression.define_types(outer_context)?; } } } ValueNode::List(expressions) => { for expression in expressions { - expression.define_types(_context)?; + expression.define_types(outer_context)?; } } ValueNode::Map(fields) => { for (_, _, expression) in fields { - expression.define_types(_context)?; + expression.define_types(outer_context)?; } } ValueNode::Structure { fields, .. } => { for (_, expression) in fields { - expression.define_types(_context)?; + expression.define_types(outer_context)?; } } ValueNode::Function(FunctionNode { @@ -95,12 +96,12 @@ impl AbstractNode for ValueNode { } for (identifier, type_constructor) in value_parameters { - let r#type = type_constructor.clone().construct(&context_template)?; + let r#type = type_constructor.clone().construct(outer_context)?; context_template.set_type(identifier.clone(), r#type)?; } - body.node.define_types(_context)?; + body.node.define_types(context_template)?; } _ => {} } @@ -169,7 +170,10 @@ impl AbstractNode for ValueNode { let ((expected_return, expected_position), actual_return) = match (return_type, body.node.expected_type(&context_template)?) { (Some(constructor), Some(r#type)) => ( - (constructor.construct(context)?, constructor.position()), + ( + constructor.construct(context_template)?, + constructor.position(), + ), r#type, ), (None, Some(_)) => return Err(ValidationError::ExpectedValue(body.position)), @@ -312,11 +316,10 @@ impl AbstractNode for ValueNode { context_template, }) => { let outer_context = context; - let function_context = context_template.create_child(); let mut value_parameters = Vec::with_capacity(constructors.len()); for (identifier, constructor) in constructors { - let r#type = constructor.construct(&function_context)?; + let r#type = constructor.construct(&outer_context)?; value_parameters.push((identifier, r#type)); } diff --git a/dust-lang/src/error.rs b/dust-lang/src/error.rs index c6229c7..279b983 100644 --- a/dust-lang/src/error.rs +++ b/dust-lang/src/error.rs @@ -118,6 +118,10 @@ pub enum ValidationError { actual: Type, position: SourcePosition, }, + ExpectedList { + actual: Type, + position: SourcePosition, + }, ExpectedBoolean { actual: Type, position: SourcePosition, diff --git a/dust-lang/src/lexer.rs b/dust-lang/src/lexer.rs index a421da1..ec6909b 100644 --- a/dust-lang/src/lexer.rs +++ b/dust-lang/src/lexer.rs @@ -49,7 +49,6 @@ pub enum Keyword { If, JsonParse, Length, - List, Map, None, Range, @@ -78,7 +77,6 @@ impl Display for Keyword { Keyword::Fn => write!(f, "fn"), Keyword::Int => write!(f, "int"), Keyword::If => write!(f, "if"), - Keyword::List => write!(f, "list"), Keyword::Map => write!(f, "map"), Keyword::None => write!(f, "none"), Keyword::Range => write!(f, "range"), @@ -263,7 +261,6 @@ pub fn lexer<'src>() -> impl Parser< just("fn").to(Token::Keyword(Keyword::Fn)), just("int").to(Token::Keyword(Keyword::Int)), just("if").to(Token::Keyword(Keyword::If)), - just("list").to(Token::Keyword(Keyword::List)), just("map").to(Token::Keyword(Keyword::Map)), just("none").to(Token::Keyword(Keyword::None)), just("range").to(Token::Keyword(Keyword::Range)), diff --git a/dust-lang/src/value.rs b/dust-lang/src/value.rs index fe2ca4d..2dcd773 100644 --- a/dust-lang/src/value.rs +++ b/dust-lang/src/value.rs @@ -721,6 +721,22 @@ pub struct Function { } impl Function { + pub fn new( + type_parameters: Option>, + value_parameters: Vec<(Identifier, Type)>, + return_type: Option, + body: Block, + context_template: Context, + ) -> Self { + Self { + type_parameters, + value_parameters, + return_type, + body, + context_template, + } + } + pub fn context_template(&self) -> &Context { &self.context_template }