Pass all tests

This commit is contained in:
Jeff 2024-06-24 10:09:07 -04:00
parent 63f648c3ac
commit a5c5075e6b
3 changed files with 97 additions and 33 deletions

View File

@ -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::{Deserialize, Serialize};
use serde_json::from_str; use serde_json::from_str;
@ -11,7 +11,7 @@ use crate::{
Value, Value,
}; };
use super::{AbstractNode, Evaluation, Expression, Type, TypeConstructor}; use super::Type;
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum BuiltInFunction { pub enum BuiltInFunction {
@ -98,13 +98,29 @@ impl FunctionLogic for ReadFile {
fn r#type() -> Type { fn r#type() -> Type {
Type::Function { Type::Function {
type_parameters: None, type_parameters: None,
value_parameters: None, value_parameters: Some(vec![(Identifier::new("path"), Type::String)]),
return_type: Some(Box::new(Type::String)), return_type: Some(Box::new(Type::String)),
} }
} }
fn call(context: &Context, manage_memory: bool) -> Result<Option<Value>, RuntimeError> { fn call(context: &Context, manage_memory: bool) -> Result<Option<Value>, 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<Option<Value>, RuntimeError> { fn call(context: &Context, manage_memory: bool) -> Result<Option<Value>, 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 { fn r#type() -> Type {
Type::Function { Type::Function {
type_parameters: None, type_parameters: None,
value_parameters: None, value_parameters: Some(vec![(Identifier::new("milliseconds"), Type::Integer)]),
return_type: None, return_type: None,
} }
} }
fn call(context: &Context, manage_memory: bool) -> Result<Option<Value>, RuntimeError> { fn call(context: &Context, manage_memory: bool) -> Result<Option<Value>, 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 { fn r#type() -> Type {
Type::Function { Type::Function {
type_parameters: None, type_parameters: None,
value_parameters: None, value_parameters: Some(vec![(Identifier::new("output"), Type::String)]),
return_type: None, return_type: None,
} }
} }
@ -162,7 +199,7 @@ impl FunctionLogic for WriteLine {
ValidationError::BuiltInFunctionFailure("output does not exist"), 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 string
} else { } else {
return Err(RuntimeError::ValidationFailure( return Err(RuntimeError::ValidationFailure(
@ -170,7 +207,7 @@ impl FunctionLogic for WriteLine {
)); ));
}; };
println!("{input}"); println!("{output}");
Ok(None) Ok(None)
} }
@ -181,13 +218,15 @@ struct JsonParse;
impl FunctionLogic for JsonParse { impl FunctionLogic for JsonParse {
fn r#type() -> Type { fn r#type() -> Type {
Type::Function { let type_t = Type::Generic {
type_parameters: None,
value_parameters: None,
return_type: Some(Box::new(Type::Generic {
identifier: Identifier::new("T"), identifier: Identifier::new("T"),
concrete_type: None, concrete_type: None,
})), };
Type::Function {
type_parameters: None,
value_parameters: Some(vec![(Identifier::new("input"), type_t.clone())]),
return_type: Some(Box::new(type_t)),
} }
} }

View File

@ -47,14 +47,6 @@ impl AbstractNode for FunctionCall {
} }
fn validate(&self, context: &Context, manage_memory: bool) -> Result<(), ValidationError> { 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)?; self.function_expression.validate(context, manage_memory)?;
if let Some(value_arguments) = &self.value_arguments { if let Some(value_arguments) = &self.value_arguments {
@ -63,8 +55,13 @@ impl AbstractNode for FunctionCall {
} }
} }
let function_node_type = let function_node_type = if let Expression::Value(WithPosition {
if let Some(r#type) = self.function_expression.expected_type(context)? { 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 r#type
} else { } else {
return Err(ValidationError::ExpectedExpression( return Err(ValidationError::ExpectedExpression(
@ -74,7 +71,7 @@ impl AbstractNode for FunctionCall {
if let Type::Function { if let Type::Function {
type_parameters, type_parameters,
value_parameters: _, value_parameters,
return_type: _, return_type: _,
} = function_node_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(()) Ok(())
} else { } else {
Err(ValidationError::ExpectedFunction { Err(ValidationError::ExpectedFunction {

View File

@ -452,7 +452,11 @@ impl InterpreterError {
), ),
), ),
ValidationError::WrongArguments { .. } => todo!(), 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 } => { ValidationError::ExpectedIntegerFloatOrString { actual, position } => {
builder = builder.with_message(format!( builder = builder.with_message(format!(
"Expected an {}, {} or {}.", "Expected an {}, {} or {}.",