Implement type checking for functions and indexes
This commit is contained in:
parent
b91e23fef3
commit
ce4d366bab
@ -1,4 +1,4 @@
|
|||||||
create_random_numbers <(int)> = fn |count| {
|
create_random_numbers = (fn count <int>) <any> {
|
||||||
numbers = []
|
numbers = []
|
||||||
|
|
||||||
while (length numbers) < count {
|
while (length numbers) < count {
|
||||||
|
@ -4,26 +4,26 @@ all_cards = {
|
|||||||
weapons = ['Rope' 'Lead_Pipe' 'Knife']
|
weapons = ['Rope' 'Lead_Pipe' 'Knife']
|
||||||
}
|
}
|
||||||
|
|
||||||
is_ready_to_solve <(map) -> bool> = fn |cards| {
|
is_ready_to_solve = (fn cards <map>) <bool> {
|
||||||
((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 <(map str str) -> map> = fn |cards opponent_card current_room| {
|
take_turn = (fn cards <map>, opponent_card <str>, current_room <str>) <map> {
|
||||||
cards = (remove_card opponent_card cards)
|
cards = (remove_card opponent_card cards)
|
||||||
cards = (make_guess current_room cards)
|
cards = (make_guess current_room cards)
|
||||||
cards
|
cards
|
||||||
}
|
}
|
||||||
|
|
||||||
remove_card <(map str) -> map> = fn |cards opponent_card| {
|
remove_card = (fn cards <map>, opponent_card <str>) <map> {
|
||||||
cards:rooms -= opponent_card
|
cards:rooms -= opponent_card
|
||||||
cards:suspects -= opponent_card
|
cards:suspects -= opponent_card
|
||||||
cards:weapons -= opponent_card
|
cards:weapons -= opponent_card
|
||||||
cards
|
cards
|
||||||
}
|
}
|
||||||
|
|
||||||
make_guess <(map str)> = fn |cards current_room| {
|
make_guess = (fn cards <map> current_room <str>) <map> {
|
||||||
if (is_ready_to_solve cards) {
|
if (is_ready_to_solve cards) {
|
||||||
(output 'It was '
|
(output 'It was '
|
||||||
+ cards:suspects:0
|
+ cards:suspects:0
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
1 -> (output)
|
1 -> (output)
|
||||||
|
|
||||||
add_one <([int]) -> [int]> = fn |numbers| {
|
add_one = (fn numbers <[int]>) <[int]> {
|
||||||
new_numbers = []
|
new_numbers = []
|
||||||
|
|
||||||
for number in numbers {
|
for number in numbers {
|
||||||
|
@ -57,9 +57,14 @@ impl AbstractTree for Assignment {
|
|||||||
|
|
||||||
let statement_node = node.child(child_count - 1).unwrap();
|
let statement_node = node.child(child_count - 1).unwrap();
|
||||||
let statement = Statement::from_syntax_node(source, statement_node, context)?;
|
let statement = Statement::from_syntax_node(source, statement_node, context)?;
|
||||||
|
let statement_type = statement.expected_type(context)?;
|
||||||
|
|
||||||
if let Some(type_definition) = &type_definition {
|
if let Some(type_definition) = &type_definition {
|
||||||
let statement_type = statement.expected_type(context)?;
|
context.set(
|
||||||
|
identifier.inner().clone(),
|
||||||
|
Value::Empty,
|
||||||
|
Some(type_definition.inner().clone()),
|
||||||
|
)?;
|
||||||
|
|
||||||
match operator {
|
match operator {
|
||||||
AssignmentOperator::Equal => {
|
AssignmentOperator::Equal => {
|
||||||
@ -78,22 +83,6 @@ impl AbstractTree for Assignment {
|
|||||||
}
|
}
|
||||||
AssignmentOperator::MinusEqual => todo!(),
|
AssignmentOperator::MinusEqual => todo!(),
|
||||||
}
|
}
|
||||||
} else if let Some((_previous_value, previous_type)) =
|
|
||||||
context.variables()?.get(identifier.inner())
|
|
||||||
{
|
|
||||||
let statement_type = statement.expected_type(context)?;
|
|
||||||
let type_check = if let Type::List(item_type) = previous_type {
|
|
||||||
item_type.check(&statement_type)
|
|
||||||
} else {
|
|
||||||
previous_type.check(&statement_type)
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Err(error) = type_check {
|
|
||||||
return Err(error.with_context(
|
|
||||||
statement_node.start_position(),
|
|
||||||
source[statement_node.byte_range()].to_string(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Assignment {
|
Ok(Assignment {
|
||||||
@ -129,6 +118,8 @@ impl AbstractTree for Assignment {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if let Some(type_defintion) = &self.type_definition {
|
if let Some(type_defintion) = &self.type_definition {
|
||||||
|
type_defintion.inner().check(&new_value.r#type())?;
|
||||||
|
|
||||||
context.set(key.clone(), new_value, Some(type_defintion.inner().clone()))?;
|
context.set(key.clone(), new_value, Some(type_defintion.inner().clone()))?;
|
||||||
} else {
|
} else {
|
||||||
context.set(key.clone(), new_value, None)?;
|
context.set(key.clone(), new_value, None)?;
|
||||||
|
@ -57,9 +57,7 @@ impl AbstractTree for For {
|
|||||||
values.par_iter().try_for_each(|value| {
|
values.par_iter().try_for_each(|value| {
|
||||||
let mut iter_context = Map::clone_from(context)?;
|
let mut iter_context = Map::clone_from(context)?;
|
||||||
|
|
||||||
iter_context
|
iter_context.set(key.clone(), value.clone(), None)?;
|
||||||
.variables_mut()?
|
|
||||||
.insert(key.clone(), (value.clone(), value.r#type()));
|
|
||||||
|
|
||||||
self.block.run(source, &mut iter_context).map(|_value| ())
|
self.block.run(source, &mut iter_context).map(|_value| ())
|
||||||
})?;
|
})?;
|
||||||
@ -67,9 +65,7 @@ impl AbstractTree for For {
|
|||||||
let loop_context = Map::clone_from(context)?;
|
let loop_context = Map::clone_from(context)?;
|
||||||
|
|
||||||
for value in values.iter() {
|
for value in values.iter() {
|
||||||
loop_context
|
loop_context.set(key.clone(), value.clone(), None)?;
|
||||||
.variables_mut()?
|
|
||||||
.insert(key.clone(), (value.clone(), value.r#type()));
|
|
||||||
|
|
||||||
self.block.run(source, &mut loop_context.clone())?;
|
self.block.run(source, &mut loop_context.clone())?;
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@ impl AbstractTree for FunctionCall {
|
|||||||
|
|
||||||
let expression_node = node.child(1).unwrap();
|
let expression_node = node.child(1).unwrap();
|
||||||
let function_expression = Expression::from_syntax_node(source, expression_node, context)?;
|
let function_expression = Expression::from_syntax_node(source, expression_node, context)?;
|
||||||
|
let function_type = function_expression.expected_type(context)?;
|
||||||
|
|
||||||
let mut arguments = Vec::new();
|
let mut arguments = Vec::new();
|
||||||
|
|
||||||
@ -34,24 +35,28 @@ impl AbstractTree for FunctionCall {
|
|||||||
|
|
||||||
if child.is_named() {
|
if child.is_named() {
|
||||||
let expression = Expression::from_syntax_node(source, child, context)?;
|
let expression = Expression::from_syntax_node(source, child, context)?;
|
||||||
|
let expression_type = expression.expected_type(context)?;
|
||||||
arguments.push(expression);
|
let argument_index = arguments.len();
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let function_type = function_expression.expected_type(context)?;
|
|
||||||
|
|
||||||
if let Type::Function {
|
if let Type::Function {
|
||||||
parameter_types,
|
parameter_types,
|
||||||
return_type: _,
|
return_type: _,
|
||||||
} = function_type
|
} = &function_type
|
||||||
{
|
{
|
||||||
let argument_type_pairs = arguments.iter().zip(parameter_types.iter());
|
let expected_type = parameter_types.get(argument_index).unwrap();
|
||||||
|
|
||||||
for (argument, r#type) in argument_type_pairs {
|
println!("{expected_type} {expression_type}");
|
||||||
let argument_type = argument.expected_type(context)?;
|
|
||||||
|
|
||||||
r#type.check(&argument_type)?;
|
expected_type
|
||||||
|
.check(&expression_type)
|
||||||
|
.map_err(|error| Error::WithContext {
|
||||||
|
error: Box::new(error),
|
||||||
|
location: child.start_position(),
|
||||||
|
source: source[child.byte_range()].to_string(),
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
|
||||||
|
arguments.push(expression);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,7 +47,9 @@ impl AbstractTree for Identifier {
|
|||||||
} else {
|
} else {
|
||||||
for built_in_function in BUILT_IN_FUNCTIONS {
|
for built_in_function in BUILT_IN_FUNCTIONS {
|
||||||
if self.0 == built_in_function.name() {
|
if self.0 == built_in_function.name() {
|
||||||
return Ok(built_in_function.r#type());
|
if let Type::Function { return_type, .. } = built_in_function.r#type() {
|
||||||
|
return Ok(*return_type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,7 +88,12 @@ impl AbstractTree for Index {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, context: &Map) -> Result<Type> {
|
fn expected_type(&self, context: &Map) -> Result<Type> {
|
||||||
self.collection.expected_type(context)
|
match self.collection.expected_type(context)? {
|
||||||
|
Type::List(item_type) => Ok(*item_type.clone()),
|
||||||
|
Type::Map => Ok(Type::Any),
|
||||||
|
Type::Empty => Ok(Type::Empty),
|
||||||
|
_ => todo!(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,11 +85,8 @@ impl AbstractTree for IndexAssignment {
|
|||||||
}
|
}
|
||||||
AssignmentOperator::Equal => value,
|
AssignmentOperator::Equal => value,
|
||||||
};
|
};
|
||||||
let new_value_type = new_value.r#type();
|
|
||||||
|
|
||||||
index_context
|
index_context.set(index_key.clone(), new_value, None)?;
|
||||||
.variables_mut()?
|
|
||||||
.insert(index_key.clone(), (new_value, new_value_type));
|
|
||||||
|
|
||||||
Ok(Value::Empty)
|
Ok(Value::Empty)
|
||||||
}
|
}
|
||||||
|
@ -76,8 +76,10 @@ impl AbstractTree for Match {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expected_type(&self, _context: &Map) -> Result<Type> {
|
fn expected_type(&self, context: &Map) -> Result<Type> {
|
||||||
todo!()
|
let (_, first_statement) = self.options.first().unwrap();
|
||||||
|
|
||||||
|
first_statement.expected_type(context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ pub mod logic;
|
|||||||
pub mod r#match;
|
pub mod r#match;
|
||||||
pub mod math;
|
pub mod math;
|
||||||
pub mod statement;
|
pub mod statement;
|
||||||
pub mod type_defintion;
|
pub mod type_definition;
|
||||||
pub mod r#use;
|
pub mod r#use;
|
||||||
pub mod value_node;
|
pub mod value_node;
|
||||||
pub mod r#while;
|
pub mod r#while;
|
||||||
@ -28,7 +28,7 @@ pub mod r#yield;
|
|||||||
pub use {
|
pub use {
|
||||||
assignment::*, block::*, expression::*, function_call::*, identifier::*, if_else::*, index::*,
|
assignment::*, block::*, expression::*, function_call::*, identifier::*, if_else::*, index::*,
|
||||||
index_assignment::IndexAssignment, logic::*, math::*, r#for::*, r#match::*, r#use::*,
|
index_assignment::IndexAssignment, logic::*, math::*, r#for::*, r#match::*, r#use::*,
|
||||||
r#while::*, r#yield::*, statement::*, type_defintion::*, value_node::*,
|
r#while::*, r#yield::*, statement::*, type_definition::*, value_node::*,
|
||||||
};
|
};
|
||||||
|
|
||||||
use tree_sitter::Node;
|
use tree_sitter::Node;
|
||||||
|
@ -100,10 +100,24 @@ impl Type {
|
|||||||
.zip(other_parameter_types.iter());
|
.zip(other_parameter_types.iter());
|
||||||
|
|
||||||
for (self_parameter_type, other_parameter_type) in parameter_type_pairs {
|
for (self_parameter_type, other_parameter_type) in parameter_type_pairs {
|
||||||
self_parameter_type.check(&other_parameter_type)?;
|
let check = self_parameter_type.check(&other_parameter_type);
|
||||||
|
|
||||||
|
if let Err(Error::TypeCheck { .. }) = check {
|
||||||
|
return Err(Error::TypeCheck {
|
||||||
|
expected: self.clone(),
|
||||||
|
actual: other.clone(),
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self_return_type.check(other_return_type)?;
|
let check = self_return_type.check(other_return_type);
|
||||||
|
|
||||||
|
if let Err(Error::TypeCheck { .. }) = check {
|
||||||
|
return Err(Error::TypeCheck {
|
||||||
|
expected: self.clone(),
|
||||||
|
actual: other.clone(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1,217 +0,0 @@
|
|||||||
use std::fmt::{self, Display, Formatter};
|
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use tree_sitter::Node;
|
|
||||||
|
|
||||||
use crate::{AbstractTree, Error, Map, Result, Value};
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
|
||||||
pub struct TypeDefinition {
|
|
||||||
r#type: Type,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TypeDefinition {
|
|
||||||
pub fn new(r#type: Type) -> Self {
|
|
||||||
Self { r#type }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn inner(&self) -> &Type {
|
|
||||||
&self.r#type
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn take_inner(self) -> Type {
|
|
||||||
self.r#type
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AbstractTree for TypeDefinition {
|
|
||||||
fn from_syntax_node(source: &str, node: Node, context: &Map) -> Result<Self> {
|
|
||||||
Error::expect_syntax_node(source, "type_definition", node)?;
|
|
||||||
|
|
||||||
let type_node = node.child(1).unwrap();
|
|
||||||
let r#type = Type::from_syntax_node(source, type_node, context)?;
|
|
||||||
|
|
||||||
Ok(TypeDefinition { r#type })
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(&self, source: &str, context: &Map) -> Result<Value> {
|
|
||||||
self.r#type.run(source, context)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn expected_type(&self, context: &Map) -> Result<Type> {
|
|
||||||
self.r#type.expected_type(context)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for TypeDefinition {
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
|
||||||
write!(f, "<{}>", self.r#type)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)]
|
|
||||||
pub enum Type {
|
|
||||||
Any,
|
|
||||||
Boolean,
|
|
||||||
Empty,
|
|
||||||
Float,
|
|
||||||
Function {
|
|
||||||
parameter_types: Vec<Type>,
|
|
||||||
return_type: Box<Type>,
|
|
||||||
},
|
|
||||||
Integer,
|
|
||||||
List(Box<Type>),
|
|
||||||
Map,
|
|
||||||
Number,
|
|
||||||
String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Type {
|
|
||||||
pub fn check(&self, other: &Type) -> Result<()> {
|
|
||||||
match (self, other) {
|
|
||||||
(Type::Any, _)
|
|
||||||
| (_, Type::Any)
|
|
||||||
| (Type::Boolean, Type::Boolean)
|
|
||||||
| (Type::Empty, Type::Empty)
|
|
||||||
| (Type::Float, Type::Float)
|
|
||||||
| (Type::Integer, Type::Integer)
|
|
||||||
| (Type::Map, Type::Map)
|
|
||||||
| (Type::Number, Type::Number)
|
|
||||||
| (Type::Number, Type::Integer)
|
|
||||||
| (Type::Number, Type::Float)
|
|
||||||
| (Type::Integer, Type::Number)
|
|
||||||
| (Type::Float, Type::Number)
|
|
||||||
| (Type::String, Type::String) => Ok(()),
|
|
||||||
(Type::List(self_item_type), Type::List(other_item_type)) => {
|
|
||||||
self_item_type.check(&other_item_type)
|
|
||||||
}
|
|
||||||
(
|
|
||||||
Type::Function {
|
|
||||||
parameter_types: self_parameter_types,
|
|
||||||
return_type: self_return_type,
|
|
||||||
},
|
|
||||||
Type::Function {
|
|
||||||
parameter_types: other_parameter_types,
|
|
||||||
return_type: other_return_type,
|
|
||||||
},
|
|
||||||
) => {
|
|
||||||
let parameter_type_pairs = self_parameter_types
|
|
||||||
.iter()
|
|
||||||
.zip(other_parameter_types.iter());
|
|
||||||
|
|
||||||
for (self_parameter_type, other_parameter_type) in parameter_type_pairs {
|
|
||||||
self_parameter_type.check(&other_parameter_type)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
self_return_type.check(other_return_type)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
_ => Err(Error::TypeCheck {
|
|
||||||
expected: self.clone(),
|
|
||||||
actual: other.clone(),
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AbstractTree for Type {
|
|
||||||
fn from_syntax_node(source: &str, node: Node, context: &Map) -> Result<Self> {
|
|
||||||
Error::expect_syntax_node(source, "type", node)?;
|
|
||||||
|
|
||||||
let type_node = node.child(0).unwrap();
|
|
||||||
|
|
||||||
let r#type = match type_node.kind() {
|
|
||||||
"[" => {
|
|
||||||
let item_type_node = node.child(1).unwrap();
|
|
||||||
let item_type = Type::from_syntax_node(source, item_type_node, context)?;
|
|
||||||
|
|
||||||
Type::List(Box::new(item_type))
|
|
||||||
}
|
|
||||||
"any" => Type::Any,
|
|
||||||
"bool" => Type::Boolean,
|
|
||||||
"float" => Type::Float,
|
|
||||||
"(" => {
|
|
||||||
let child_count = node.child_count();
|
|
||||||
let mut parameter_types = Vec::new();
|
|
||||||
|
|
||||||
for index in 1..child_count - 2 {
|
|
||||||
let child = node.child(index).unwrap();
|
|
||||||
|
|
||||||
if child.is_named() {
|
|
||||||
let parameter_type = Type::from_syntax_node(source, child, context)?;
|
|
||||||
|
|
||||||
parameter_types.push(parameter_type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let final_node = node.child(child_count - 1).unwrap();
|
|
||||||
let return_type = if final_node.is_named() {
|
|
||||||
Type::from_syntax_node(source, final_node, context)?
|
|
||||||
} else {
|
|
||||||
Type::Empty
|
|
||||||
};
|
|
||||||
|
|
||||||
Type::Function {
|
|
||||||
parameter_types,
|
|
||||||
return_type: Box::new(return_type),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"int" => Type::Integer,
|
|
||||||
"map" => Type::Map,
|
|
||||||
"num" => Type::Number,
|
|
||||||
"str" => Type::String,
|
|
||||||
_ => {
|
|
||||||
return Err(Error::UnexpectedSyntaxNode {
|
|
||||||
expected: "any, bool, float, fn, int, list, map, num or str",
|
|
||||||
actual: type_node.kind(),
|
|
||||||
location: type_node.start_position(),
|
|
||||||
relevant_source: source[type_node.byte_range()].to_string(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(r#type)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run(&self, _source: &str, _context: &Map) -> Result<Value> {
|
|
||||||
Ok(Value::Empty)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn expected_type(&self, _context: &Map) -> Result<Type> {
|
|
||||||
Ok(Type::Empty)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Type {
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
Type::Any => write!(f, "any"),
|
|
||||||
Type::Boolean => write!(f, "bool"),
|
|
||||||
Type::Empty => write!(f, "empty"),
|
|
||||||
Type::Float => write!(f, "float"),
|
|
||||||
Type::Function {
|
|
||||||
parameter_types,
|
|
||||||
return_type,
|
|
||||||
} => {
|
|
||||||
write!(f, "(")?;
|
|
||||||
|
|
||||||
for parameter_type in parameter_types {
|
|
||||||
write!(f, "{parameter_type}")?;
|
|
||||||
|
|
||||||
if parameter_type != parameter_types.last().unwrap() {
|
|
||||||
write!(f, " ")?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
write!(f, ")")?;
|
|
||||||
write!(f, " -> {return_type}")
|
|
||||||
}
|
|
||||||
Type::Integer => write!(f, "int"),
|
|
||||||
Type::List(item_type) => write!(f, "[{item_type}]"),
|
|
||||||
Type::Map => write!(f, "map"),
|
|
||||||
Type::Number => write!(f, "num"),
|
|
||||||
Type::String => write!(f, "str"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -31,8 +31,8 @@ impl AbstractTree for Use {
|
|||||||
|
|
||||||
evaluate_with_context(&file_contents, &mut file_context)?;
|
evaluate_with_context(&file_contents, &mut file_context)?;
|
||||||
|
|
||||||
for (key, value) in file_context.variables()?.iter() {
|
for (key, (value, r#type)) in file_context.variables()?.iter() {
|
||||||
context.variables_mut()?.insert(key.clone(), value.clone());
|
context.set(key.clone(), value.clone(), Some(r#type.clone()))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Value::Map(file_context))
|
Ok(Value::Map(file_context))
|
||||||
|
@ -145,13 +145,10 @@ impl AbstractTree for ValueNode {
|
|||||||
let map = Map::new();
|
let map = Map::new();
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut variables = map.variables_mut()?;
|
|
||||||
|
|
||||||
for (key, statement) in key_statement_pairs {
|
for (key, statement) in key_statement_pairs {
|
||||||
let value = statement.run(source, context)?;
|
let value = statement.run(source, context)?;
|
||||||
let value_type = value.r#type();
|
|
||||||
|
|
||||||
variables.insert(key.clone(), (value, value_type));
|
map.set(key.clone(), value, None)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -252,15 +249,9 @@ mod tests {
|
|||||||
fn evaluate_map() {
|
fn evaluate_map() {
|
||||||
let map = Map::new();
|
let map = Map::new();
|
||||||
|
|
||||||
{
|
map.set("x".to_string(), Value::Integer(1), None).unwrap();
|
||||||
let mut variables = map.variables_mut().unwrap();
|
map.set("foo".to_string(), Value::String("bar".to_string()), None)
|
||||||
|
.unwrap();
|
||||||
variables.insert("x".to_string(), (Value::Integer(1), Type::Integer));
|
|
||||||
variables.insert(
|
|
||||||
"foo".to_string(),
|
|
||||||
(Value::String("bar".to_string()), Type::String),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
assert_eq!(evaluate("{ x = 1, foo = 'bar' }"), Ok(Value::Map(map)));
|
assert_eq!(evaluate("{ x = 1, foo = 'bar' }"), Ok(Value::Map(map)));
|
||||||
}
|
}
|
||||||
|
@ -24,24 +24,14 @@ impl BuiltInFunction for Read {
|
|||||||
let entry = entry?;
|
let entry = entry?;
|
||||||
let file_data = Map::new();
|
let file_data = Map::new();
|
||||||
|
|
||||||
{
|
|
||||||
let mut file_data_variables = file_data.variables_mut()?;
|
|
||||||
let name = entry.file_name().to_string_lossy().to_string();
|
let name = entry.file_name().to_string_lossy().to_string();
|
||||||
let metadata = entry.metadata()?;
|
let metadata = entry.metadata()?;
|
||||||
let created = metadata.created()?.elapsed()?.as_secs() as i64;
|
let created = metadata.created()?.elapsed()?.as_secs() as i64;
|
||||||
let modified = metadata.modified()?.elapsed()?.as_secs() as i64;
|
let modified = metadata.modified()?.elapsed()?.as_secs() as i64;
|
||||||
|
|
||||||
file_data_variables
|
file_data.set("name".to_string(), Value::String(name), None)?;
|
||||||
.insert("name".to_string(), (Value::String(name), Type::String));
|
file_data.set("created".to_string(), Value::Integer(created), None)?;
|
||||||
file_data_variables.insert(
|
file_data.set("modified".to_string(), Value::Integer(modified), None)?;
|
||||||
"created".to_string(),
|
|
||||||
(Value::Integer(created), Type::Integer),
|
|
||||||
);
|
|
||||||
file_data_variables.insert(
|
|
||||||
"modified".to_string(),
|
|
||||||
(Value::Integer(modified), Type::Integer),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
files.items_mut().push(Value::Map(file_data));
|
files.items_mut().push(Value::Map(file_data));
|
||||||
}
|
}
|
||||||
|
@ -31,13 +31,9 @@ pub fn evaluate(source: &str) -> Result<Value> {
|
|||||||
/// # use dust_lang::*;
|
/// # use dust_lang::*;
|
||||||
/// let mut context = Map::new();
|
/// let mut context = Map::new();
|
||||||
///
|
///
|
||||||
/// {
|
/// context.set("one".into(), 1.into(), None);
|
||||||
/// let mut variables = context.variables_mut().unwrap();
|
/// context.set("two".into(), 2.into(), None);
|
||||||
///
|
/// context.set("three".into(), 3.into(), None);
|
||||||
/// variables.insert("one".into(), (1.into(), Type::Integer));
|
|
||||||
/// variables.insert("two".into(), (2.into(), Type::Integer));
|
|
||||||
/// variables.insert("three".into(), (3.into(), Type::Integer));
|
|
||||||
/// }
|
|
||||||
///
|
///
|
||||||
/// let dust_code = "four = 4 one + two + three + four";
|
/// let dust_code = "four = 4 one + two + three + four";
|
||||||
///
|
///
|
||||||
|
14
src/main.rs
14
src/main.rs
@ -12,7 +12,7 @@ use tree_sitter::Parser as TSParser;
|
|||||||
|
|
||||||
use std::{borrow::Cow, fs::read_to_string};
|
use std::{borrow::Cow, fs::read_to_string};
|
||||||
|
|
||||||
use dust_lang::{evaluate_with_context, language, Interpreter, Map, Type, Value};
|
use dust_lang::{evaluate_with_context, language, Interpreter, Map, Value};
|
||||||
|
|
||||||
/// Command-line arguments to be parsed.
|
/// Command-line arguments to be parsed.
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
@ -61,18 +61,16 @@ fn main() {
|
|||||||
|
|
||||||
if let Some(input) = args.input {
|
if let Some(input) = args.input {
|
||||||
context
|
context
|
||||||
.variables_mut()
|
.set("input".to_string(), Value::String(input), None)
|
||||||
.unwrap()
|
.unwrap();
|
||||||
.insert("input".to_string(), (Value::String(input), Type::String));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(path) = args.input_path {
|
if let Some(path) = args.input_path {
|
||||||
let file_contents = read_to_string(path).unwrap();
|
let file_contents = read_to_string(path).unwrap();
|
||||||
|
|
||||||
context.variables_mut().unwrap().insert(
|
context
|
||||||
"input".to_string(),
|
.set("input".to_string(), Value::String(file_contents), None)
|
||||||
(Value::String(file_contents), Type::String),
|
.unwrap();
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut parser = TSParser::new();
|
let mut parser = TSParser::new();
|
||||||
|
@ -82,9 +82,7 @@ impl Function {
|
|||||||
|
|
||||||
let key = identifier.inner().clone();
|
let key = identifier.inner().clone();
|
||||||
|
|
||||||
function_context
|
function_context.set(key, value, Some(value_type))?;
|
||||||
.variables_mut()?
|
|
||||||
.insert(key, (value, value_type));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let return_value = self.body.run(source, &function_context)?;
|
let return_value = self.body.run(source, &function_context)?;
|
||||||
|
@ -3,7 +3,7 @@ use std::{
|
|||||||
cmp::Ordering,
|
cmp::Ordering,
|
||||||
collections::BTreeMap,
|
collections::BTreeMap,
|
||||||
fmt::{self, Display, Formatter},
|
fmt::{self, Display, Formatter},
|
||||||
sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard},
|
sync::{Arc, RwLock, RwLockReadGuard},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{value::Value, Result, Type};
|
use crate::{value::Value, Result, Type};
|
||||||
@ -59,10 +59,6 @@ impl Map {
|
|||||||
|
|
||||||
Ok(previous)
|
Ok(previous)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn variables_mut(&self) -> Result<RwLockWriteGuard<BTreeMap<String, (Value, Type)>>> {
|
|
||||||
Ok(self.variables.write()?)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Map {
|
impl Default for Map {
|
||||||
|
@ -781,11 +781,8 @@ impl<'de> Visitor<'de> for ValueVisitor {
|
|||||||
let map = Map::new();
|
let map = Map::new();
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut variables = map.variables_mut().unwrap();
|
|
||||||
|
|
||||||
while let Some((key, value)) = access.next_entry::<String, Value>()? {
|
while let Some((key, value)) = access.next_entry::<String, Value>()? {
|
||||||
let r#type = value.r#type();
|
map.set(key, value, None).unwrap();
|
||||||
variables.insert(key, (value, r#type));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user