From ae05e942f2cb21c8b8979c2afbbf884253655fd2 Mon Sep 17 00:00:00 2001 From: Jeff Date: Fri, 1 Dec 2023 22:16:50 -0500 Subject: [PATCH] Add types for built-in functions --- examples/clue_solver.ds | 7 +++-- src/abstract_tree/function_call.rs | 35 ++++++++++++++--------- src/abstract_tree/function_declaration.rs | 4 +-- src/abstract_tree/identifier.rs | 8 +++++- src/abstract_tree/logic.rs | 21 ++++++++++---- src/built_in_functions/assert.rs | 16 ++++++++++- src/built_in_functions/data_formats.rs | 8 ++++++ src/built_in_functions/fs.rs | 12 ++++++++ src/built_in_functions/mod.rs | 3 +- src/built_in_functions/output.rs | 9 +++++- src/built_in_functions/random.rs | 29 ++++++++++++++++--- src/built_in_functions/type.rs | 4 +++ src/value/function.rs | 24 +++++++++++++++- 13 files changed, 148 insertions(+), 32 deletions(-) diff --git a/examples/clue_solver.ds b/examples/clue_solver.ds index 0f1e5c3..07b0a22 100644 --- a/examples/clue_solver.ds +++ b/examples/clue_solver.ds @@ -5,9 +5,9 @@ all_cards = { } is_ready_to_solve bool> |cards| { - (length cards:suspects) == 1 - && (length cards:rooms) == 1 - && (length cards:weapons) == 1 + ((length cards:suspects) == 1) + && ((length cards:rooms) == 1) + && ((length cards:weapons) == 1) } take_turn map> |opponent_card current_room cards| { @@ -17,6 +17,7 @@ take_turn map> |opponent_card current_room cards| { } remove_card |opponent_card cards| { + (output opponent_card cards) cards:rooms -= opponent_card cards:suspects -= opponent_card cards:weapons -= opponent_card diff --git a/src/abstract_tree/function_call.rs b/src/abstract_tree/function_call.rs index c5743e8..34bb1f3 100644 --- a/src/abstract_tree/function_call.rs +++ b/src/abstract_tree/function_call.rs @@ -41,10 +41,20 @@ impl AbstractTree for FunctionCall { } } - Ok(FunctionCall { + let function_type = function_name.expected_type(context)?; + let function_call = FunctionCall { function_name, arguments, - }) + }; + + function_type.abstract_check( + &function_call.expected_type(context)?, + context, + node, + source, + )?; + + Ok(function_call) } fn run(&self, source: &str, context: &Map) -> Result { @@ -72,21 +82,20 @@ impl AbstractTree for FunctionCall { self.function_name.clone(), )); }; - let mut function_context = Map::clone_from(context)?; - let parameter_expression_pairs = function.parameters().iter().zip(self.arguments.iter()); - for ((identifier, _type), expression) in parameter_expression_pairs { - let key = identifier.clone().take_inner(); - let value = expression.run(source, context)?; - - function_context.variables_mut()?.insert(key, value); - } - - function.body().run(source, &mut function_context) + function.call(&self.arguments, source, context) } fn expected_type(&self, context: &Map) -> Result { - self.function_name.expected_type(context) + let function_name = self.function_name.inner(); + + if let Some(value) = context.variables()?.get(function_name) { + let return_type = value.as_function()?.return_type(); + + Ok(return_type.clone()) + } else { + self.function_name.expected_type(context) + } } } diff --git a/src/abstract_tree/function_declaration.rs b/src/abstract_tree/function_declaration.rs index 7f21e3c..58a706c 100644 --- a/src/abstract_tree/function_declaration.rs +++ b/src/abstract_tree/function_declaration.rs @@ -8,7 +8,7 @@ use crate::{ #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] pub struct FunctionDeclaration { name: Identifier, - _type_definition: TypeDefinition, + type_definition: TypeDefinition, function: Function, } @@ -72,7 +72,7 @@ impl AbstractTree for FunctionDeclaration { Ok(FunctionDeclaration { name, - _type_definition: type_definition, + type_definition, function, }) } diff --git a/src/abstract_tree/identifier.rs b/src/abstract_tree/identifier.rs index 7b23c77..e01f2a1 100644 --- a/src/abstract_tree/identifier.rs +++ b/src/abstract_tree/identifier.rs @@ -1,7 +1,7 @@ use serde::{Deserialize, Serialize}; use tree_sitter::Node; -use crate::{AbstractTree, Error, Map, Result, Type, TypeDefinition, Value}; +use crate::{AbstractTree, Error, Map, Result, Type, TypeDefinition, Value, BUILT_IN_FUNCTIONS}; #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] pub struct Identifier(String); @@ -41,6 +41,12 @@ impl AbstractTree for Identifier { if let Some(value) = context.variables()?.get(&self.0) { value.r#type(context) } else { + for built_in_function in BUILT_IN_FUNCTIONS { + if self.0 == built_in_function.name() { + return Ok(built_in_function.type_definition()); + } + } + Ok(TypeDefinition::new(Type::Empty)) } } diff --git a/src/abstract_tree/logic.rs b/src/abstract_tree/logic.rs index ab97319..a26340c 100644 --- a/src/abstract_tree/logic.rs +++ b/src/abstract_tree/logic.rs @@ -12,10 +12,23 @@ pub struct Logic { impl AbstractTree for Logic { fn from_syntax_node(source: &str, node: Node, context: &Map) -> Result { - let left_node = node.child(0).unwrap(); + let first_node = node.child(0).unwrap(); + let (left_node, operator_node, right_node) = { + if first_node.is_named() { + ( + first_node, + node.child(1).unwrap().child(0).unwrap(), + node.child(2).unwrap(), + ) + } else { + ( + node.child(1).unwrap(), + node.child(2).unwrap().child(0).unwrap(), + node.child(3).unwrap(), + ) + } + }; let left = Expression::from_syntax_node(source, left_node, context)?; - - let operator_node = node.child(1).unwrap().child(0).unwrap(); let operator = match operator_node.kind() { "==" => LogicOperator::Equal, "!=" => LogicOperator::NotEqual, @@ -34,8 +47,6 @@ impl AbstractTree for Logic { }) } }; - - let right_node = node.child(2).unwrap(); let right = Expression::from_syntax_node(source, right_node, context)?; Ok(Logic { diff --git a/src/built_in_functions/assert.rs b/src/built_in_functions/assert.rs index 0a52eda..1b9516d 100644 --- a/src/built_in_functions/assert.rs +++ b/src/built_in_functions/assert.rs @@ -1,4 +1,4 @@ -use crate::{BuiltInFunction, Error, Map, Result, Value}; +use crate::{BuiltInFunction, Error, Map, Result, Type, TypeDefinition, Value}; pub struct Assert; @@ -16,6 +16,13 @@ impl BuiltInFunction for Assert { Ok(Value::Empty) } + + fn type_definition(&self) -> TypeDefinition { + TypeDefinition::new(Type::Function { + parameter_types: vec![Type::Any], + return_type: Box::new(Type::Empty), + }) + } } pub struct AssertEqual; @@ -40,4 +47,11 @@ impl BuiltInFunction for AssertEqual { }) } } + + fn type_definition(&self) -> TypeDefinition { + TypeDefinition::new(Type::Function { + parameter_types: vec![Type::Any, Type::Any], + return_type: Box::new(Type::Boolean), + }) + } } diff --git a/src/built_in_functions/data_formats.rs b/src/built_in_functions/data_formats.rs index 02888bb..846b838 100644 --- a/src/built_in_functions/data_formats.rs +++ b/src/built_in_functions/data_formats.rs @@ -15,6 +15,10 @@ impl BuiltInFunction for FromJson { Ok(value) } + + fn type_definition(&self) -> crate::TypeDefinition { + todo!() + } } pub struct ToJson; @@ -32,4 +36,8 @@ impl BuiltInFunction for ToJson { Ok(Value::String(json_string)) } + + fn type_definition(&self) -> crate::TypeDefinition { + todo!() + } } diff --git a/src/built_in_functions/fs.rs b/src/built_in_functions/fs.rs index 34b2d9a..22b7e1b 100644 --- a/src/built_in_functions/fs.rs +++ b/src/built_in_functions/fs.rs @@ -46,6 +46,10 @@ impl BuiltInFunction for Read { Ok(Value::String(file_content)) } + + fn type_definition(&self) -> crate::TypeDefinition { + todo!() + } } pub struct Write; @@ -63,6 +67,10 @@ impl BuiltInFunction for Write { Ok(Value::Empty) } + + fn type_definition(&self) -> crate::TypeDefinition { + todo!() + } } pub struct Append; @@ -84,4 +92,8 @@ impl BuiltInFunction for Append { Ok(Value::Empty) } + + fn type_definition(&self) -> crate::TypeDefinition { + todo!() + } } diff --git a/src/built_in_functions/mod.rs b/src/built_in_functions/mod.rs index 8be8f65..3d8f8ff 100644 --- a/src/built_in_functions/mod.rs +++ b/src/built_in_functions/mod.rs @@ -1,4 +1,4 @@ -use crate::{Map, Result, Value}; +use crate::{Map, Result, TypeDefinition, Value}; mod assert; mod data_formats; @@ -26,4 +26,5 @@ pub const BUILT_IN_FUNCTIONS: [&dyn BuiltInFunction; 13] = [ pub trait BuiltInFunction { fn name(&self) -> &'static str; fn run(&self, arguments: &[Value], context: &Map) -> Result; + fn type_definition(&self) -> TypeDefinition; } diff --git a/src/built_in_functions/output.rs b/src/built_in_functions/output.rs index 859edb2..44105cb 100644 --- a/src/built_in_functions/output.rs +++ b/src/built_in_functions/output.rs @@ -1,4 +1,4 @@ -use crate::{BuiltInFunction, Map, Result, Value}; +use crate::{BuiltInFunction, Map, Result, Type, TypeDefinition, Value}; pub struct Output; @@ -14,4 +14,11 @@ impl BuiltInFunction for Output { Ok(Value::Empty) } + + fn type_definition(&self) -> crate::TypeDefinition { + TypeDefinition::new(Type::Function { + parameter_types: vec![Type::Any], + return_type: Box::new(Type::Empty), + }) + } } diff --git a/src/built_in_functions/random.rs b/src/built_in_functions/random.rs index 94bd097..eb3f432 100644 --- a/src/built_in_functions/random.rs +++ b/src/built_in_functions/random.rs @@ -1,6 +1,6 @@ use rand::{random, thread_rng, Rng}; -use crate::{BuiltInFunction, Error, Map, Result, Value}; +use crate::{BuiltInFunction, Error, Map, Result, Type, TypeDefinition, Value}; pub struct Random; @@ -10,13 +10,22 @@ impl BuiltInFunction for Random { } fn run(&self, arguments: &[Value], _context: &Map) -> Result { - Error::expect_argument_minimum(self, 2, arguments.len())?; + Error::expect_argument_minimum(self, 1, arguments.len())?; - let random_index = thread_rng().gen_range(0..arguments.len()); - let random_argument = arguments.get(random_index).unwrap(); + let list = arguments.first().unwrap().as_list()?; + let items = list.items(); + let random_index = thread_rng().gen_range(0..items.len()); + let random_argument = items.get(random_index).unwrap(); Ok(random_argument.clone()) } + + fn type_definition(&self) -> TypeDefinition { + TypeDefinition::new(Type::Function { + parameter_types: vec![Type::List(Box::new(Type::Any))], + return_type: Box::new(Type::Any), + }) + } } pub struct RandomInteger; @@ -31,6 +40,10 @@ impl BuiltInFunction for RandomInteger { Ok(Value::Integer(random())) } + + fn type_definition(&self) -> crate::TypeDefinition { + todo!() + } } pub struct RandomFloat; @@ -45,6 +58,10 @@ impl BuiltInFunction for RandomFloat { Ok(Value::Float(random())) } + + fn type_definition(&self) -> crate::TypeDefinition { + todo!() + } } pub struct RandomBoolean; @@ -59,4 +76,8 @@ impl BuiltInFunction for RandomBoolean { Ok(Value::Boolean(random())) } + + fn type_definition(&self) -> crate::TypeDefinition { + todo!() + } } diff --git a/src/built_in_functions/type.rs b/src/built_in_functions/type.rs index ff8caee..8ebffb1 100644 --- a/src/built_in_functions/type.rs +++ b/src/built_in_functions/type.rs @@ -31,4 +31,8 @@ impl BuiltInFunction for Type { Ok(Value::List(List::with_items(answers))) } } + + fn type_definition(&self) -> crate::TypeDefinition { + todo!() + } } diff --git a/src/value/function.rs b/src/value/function.rs index 3d7fdb0..04f30a8 100644 --- a/src/value/function.rs +++ b/src/value/function.rs @@ -2,7 +2,7 @@ use std::fmt::{self, Display, Formatter}; use serde::{Deserialize, Serialize}; -use crate::{Block, Identifier, TypeDefinition}; +use crate::{AbstractTree, Block, Expression, Identifier, Map, Result, TypeDefinition, Value}; #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] pub struct Function { @@ -35,6 +35,28 @@ impl Function { pub fn return_type(&self) -> &TypeDefinition { &self.return_type } + + pub fn call(&self, arguments: &[Expression], source: &str, context: &Map) -> Result { + let function_context = Map::new(); + let parameter_argument_pairs = self.parameters.iter().zip(arguments.iter()); + + for ((identifier, type_definition), expression) in parameter_argument_pairs { + let key = identifier.inner(); + let value = expression.run(source, context)?; + + println!("{key} {value}"); + + type_definition.runtime_check(&value.r#type(context)?, context)?; + function_context.variables_mut()?.insert(key.clone(), value); + } + + let return_value = self.body.run(source, &function_context)?; + + self.return_type + .runtime_check(&return_value.r#type(context)?, context)?; + + Ok(return_value) + } } impl Display for Function {