From a5c5075e6b4ff565cf5058cca08fc3b5a2d29766 Mon Sep 17 00:00:00 2001 From: Jeff Date: Mon, 24 Jun 2024 10:09:07 -0400 Subject: [PATCH] Pass all tests --- .../src/abstract_tree/built_in_function.rs | 69 +++++++++++++++---- dust-lang/src/abstract_tree/function_call.rs | 55 ++++++++++----- dust-lang/src/lib.rs | 6 +- 3 files changed, 97 insertions(+), 33 deletions(-) diff --git a/dust-lang/src/abstract_tree/built_in_function.rs b/dust-lang/src/abstract_tree/built_in_function.rs index 49ef105..4616c41 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::{fs::read_to_string, io::stdin}; +use std::{fs::read_to_string, io::stdin, thread::sleep, time::Duration}; use serde::{Deserialize, Serialize}; use serde_json::from_str; @@ -11,7 +11,7 @@ use crate::{ Value, }; -use super::{AbstractNode, Evaluation, Expression, Type, TypeConstructor}; +use super::Type; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub enum BuiltInFunction { @@ -98,13 +98,29 @@ impl FunctionLogic for ReadFile { fn r#type() -> Type { Type::Function { type_parameters: None, - value_parameters: None, + value_parameters: Some(vec![(Identifier::new("path"), Type::String)]), return_type: Some(Box::new(Type::String)), } } fn call(context: &Context, manage_memory: bool) -> Result, RuntimeError> { - todo!() + let value = if let Some(value) = context.get_value(&Identifier::new("path"))? { + value + } else { + return Err(RuntimeError::ValidationFailure( + ValidationError::BuiltInFunctionFailure("path does not exist"), + )); + }; + let path = if let ValueInner::String(string) = value.inner().as_ref() { + string + } else { + return Err(RuntimeError::ValidationFailure( + ValidationError::BuiltInFunctionFailure("path is not a string"), + )); + }; + let file_content = read_to_string(path)?; + + Ok(Some(Value::string(file_content))) } } @@ -121,7 +137,11 @@ impl FunctionLogic for ReadLine { } fn call(context: &Context, manage_memory: bool) -> Result, RuntimeError> { - todo!() + let mut user_input = String::new(); + + stdin().read_line(&mut user_input)?; + + Ok(Some(Value::string(user_input))) } } @@ -132,13 +152,30 @@ impl FunctionLogic for Sleep { fn r#type() -> Type { Type::Function { type_parameters: None, - value_parameters: None, + value_parameters: Some(vec![(Identifier::new("milliseconds"), Type::Integer)]), return_type: None, } } fn call(context: &Context, manage_memory: bool) -> Result, RuntimeError> { - todo!() + let value = if let Some(value) = context.get_value(&Identifier::new("milliseconds"))? { + value + } else { + return Err(RuntimeError::ValidationFailure( + ValidationError::BuiltInFunctionFailure("milliseconds does not exist"), + )); + }; + let milliseconds = if let ValueInner::Integer(integer) = value.inner().as_ref() { + integer + } else { + return Err(RuntimeError::ValidationFailure( + ValidationError::BuiltInFunctionFailure("milliseconds is not an integer"), + )); + }; + + sleep(Duration::from_millis(*milliseconds as u64)); + + Ok(None) } } @@ -149,7 +186,7 @@ impl FunctionLogic for WriteLine { fn r#type() -> Type { Type::Function { type_parameters: None, - value_parameters: None, + value_parameters: Some(vec![(Identifier::new("output"), Type::String)]), return_type: None, } } @@ -162,7 +199,7 @@ impl FunctionLogic for WriteLine { ValidationError::BuiltInFunctionFailure("output does not exist"), )); }; - let input = if let ValueInner::String(string) = value.inner().as_ref() { + let output = if let ValueInner::String(string) = value.inner().as_ref() { string } else { return Err(RuntimeError::ValidationFailure( @@ -170,7 +207,7 @@ impl FunctionLogic for WriteLine { )); }; - println!("{input}"); + println!("{output}"); Ok(None) } @@ -181,13 +218,15 @@ struct JsonParse; impl FunctionLogic for JsonParse { fn r#type() -> Type { + let type_t = Type::Generic { + identifier: Identifier::new("T"), + concrete_type: None, + }; + Type::Function { type_parameters: None, - value_parameters: None, - return_type: Some(Box::new(Type::Generic { - identifier: Identifier::new("T"), - concrete_type: None, - })), + value_parameters: Some(vec![(Identifier::new("input"), type_t.clone())]), + return_type: Some(Box::new(type_t)), } } diff --git a/dust-lang/src/abstract_tree/function_call.rs b/dust-lang/src/abstract_tree/function_call.rs index d8a7e02..5de24a0 100644 --- a/dust-lang/src/abstract_tree/function_call.rs +++ b/dust-lang/src/abstract_tree/function_call.rs @@ -47,14 +47,6 @@ impl AbstractNode for FunctionCall { } fn validate(&self, context: &Context, manage_memory: bool) -> Result<(), ValidationError> { - if let Expression::Value(WithPosition { - node: ValueNode::BuiltInFunction(_), - .. - }) = self.function_expression.as_ref() - { - return Ok(()); - } - self.function_expression.validate(context, manage_memory)?; if let Some(value_arguments) = &self.value_arguments { @@ -63,18 +55,23 @@ impl AbstractNode for FunctionCall { } } - let function_node_type = - if let Some(r#type) = self.function_expression.expected_type(context)? { - r#type - } else { - return Err(ValidationError::ExpectedExpression( - self.function_expression.position(), - )); - }; + let function_node_type = if let Expression::Value(WithPosition { + node: ValueNode::BuiltInFunction(function), + .. + }) = self.function_expression.as_ref() + { + function.r#type() + } else if let Some(r#type) = self.function_expression.expected_type(context)? { + r#type + } else { + return Err(ValidationError::ExpectedExpression( + self.function_expression.position(), + )); + }; if let Type::Function { type_parameters, - value_parameters: _, + value_parameters, return_type: _, } = function_node_type { @@ -90,6 +87,30 @@ impl AbstractNode for FunctionCall { _ => {} } + match (value_parameters, &self.value_arguments) { + (Some(parameters), Some(arguments)) => { + if parameters.len() != arguments.len() { + return Err(ValidationError::WrongTypeArgumentCount { + actual: parameters.len(), + expected: arguments.len(), + }); + } + } + (Some(parameters), None) => { + return Err(ValidationError::WrongTypeArgumentCount { + expected: parameters.len(), + actual: 0, + }) + } + (None, Some(arguments)) => { + return Err(ValidationError::WrongTypeArgumentCount { + expected: 0, + actual: arguments.len(), + }) + } + (None, None) => {} + } + Ok(()) } else { Err(ValidationError::ExpectedFunction { diff --git a/dust-lang/src/lib.rs b/dust-lang/src/lib.rs index a1089da..9d25111 100644 --- a/dust-lang/src/lib.rs +++ b/dust-lang/src/lib.rs @@ -452,7 +452,11 @@ impl InterpreterError { ), ), ValidationError::WrongArguments { .. } => todo!(), - ValidationError::WrongTypeArgumentCount { .. } => todo!(), + ValidationError::WrongTypeArgumentCount { expected, actual } => { + builder = builder.with_message(format!( + "Expected {expected} arguments but got {actual}." + )); + } ValidationError::ExpectedIntegerFloatOrString { actual, position } => { builder = builder.with_message(format!( "Expected an {}, {} or {}.",