From f106d6436774eddcbe2e6aca70da0432aa9c8b41 Mon Sep 17 00:00:00 2001 From: Jeff Date: Mon, 24 Jun 2024 05:26:49 -0400 Subject: [PATCH] Simplify built-in functions --- .../src/abstract_tree/built_in_function.rs | 331 +++++------------- dust-lang/src/abstract_tree/map_index.rs | 29 +- dust-lang/src/error.rs | 2 +- dust-lang/src/lib.rs | 12 +- dust-lang/src/parser/mod.rs | 20 +- dust-lang/src/parser/tests.rs | 6 +- 6 files changed, 141 insertions(+), 259 deletions(-) diff --git a/dust-lang/src/abstract_tree/built_in_function.rs b/dust-lang/src/abstract_tree/built_in_function.rs index 7cdda64..0098a7c 100644 --- a/dust-lang/src/abstract_tree/built_in_function.rs +++ b/dust-lang/src/abstract_tree/built_in_function.rs @@ -1,4 +1,4 @@ -use std::{array, fs::read_to_string, io::stdin}; +use std::{fs::read_to_string, io::stdin}; use serde::{Deserialize, Serialize}; use serde_json::from_str; @@ -15,64 +15,21 @@ use super::{AbstractNode, Evaluation, Expression, Type, TypeConstructor}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub enum BuiltInFunctionCall { - Length(BuiltInContextBinding), - ReadFile(BuiltInContextBinding), - ReadLine(BuiltInContextBinding), - Sleep(BuiltInContextBinding), - WriteLine(BuiltInContextBinding), - JsonParse(BuiltInContextBinding), -} - -impl BuiltInFunctionCall { - pub fn length(argument: Expression) -> Self { - BuiltInFunctionCall::Length(BuiltInContextBinding::new(Length(Box::new(argument)))) - } - - pub fn read_file(argument: Expression) -> Self { - BuiltInFunctionCall::ReadFile(BuiltInContextBinding::new(ReadFile(Box::new(argument)))) - } - - pub fn read_line() -> Self { - BuiltInFunctionCall::ReadLine(BuiltInContextBinding::new(ReadLine)) - } - - pub fn sleep(argument: Expression) -> Self { - BuiltInFunctionCall::Sleep(BuiltInContextBinding::new(Sleep(Box::new(argument)))) - } - - pub fn write_line(argument: Expression) -> Self { - BuiltInFunctionCall::WriteLine(BuiltInContextBinding::new(WriteLine(Box::new(argument)))) - } - - pub fn json_parse(r#type: TypeConstructor, argument: Expression) -> Self { - BuiltInFunctionCall::JsonParse(BuiltInContextBinding::new(JsonParse( - r#type, - Box::new(argument), - ))) - } + Length(Length), + ReadFile(ReadFile), + ReadLine(ReadLine), + Sleep(Sleep), + WriteLine(WriteLine), + JsonParse(JsonParse), } impl AbstractNode for BuiltInFunctionCall { fn define_types(&self, _context: &Context) -> Result<(), ValidationError> { - match self { - BuiltInFunctionCall::Length(inner) => inner.define_types(_context), - BuiltInFunctionCall::ReadFile(inner) => inner.define_types(_context), - BuiltInFunctionCall::ReadLine(inner) => inner.define_types(_context), - BuiltInFunctionCall::Sleep(inner) => inner.define_types(_context), - BuiltInFunctionCall::WriteLine(inner) => inner.define_types(_context), - BuiltInFunctionCall::JsonParse(inner) => inner.define_types(_context), - } + Ok(()) } fn validate(&self, _context: &Context, _manage_memory: bool) -> Result<(), ValidationError> { - match self { - BuiltInFunctionCall::Length(inner) => inner.validate(_context, _manage_memory), - BuiltInFunctionCall::ReadFile(inner) => inner.validate(_context, _manage_memory), - BuiltInFunctionCall::ReadLine(inner) => inner.validate(_context, _manage_memory), - BuiltInFunctionCall::Sleep(inner) => inner.validate(_context, _manage_memory), - BuiltInFunctionCall::WriteLine(inner) => inner.validate(_context, _manage_memory), - BuiltInFunctionCall::JsonParse(inner) => inner.validate(_context, _manage_memory), - } + Ok(()) } fn evaluate( @@ -81,70 +38,28 @@ impl AbstractNode for BuiltInFunctionCall { _manage_memory: bool, ) -> Result, RuntimeError> { match self { - BuiltInFunctionCall::Length(inner) => inner.evaluate(_context, _manage_memory), - BuiltInFunctionCall::ReadFile(inner) => inner.evaluate(_context, _manage_memory), - BuiltInFunctionCall::ReadLine(inner) => inner.evaluate(_context, _manage_memory), - BuiltInFunctionCall::Sleep(inner) => inner.evaluate(_context, _manage_memory), - BuiltInFunctionCall::WriteLine(inner) => inner.evaluate(_context, _manage_memory), - BuiltInFunctionCall::JsonParse(inner) => inner.evaluate(_context, _manage_memory), + BuiltInFunctionCall::Length(inner) => inner.call(_context, _manage_memory), + BuiltInFunctionCall::ReadFile(inner) => inner.call(_context, _manage_memory), + BuiltInFunctionCall::ReadLine(inner) => inner.call(_context, _manage_memory), + BuiltInFunctionCall::Sleep(inner) => inner.call(_context, _manage_memory), + BuiltInFunctionCall::WriteLine(inner) => inner.call(_context, _manage_memory), + BuiltInFunctionCall::JsonParse(inner) => inner.call(_context, _manage_memory), } } fn expected_type(&self, _context: &Context) -> Result, ValidationError> { match self { - BuiltInFunctionCall::Length(inner) => inner.expected_type(_context), - BuiltInFunctionCall::ReadFile(inner) => inner.expected_type(_context), - BuiltInFunctionCall::ReadLine(inner) => inner.expected_type(_context), - BuiltInFunctionCall::Sleep(inner) => inner.expected_type(_context), - BuiltInFunctionCall::WriteLine(inner) => inner.expected_type(_context), - BuiltInFunctionCall::JsonParse(inner) => inner.expected_type(_context), + BuiltInFunctionCall::Length(inner) => inner.return_type(_context), + BuiltInFunctionCall::ReadFile(inner) => inner.return_type(_context), + BuiltInFunctionCall::ReadLine(inner) => inner.return_type(_context), + BuiltInFunctionCall::Sleep(inner) => inner.return_type(_context), + BuiltInFunctionCall::WriteLine(inner) => inner.return_type(_context), + BuiltInFunctionCall::JsonParse(inner) => inner.return_type(_context), } } } -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct BuiltInContextBinding { - function: F, - #[serde(skip)] - context: Context, -} - -impl BuiltInContextBinding { - pub fn new(function: F) -> Self { - Self { - function, - context: Context::new(None), - } - } -} - -impl Eq for BuiltInContextBinding {} - -impl PartialEq for BuiltInContextBinding { - fn eq(&self, other: &Self) -> bool { - self.function == other.function - } -} - -impl PartialOrd for BuiltInContextBinding { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.function.cmp(&other.function)) - } -} - -impl Ord for BuiltInContextBinding { - fn cmp(&self, other: &Self) -> std::cmp::Ordering { - self.function.cmp(&other.function) - } -} - trait FunctionLogic { - fn arguments( - self, - ) -> ( - Option>, - Option>, - ); fn return_type(&self, context: &Context) -> Result, ValidationError>; fn call( self, @@ -153,68 +68,16 @@ trait FunctionLogic { ) -> Result, RuntimeError>; } -impl AbstractNode for BuiltInContextBinding -where - F: FunctionLogic + Clone, -{ - fn define_types(&self, _: &Context) -> Result<(), ValidationError> { - let (type_arguments, value_arguments) = self.function.clone().arguments(); - - if let Some(type_arguments) = type_arguments { - for identifier in type_arguments { - self.context.set_type( - identifier.clone(), - Type::Generic { - identifier, - concrete_type: None, - }, - )?; - } - } - - if let Some(value_arguments) = value_arguments { - for (identifier, r#type) in value_arguments { - self.context.set_type(identifier, r#type)?; - } - } - - Ok(()) - } - - fn validate(&self, _context: &Context, _manage_memory: bool) -> Result<(), ValidationError> { - Ok(()) - } - - fn evaluate( - self, - context: &Context, - manage_memory: bool, - ) -> Result, RuntimeError> { - self.context.set_parent(context.clone())?; - self.function.call(&self.context, manage_memory) - } - - fn expected_type(&self, context: &Context) -> Result, ValidationError> { - self.function.return_type(context) - } -} - #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub struct Length(Box); -impl FunctionLogic for Length { - fn arguments( - self, - ) -> ( - Option>, - Option>, - ) { - ( - None::>, - Some([(Identifier::new("list"), Type::ListOf(Box::new(Type::Any)))].into_iter()), - ) +impl Length { + pub fn new(expression: Expression) -> Self { + Length(Box::new(expression)) } +} +impl FunctionLogic for Length { fn return_type(&self, _: &Context) -> Result, ValidationError> { Ok(Some(Type::Integer)) } @@ -251,19 +114,13 @@ impl FunctionLogic for Length { #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub struct ReadFile(Box); -impl FunctionLogic for ReadFile { - fn arguments( - self, - ) -> ( - Option>, - Option>, - ) { - ( - None::>, - Some([(Identifier::new("path"), Type::ListOf(Box::new(Type::Any)))].into_iter()), - ) +impl ReadFile { + pub fn new(expression: Expression) -> Self { + ReadFile(Box::new(expression)) } +} +impl FunctionLogic for ReadFile { fn return_type(&self, _: &Context) -> Result, ValidationError> { Ok(Some(Type::String)) } @@ -287,18 +144,6 @@ impl FunctionLogic for ReadFile { pub struct ReadLine; impl FunctionLogic for ReadLine { - fn arguments( - self, - ) -> ( - Option>, - Option>, - ) { - ( - None::>, - None::>, - ) - } - fn return_type(&self, _: &Context) -> Result, ValidationError> { Ok(Some(Type::String)) } @@ -317,19 +162,13 @@ impl FunctionLogic for ReadLine { #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub struct Sleep(Box); -impl FunctionLogic for Sleep { - fn arguments( - self, - ) -> ( - Option>, - Option>, - ) { - ( - None::>, - Some([(Identifier::new("milliseconds"), Type::Integer)].into_iter()), - ) +impl Sleep { + pub fn new(expression: Expression) -> Self { + Sleep(Box::new(expression)) } +} +impl FunctionLogic for Sleep { fn return_type(&self, _: &Context) -> Result, ValidationError> { Ok(None) } @@ -342,19 +181,13 @@ impl FunctionLogic for Sleep { #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub struct WriteLine(Box); -impl FunctionLogic for WriteLine { - fn arguments( - self, - ) -> ( - Option>, - Option>, - ) { - ( - None::>, - Some([(Identifier::new("output"), Type::Any)].into_iter()), - ) +impl WriteLine { + pub fn new(expression: Expression) -> Self { + WriteLine(Box::new(expression)) } +} +impl FunctionLogic for WriteLine { fn return_type(&self, _: &Context) -> Result, ValidationError> { Ok(None) } @@ -383,57 +216,71 @@ impl FunctionLogic for WriteLine { #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub struct JsonParse(TypeConstructor, Box); -impl FunctionLogic for JsonParse { - fn arguments( - self, - ) -> ( - Option>, - Option>, - ) { - ( - Some([Identifier::new("T")].into_iter()), - Some([(Identifier::new("input"), Type::Any)].into_iter()), - ) +impl JsonParse { + pub fn new(constructor: TypeConstructor, expression: Expression) -> Self { + JsonParse(constructor, Box::new(expression)) } +} +impl FunctionLogic for JsonParse { fn return_type(&self, context: &Context) -> Result, ValidationError> { self.0.construct(context).map(|r#type| Some(r#type)) } - fn call(self, context: &Context, _: bool) -> Result, RuntimeError> { - let target_type = context.get_type(&Identifier::new("T"))?; - let input = context.get_value(&Identifier::new("input"))?; + fn call( + self, + context: &Context, + manage_memory: bool, + ) -> Result, RuntimeError> { + let target_type = self.0.construct(context)?; + let position = self.1.position(); + let evaluation = self.1.evaluate(context, manage_memory)?; + let value = if let Some(Evaluation::Return(value)) = evaluation { + value + } else { + return Err(RuntimeError::ValidationFailure( + ValidationError::ExpectedExpression(position), + )); + }; + let input = if let ValueInner::String(string) = value.inner().as_ref() { + string + } else { + return Err(RuntimeError::ValidationFailure( + ValidationError::ExpectedString { + actual: value.r#type(context)?, + position, + }, + )); + }; - if let (Some(r#type), Some(value)) = (target_type, input) { - let input_string = if let ValueInner::String(string) = value.inner().as_ref() { - string - } else { - return Err(RuntimeError::ValidationFailure( - ValidationError::BuiltInFunctionFailure(self.0.position()), - )); - }; - - let parsed_value = match r#type { - Type::Any => from_str::(input_string)?, - Type::Boolean => Value::boolean(from_str::(input_string)?), + fn parse_value(input: &str, r#type: Type) -> Result { + let value = match r#type { + Type::Any => from_str::(input)?, + Type::Boolean => Value::boolean(from_str::(input)?), Type::Enum { .. } => todo!(), - Type::Float => Value::float(from_str::(input_string)?), + Type::Float => Value::float(from_str::(input)?), Type::Function { .. } => todo!(), - Type::Generic { .. } => todo!(), - Type::Integer => Value::integer(from_str::(input_string)?), + Type::Generic { concrete_type, .. } => { + if let Some(r#type) = concrete_type { + parse_value(input, *r#type)? + } else { + todo!("Create an error for this occurence"); + } + } + Type::Integer => Value::integer(from_str::(input)?), Type::List { .. } => todo!(), Type::ListOf(_) => todo!(), Type::Map(_) => todo!(), Type::Range => todo!(), - Type::String => Value::string(from_str::(input_string)?), + Type::String => Value::string(from_str::(input)?), Type::Structure { .. } => todo!(), }; - return Ok(Some(Evaluation::Return(parsed_value))); + Ok(value) } - Err(RuntimeError::ValidationFailure( - ValidationError::BuiltInFunctionFailure(self.0.position()), - )) + let value = parse_value(&input, target_type)?; + + Ok(Some(Evaluation::Return(value))) } } diff --git a/dust-lang/src/abstract_tree/map_index.rs b/dust-lang/src/abstract_tree/map_index.rs index 395014b..9dfee7a 100644 --- a/dust-lang/src/abstract_tree/map_index.rs +++ b/dust-lang/src/abstract_tree/map_index.rs @@ -29,13 +29,32 @@ impl AbstractNode for MapIndex { self.index.define_types(_context) } - fn validate(&self, _context: &Context, _manage_memory: bool) -> Result<(), ValidationError> { - self.collection.validate(_context, _manage_memory)?; + fn validate(&self, context: &Context, _manage_memory: bool) -> Result<(), ValidationError> { + self.collection.validate(context, _manage_memory)?; - if let Expression::Identifier(identifier) = &self.index { + let collection_type = if let Some(r#type) = self.collection.expected_type(context)? { + r#type + } else { + return Err(ValidationError::ExpectedExpression( + self.collection.position(), + )); + }; + + if let (Type::Map(fields), Expression::Identifier(identifier)) = + (collection_type, &self.index) + { + if !fields.contains_key(&identifier.node) { + return Err(ValidationError::FieldNotFound { + identifier: identifier.node.clone(), + position: identifier.position, + }); + } + } + + if let Expression::Identifier(_) = &self.index { Ok(()) } else { - self.index.validate(_context, _manage_memory) + self.index.validate(context, _manage_memory) } } @@ -90,7 +109,7 @@ impl AbstractNode for MapIndex { return if let Some(value) = map.get(&index.node) { Ok(Some(value.r#type(context)?)) } else { - Err(ValidationError::PropertyNotFound { + Err(ValidationError::FieldNotFound { identifier: index.node.clone(), position: index.position, }) diff --git a/dust-lang/src/error.rs b/dust-lang/src/error.rs index 929b628..e06d4a3 100644 --- a/dust-lang/src/error.rs +++ b/dust-lang/src/error.rs @@ -165,7 +165,7 @@ pub enum ValidationError { identifier: Identifier, position: SourcePosition, }, - PropertyNotFound { + FieldNotFound { identifier: Identifier, position: SourcePosition, }, diff --git a/dust-lang/src/lib.rs b/dust-lang/src/lib.rs index 31c0074..1f33f65 100644 --- a/dust-lang/src/lib.rs +++ b/dust-lang/src/lib.rs @@ -434,7 +434,17 @@ impl InterpreterError { ValidationError::ExpectedExpression(_) => todo!(), ValidationError::ExpectedFunction { .. } => todo!(), ValidationError::ExpectedValue(_) => todo!(), - ValidationError::PropertyNotFound { .. } => todo!(), + ValidationError::FieldNotFound { + identifier, + position, + } => builder.add_label( + Label::new((self.source_id.clone(), position.0..position.1)).with_message( + format!( + "This map has no field named {}.", + identifier.fg(identifier_color) + ), + ), + ), ValidationError::WrongArguments { .. } => todo!(), ValidationError::WrongTypeArgumentCount { .. } => todo!(), ValidationError::ExpectedIntegerFloatOrString { actual, position } => { diff --git a/dust-lang/src/parser/mod.rs b/dust-lang/src/parser/mod.rs index 37d82a1..226ecc9 100644 --- a/dust-lang/src/parser/mod.rs +++ b/dust-lang/src/parser/mod.rs @@ -13,7 +13,9 @@ use crate::{ }; use self::{ - built_in_function::BuiltInFunctionCall, + built_in_function::{ + BuiltInFunctionCall, JsonParse, Length, ReadFile, ReadLine, Sleep, WriteLine, + }, enum_declaration::EnumVariant, type_constructor::{RawTypeConstructor, TypeInvokationConstructor}, }; @@ -385,33 +387,37 @@ pub fn parser<'src>( .ignore_then(expression.clone()) .map_with(|argument, state| { Expression::BuiltIn( - BuiltInFunctionCall::length(argument).with_position(state.span()), + BuiltInFunctionCall::Length(Length::new(argument)) + .with_position(state.span()), ) }), _built_in_function(Keyword::ReadFile) .ignore_then(expression.clone()) .map_with(|argument, state| { Expression::BuiltIn( - BuiltInFunctionCall::read_file(argument).with_position(state.span()), + BuiltInFunctionCall::ReadFile(ReadFile::new(argument)) + .with_position(state.span()), ) }), _built_in_function(Keyword::ReadLine).map_with(|_, state| { Expression::BuiltIn( - BuiltInFunctionCall::read_line().with_position(state.span()), + BuiltInFunctionCall::ReadLine(ReadLine).with_position(state.span()), ) }), _built_in_function(Keyword::Sleep) .ignore_then(expression.clone()) .map_with(|argument, state| { Expression::BuiltIn( - BuiltInFunctionCall::sleep(argument).with_position(state.span()), + BuiltInFunctionCall::Sleep(Sleep::new(argument)) + .with_position(state.span()), ) }), _built_in_function(Keyword::WriteLine) .ignore_then(expression.clone()) .map_with(|argument, state| { Expression::BuiltIn( - BuiltInFunctionCall::write_line(argument).with_position(state.span()), + BuiltInFunctionCall::WriteLine(WriteLine::new(argument)) + .with_position(state.span()), ) }), _built_in_function(Keyword::JsonParse) @@ -419,7 +425,7 @@ pub fn parser<'src>( .then(expression.clone()) .map_with(|(constructor, argument), state| { Expression::BuiltIn( - BuiltInFunctionCall::json_parse(constructor, argument) + BuiltInFunctionCall::JsonParse(JsonParse::new(constructor, argument)) .with_position(state.span()), ) }), diff --git a/dust-lang/src/parser/tests.rs b/dust-lang/src/parser/tests.rs index b0dd8ec..bf21431 100644 --- a/dust-lang/src/parser/tests.rs +++ b/dust-lang/src/parser/tests.rs @@ -271,7 +271,7 @@ fn built_in_function() { assert_eq!( statements[0], Statement::Expression(Expression::BuiltIn( - BuiltInFunctionCall::read_line().with_position((0, 13)) + BuiltInFunctionCall::ReadLine(ReadLine).with_position((0, 13)) )) ); } @@ -293,9 +293,9 @@ fn built_in_function_with_arg() { assert_eq!( statements[0], Statement::Expression(Expression::BuiltIn( - BuiltInFunctionCall::write_line(Expression::Value( + BuiltInFunctionCall::WriteLine(WriteLine::new(Expression::Value( ValueNode::String("hiya".to_string()).with_position((15, 21)) - )) + ))) .with_position((0, 21)) )) );