Add types for built-in functions
This commit is contained in:
parent
50abe9765a
commit
ae05e942f2
@ -5,9 +5,9 @@ all_cards = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
is_ready_to_solve <fn map -> bool> |cards| {
|
is_ready_to_solve <fn map -> bool> |cards| {
|
||||||
(length cards:suspects) == 1
|
((length cards:suspects) == 1)
|
||||||
&& (length cards:rooms) == 1
|
&& ((length cards:rooms) == 1)
|
||||||
&& (length cards:weapons) == 1
|
&& ((length cards:weapons) == 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
take_turn <fn str str map -> map> |opponent_card current_room cards| {
|
take_turn <fn str str map -> map> |opponent_card current_room cards| {
|
||||||
@ -17,6 +17,7 @@ take_turn <fn str str map -> map> |opponent_card current_room cards| {
|
|||||||
}
|
}
|
||||||
|
|
||||||
remove_card <fn str map> |opponent_card cards| {
|
remove_card <fn str map> |opponent_card cards| {
|
||||||
|
(output opponent_card cards)
|
||||||
cards:rooms -= opponent_card
|
cards:rooms -= opponent_card
|
||||||
cards:suspects -= opponent_card
|
cards:suspects -= opponent_card
|
||||||
cards:weapons -= opponent_card
|
cards:weapons -= opponent_card
|
||||||
|
@ -41,10 +41,20 @@ impl AbstractTree for FunctionCall {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(FunctionCall {
|
let function_type = function_name.expected_type(context)?;
|
||||||
|
let function_call = FunctionCall {
|
||||||
function_name,
|
function_name,
|
||||||
arguments,
|
arguments,
|
||||||
})
|
};
|
||||||
|
|
||||||
|
function_type.abstract_check(
|
||||||
|
&function_call.expected_type(context)?,
|
||||||
|
context,
|
||||||
|
node,
|
||||||
|
source,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(function_call)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
||||||
@ -72,22 +82,21 @@ impl AbstractTree for FunctionCall {
|
|||||||
self.function_name.clone(),
|
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 {
|
function.call(&self.arguments, source, context)
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, context: &Map) -> Result<TypeDefinition> {
|
fn expected_type(&self, context: &Map) -> Result<TypeDefinition> {
|
||||||
|
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)
|
self.function_name.expected_type(context)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -8,7 +8,7 @@ use crate::{
|
|||||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub struct FunctionDeclaration {
|
pub struct FunctionDeclaration {
|
||||||
name: Identifier,
|
name: Identifier,
|
||||||
_type_definition: TypeDefinition,
|
type_definition: TypeDefinition,
|
||||||
function: Function,
|
function: Function,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,7 +72,7 @@ impl AbstractTree for FunctionDeclaration {
|
|||||||
|
|
||||||
Ok(FunctionDeclaration {
|
Ok(FunctionDeclaration {
|
||||||
name,
|
name,
|
||||||
_type_definition: type_definition,
|
type_definition,
|
||||||
function,
|
function,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tree_sitter::Node;
|
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)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub struct Identifier(String);
|
pub struct Identifier(String);
|
||||||
@ -41,6 +41,12 @@ impl AbstractTree for Identifier {
|
|||||||
if let Some(value) = context.variables()?.get(&self.0) {
|
if let Some(value) = context.variables()?.get(&self.0) {
|
||||||
value.r#type(context)
|
value.r#type(context)
|
||||||
} else {
|
} 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))
|
Ok(TypeDefinition::new(Type::Empty))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,10 +12,23 @@ pub struct Logic {
|
|||||||
|
|
||||||
impl AbstractTree for Logic {
|
impl AbstractTree for Logic {
|
||||||
fn from_syntax_node(source: &str, node: Node, context: &Map) -> Result<Self> {
|
fn from_syntax_node(source: &str, node: Node, context: &Map) -> Result<Self> {
|
||||||
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 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() {
|
let operator = match operator_node.kind() {
|
||||||
"==" => LogicOperator::Equal,
|
"==" => LogicOperator::Equal,
|
||||||
"!=" => LogicOperator::NotEqual,
|
"!=" => 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)?;
|
let right = Expression::from_syntax_node(source, right_node, context)?;
|
||||||
|
|
||||||
Ok(Logic {
|
Ok(Logic {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::{BuiltInFunction, Error, Map, Result, Value};
|
use crate::{BuiltInFunction, Error, Map, Result, Type, TypeDefinition, Value};
|
||||||
|
|
||||||
pub struct Assert;
|
pub struct Assert;
|
||||||
|
|
||||||
@ -16,6 +16,13 @@ impl BuiltInFunction for Assert {
|
|||||||
|
|
||||||
Ok(Value::Empty)
|
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;
|
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),
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,10 @@ impl BuiltInFunction for FromJson {
|
|||||||
|
|
||||||
Ok(value)
|
Ok(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn type_definition(&self) -> crate::TypeDefinition {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ToJson;
|
pub struct ToJson;
|
||||||
@ -32,4 +36,8 @@ impl BuiltInFunction for ToJson {
|
|||||||
|
|
||||||
Ok(Value::String(json_string))
|
Ok(Value::String(json_string))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn type_definition(&self) -> crate::TypeDefinition {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,6 +46,10 @@ impl BuiltInFunction for Read {
|
|||||||
|
|
||||||
Ok(Value::String(file_content))
|
Ok(Value::String(file_content))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn type_definition(&self) -> crate::TypeDefinition {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Write;
|
pub struct Write;
|
||||||
@ -63,6 +67,10 @@ impl BuiltInFunction for Write {
|
|||||||
|
|
||||||
Ok(Value::Empty)
|
Ok(Value::Empty)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn type_definition(&self) -> crate::TypeDefinition {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Append;
|
pub struct Append;
|
||||||
@ -84,4 +92,8 @@ impl BuiltInFunction for Append {
|
|||||||
|
|
||||||
Ok(Value::Empty)
|
Ok(Value::Empty)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn type_definition(&self) -> crate::TypeDefinition {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::{Map, Result, Value};
|
use crate::{Map, Result, TypeDefinition, Value};
|
||||||
|
|
||||||
mod assert;
|
mod assert;
|
||||||
mod data_formats;
|
mod data_formats;
|
||||||
@ -26,4 +26,5 @@ pub const BUILT_IN_FUNCTIONS: [&dyn BuiltInFunction; 13] = [
|
|||||||
pub trait BuiltInFunction {
|
pub trait BuiltInFunction {
|
||||||
fn name(&self) -> &'static str;
|
fn name(&self) -> &'static str;
|
||||||
fn run(&self, arguments: &[Value], context: &Map) -> Result<Value>;
|
fn run(&self, arguments: &[Value], context: &Map) -> Result<Value>;
|
||||||
|
fn type_definition(&self) -> TypeDefinition;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::{BuiltInFunction, Map, Result, Value};
|
use crate::{BuiltInFunction, Map, Result, Type, TypeDefinition, Value};
|
||||||
|
|
||||||
pub struct Output;
|
pub struct Output;
|
||||||
|
|
||||||
@ -14,4 +14,11 @@ impl BuiltInFunction for Output {
|
|||||||
|
|
||||||
Ok(Value::Empty)
|
Ok(Value::Empty)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn type_definition(&self) -> crate::TypeDefinition {
|
||||||
|
TypeDefinition::new(Type::Function {
|
||||||
|
parameter_types: vec![Type::Any],
|
||||||
|
return_type: Box::new(Type::Empty),
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use rand::{random, thread_rng, Rng};
|
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;
|
pub struct Random;
|
||||||
|
|
||||||
@ -10,13 +10,22 @@ impl BuiltInFunction for Random {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn run(&self, arguments: &[Value], _context: &Map) -> Result<Value> {
|
fn run(&self, arguments: &[Value], _context: &Map) -> Result<Value> {
|
||||||
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 list = arguments.first().unwrap().as_list()?;
|
||||||
let random_argument = arguments.get(random_index).unwrap();
|
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())
|
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;
|
pub struct RandomInteger;
|
||||||
@ -31,6 +40,10 @@ impl BuiltInFunction for RandomInteger {
|
|||||||
|
|
||||||
Ok(Value::Integer(random()))
|
Ok(Value::Integer(random()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn type_definition(&self) -> crate::TypeDefinition {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct RandomFloat;
|
pub struct RandomFloat;
|
||||||
@ -45,6 +58,10 @@ impl BuiltInFunction for RandomFloat {
|
|||||||
|
|
||||||
Ok(Value::Float(random()))
|
Ok(Value::Float(random()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn type_definition(&self) -> crate::TypeDefinition {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct RandomBoolean;
|
pub struct RandomBoolean;
|
||||||
@ -59,4 +76,8 @@ impl BuiltInFunction for RandomBoolean {
|
|||||||
|
|
||||||
Ok(Value::Boolean(random()))
|
Ok(Value::Boolean(random()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn type_definition(&self) -> crate::TypeDefinition {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,4 +31,8 @@ impl BuiltInFunction for Type {
|
|||||||
Ok(Value::List(List::with_items(answers)))
|
Ok(Value::List(List::with_items(answers)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn type_definition(&self) -> crate::TypeDefinition {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ use std::fmt::{self, Display, Formatter};
|
|||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
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)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub struct Function {
|
pub struct Function {
|
||||||
@ -35,6 +35,28 @@ impl Function {
|
|||||||
pub fn return_type(&self) -> &TypeDefinition {
|
pub fn return_type(&self) -> &TypeDefinition {
|
||||||
&self.return_type
|
&self.return_type
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn call(&self, arguments: &[Expression], source: &str, context: &Map) -> Result<Value> {
|
||||||
|
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 {
|
impl Display for Function {
|
||||||
|
Loading…
Reference in New Issue
Block a user